Print this page
    
7127  remove -Wno-missing-braces from Makefile.uts
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/llc1.c
          +++ new/usr/src/uts/common/io/llc1.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
  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 2008 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  
  27   27  /*
  28   28   * llc1 - an LLC Class 1 MUX compatible with SunConnect LLC2 uses DLPI
  29   29   * interface.  Its primary use is to support RPL for network boot but can be
  30   30   * used by other protocols.
  31   31   */
  32   32  
  33   33  #include <sys/types.h>
  34   34  #include <sys/errno.h>
  35   35  #include <sys/param.h>
  36   36  #include <sys/mkdev.h>
  37   37  #include <sys/sysmacros.h>
  38   38  #include <sys/systm.h>
  39   39  #include <sys/stropts.h>
  40   40  #include <sys/stream.h>
  41   41  #include <sys/kmem.h>
  42   42  #include <sys/conf.h>
  43   43  #include <sys/ddi.h>
  44   44  #include <sys/devops.h>
  45   45  #include <sys/sunddi.h>
  46   46  #include <sys/ksynch.h>
  47   47  #include <sys/dlpi.h>
  48   48  #include <sys/ethernet.h>
  49   49  #include <sys/strsun.h>
  50   50  #include <sys/stat.h>
  51   51  #include <netinet/in.h> /* for byteorder macros on machines that define them */
  52   52  #include <sys/llc1.h>
  53   53  #include <sys/kstat.h>
  54   54  #include <sys/debug.h>
  55   55  
  56   56  /*
  57   57   * function prototypes, etc.
  58   58   */
  59   59  static int llc1_open(queue_t *q, dev_t *dev, int flag, int sflag,
  60   60          cred_t *cred);
  61   61  static int llc1_close(queue_t *q, int flag, cred_t *cred);
  62   62  static int llc1_uwput(queue_t *q, mblk_t *mp);
  63   63  static int llc1_uwsrv(queue_t *q);
  64   64  static int llc1_lrsrv(queue_t *q);
  65   65  static int llc1_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  66   66  static int llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
  67   67  static int llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
  68   68  
  69   69  static mblk_t *llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo,
  70   70          mblk_t *mp);
  71   71  static mblk_t *llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
  72   72  static mblk_t *llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
  73   73          mblk_t *mp);
  74   74  static mblk_t *llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
  75   75  static mblk_t *llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
  76   76          mblk_t *mp);
  77   77  
  78   78  static void llc1_ioctl(queue_t *q, mblk_t *mp);
  79   79  static void llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp);
  80   80  static void llc1_req_raw(llc_mac_info_t *macinfo);
  81   81  static void llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim);
  82   82  
  83   83  static minor_t llc1_findminor(llc1dev_t *device);
  84   84  static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *);
  85   85  
  86   86  static void llc1insque(void *elem, void *pred);
  87   87  static void llc1remque(void *arg);
  88   88  static void llc1error();
  89   89  static int llc1_subs_unbind(void);
  90   90  static void llc1_init_kstat(llc_mac_info_t *macinfo);
  91   91  static void llc1_uninit_kstat(llc_mac_info_t *macinfo);
  92   92  static int llc1_update_kstat(kstat_t *ksp, int rw);
  93   93  static int llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo);
  94   94  static int llc1_unbind(queue_t *q, mblk_t *mp);
  95   95  static int llc1_subs_bind(queue_t *q, mblk_t *mp);
  96   96  static int llc1_unitdata(queue_t *q, mblk_t *mp);
  97   97  static int llc1_inforeq(queue_t *q, mblk_t *mp);
  98   98  static int llc1attach(queue_t *q, mblk_t *mp);
  99   99  static void llc1_send_bindreq(llc_mac_info_t *macinfo);
 100  100  static int llc1_req_info(queue_t *q);
 101  101  static int llc1_cmds(queue_t *q, mblk_t *mp);
 102  102  static int llc1_setppa(struct ll_snioc *snioc);
 103  103  static int llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc);
 104  104  static int llc1_bind(queue_t *q, mblk_t *mp);
 105  105  static int llc1unattach(queue_t *q, mblk_t *mp);
 106  106  static int llc1_enable_multi(queue_t *q, mblk_t *mp);
 107  107  static int llc1_disable_multi(queue_t *q, mblk_t *mp);
 108  108  static int llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res);
 109  109  static int llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res);
 110  110  static int llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo);
 111  111  static int llc1_snap_match(llc1_t *lld, struct snaphdr *snap);
 112  112  
 113  113  /*
 114  114   * the standard streams glue for defining the type of streams entity and the
 115  115   * operational parameters.
 116  116   */
 117  117  
 118  118  static struct module_info llc1_minfo = {
 119  119          LLC1IDNUM,
 120  120          "llc1",
 121  121          0,
 122  122          LLC1_DEFMAX,
 123  123          LLC1_HIWATER,           /* high water mark */
 124  124          LLC1_LOWATER,           /* low water mark */
 125  125  };
 126  126  
 127  127  static struct qinit llc1_rint = {
 128  128          NULL,
 129  129          NULL,
 130  130          llc1_open,
 131  131          llc1_close,
 132  132          NULL,
 133  133          &llc1_minfo,
 134  134          NULL
 135  135  };
 136  136  
 137  137  static struct qinit llc1_wint = {
 138  138          llc1_uwput,
 139  139          llc1_uwsrv,
 140  140          NULL,
 141  141          NULL,
 142  142          NULL,
 143  143          &llc1_minfo,
 144  144          NULL
 145  145  };
 146  146  
 147  147  static struct qinit llc1_muxrint = {
 148  148          putq,
 149  149          llc1_lrsrv,
 150  150          NULL,
 151  151          NULL,
 152  152          NULL,
 153  153          &llc1_minfo,
 154  154          NULL
 155  155  };
 156  156  
 157  157  static struct qinit llc1_muxwint = {
 158  158          NULL,
 159  159          NULL,
 160  160          NULL,
 161  161          NULL,
 162  162          NULL,
 163  163          &llc1_minfo,
 164  164          NULL
 165  165  };
 166  166  
 167  167  struct streamtab llc1_info = {
 168  168          &llc1_rint,
 169  169          &llc1_wint,
 170  170          &llc1_muxrint,
 171  171          &llc1_muxwint
 172  172  };
 173  173  
 174  174  /*
 175  175   * loadable module/driver wrapper this allows llc1 to be unloaded later
 176  176   */
 177  177  
 178  178  #if !defined(BUILD_STATIC)
 179  179  #include <sys/modctl.h>
 180  180  
 181  181  /* define the "ops" structure for a STREAMS driver */
 182  182  DDI_DEFINE_STREAM_OPS(llc1_ops, nulldev, nulldev, llc1_attach,
 183  183      llc1_detach, nodev, llc1_getinfo, D_MP | D_MTPERMOD, &llc1_info,
 184  184      ddi_quiesce_not_supported);
 185  185  
  
    | 
      ↓ open down ↓ | 
    185 lines elided | 
    
      ↑ open up ↑ | 
  
 186  186  /*
 187  187   * Module linkage information for the kernel.
 188  188   */
 189  189  static struct modldrv modldrv = {
 190  190          &mod_driverops,         /* Type of module.  This one is a driver */
 191  191          "LLC Class 1 Driver",
 192  192          &llc1_ops,              /* driver ops */
 193  193  };
 194  194  
 195  195  static struct modlinkage modlinkage = {
 196      -        MODREV_1, (void *)&modldrv, NULL
      196 +        MODREV_1, { (void *)&modldrv, NULL }
 197  197  };
 198  198  
 199  199  int
 200  200  _init(void)
 201  201  {
 202  202          return (mod_install(&modlinkage));
 203  203  }
 204  204  
 205  205  int
 206  206  _fini(void)
 207  207  {
 208  208          return (mod_remove(&modlinkage));
 209  209  }
 210  210  
 211  211  int
 212  212  _info(struct modinfo *modinfop)
 213  213  {
 214  214          return (mod_info(&modlinkage, modinfop));
 215  215  }
 216  216  
 217  217  #endif
 218  218  
 219  219  #ifdef LLC1_DEBUG
 220  220  extern int llc1_debug = 0x0;
 221  221  
 222  222  #endif
 223  223  
 224  224  /*
 225  225   * Allocate and zero-out "number" structures each of type "structure" in
 226  226   * kernel memory.
 227  227   */
 228  228  #define GETSTRUCT(structure, number)   \
 229  229          (kmem_zalloc(sizeof (structure) * (number), KM_NOSLEEP))
 230  230  #define GETBUF(structure, size) \
 231  231          (kmem_zalloc(size, KM_NOSLEEP))
 232  232  
 233  233  static struct llc1device llc1_device_list;
 234  234  
 235  235  /*
 236  236   * llc1_attach - init time attach support When the hardware specific attach
 237  237   * is called, it must call this procedure with the device class structure
 238  238   */
 239  239  
 240  240  static int
 241  241  llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
 242  242  {
 243  243          if (cmd != DDI_ATTACH)
 244  244                  return (DDI_FAILURE);
 245  245  
 246  246          /*
 247  247           * there isn't any hardware but we do need to initialize things
 248  248           */
 249  249          if (!(llc1_device_list.llc1_status & LLC1_ATTACHED)) {
 250  250                  llc1_device_list.llc1_status |= LLC1_ATTACHED;
 251  251                  rw_init(&llc1_device_list.llc1_rwlock, NULL, RW_DRIVER, NULL);
 252  252  
 253  253                  /* make sure minor device lists are initialized */
 254  254                  llc1_device_list.llc1_str_next =
 255  255                      llc1_device_list.llc1_str_prev =
 256  256                      (llc1_t *)&llc1_device_list.llc1_str_next;
 257  257  
 258  258                  /* make sure device list is initialized */
 259  259                  llc1_device_list.llc1_mac_next =
 260  260                      llc1_device_list.llc1_mac_prev =
 261  261                      (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
 262  262          }
 263  263  
 264  264          /*
 265  265           * now do all the DDI stuff necessary
 266  266           */
 267  267  
 268  268          ddi_set_driver_private(devinfo, &llc1_device_list);
 269  269  
 270  270          /*
 271  271           * create the file system device node
 272  272           */
 273  273          if (ddi_create_minor_node(devinfo, "llc1", S_IFCHR,
 274  274              0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
 275  275                  llc1error(devinfo, "ddi_create_minor_node failed");
 276  276                  ddi_remove_minor_node(devinfo, NULL);
 277  277                  return (DDI_FAILURE);
 278  278          }
 279  279          llc1_device_list.llc1_multisize = ddi_getprop(DDI_DEV_T_NONE,
 280  280              devinfo, 0, "multisize", 0);
 281  281          if (llc1_device_list.llc1_multisize == 0)
 282  282                  llc1_device_list.llc1_multisize = LLC1_MAX_MULTICAST;
 283  283  
 284  284          ddi_report_dev(devinfo);
 285  285          return (DDI_SUCCESS);
 286  286  }
 287  287  
 288  288  /*
 289  289   * llc1_detach standard kernel interface routine
 290  290   */
 291  291  
 292  292  static int
 293  293  llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
 294  294  {
 295  295          if (cmd != DDI_DETACH) {
 296  296                  return (DDI_FAILURE);
 297  297          }
 298  298          if (llc1_device_list.llc1_ndevice > 0)
 299  299                  return (DDI_FAILURE);
 300  300          /* remove all mutex and locks */
 301  301          rw_destroy(&llc1_device_list.llc1_rwlock);
 302  302          llc1_device_list.llc1_status = 0;       /* no longer attached */
 303  303          ddi_remove_minor_node(dev, NULL);
 304  304          return (DDI_SUCCESS);
 305  305  }
 306  306  
 307  307  /*
 308  308   * llc1_devinfo(dev, cmd, arg, result) standard kernel devinfo lookup
 309  309   * function
 310  310   */
 311  311  /*ARGSUSED2*/
 312  312  static int
 313  313  llc1_getinfo(dev_info_t *dev, ddi_info_cmd_t cmd, void *arg, void **result)
 314  314  {
 315  315          int error;
 316  316  
 317  317          switch (cmd) {
 318  318          case DDI_INFO_DEVT2DEVINFO:
 319  319                  if (dev == NULL) {
 320  320                          error = DDI_FAILURE;
 321  321                  } else {
 322  322                          *result = (void *)dev;
 323  323                          error = DDI_SUCCESS;
 324  324                  }
 325  325                  break;
 326  326          case DDI_INFO_DEVT2INSTANCE:
 327  327                  *result = (void *)0;
 328  328                  error = DDI_SUCCESS;
 329  329                  break;
 330  330          default:
 331  331                  error = DDI_FAILURE;
 332  332          }
 333  333          return (error);
 334  334  }
 335  335  
 336  336  /*
 337  337   * llc1_open()
 338  338   * LLC1 open routine, called when device is opened by the user
 339  339   */
 340  340  
 341  341  /*ARGSUSED2*/
 342  342  static int
 343  343  llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
 344  344  {
 345  345          llc1_t *llc1;
 346  346          minor_t minordev;
 347  347          int     status = 0;
 348  348  
 349  349          ASSERT(q);
 350  350  
 351  351          /*
 352  352           * Stream already open, sucess.
 353  353           */
 354  354          if (q->q_ptr)
 355  355                  return (0);
 356  356          /*
 357  357           * Serialize access through open/close this will serialize across all
 358  358           * llc1 devices, but open and close are not frequent so should not
 359  359           * induce much, if any delay.
 360  360           */
 361  361          rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
 362  362  
 363  363          if (sflag == CLONEOPEN) {
 364  364                  /* need to find a minor dev */
 365  365                  minordev = llc1_findminor(&llc1_device_list);
 366  366                  if (minordev == 0) {
 367  367                          rw_exit(&llc1_device_list.llc1_rwlock);
 368  368                          return (ENXIO);
 369  369                  }
 370  370                  *dev = makedevice(getmajor(*dev), minordev);
 371  371          } else {
 372  372                  minordev = getminor (*dev);
 373  373                  if ((minordev > MAXMIN32) || (minordev == 0)) {
 374  374                          rw_exit(&llc1_device_list.llc1_rwlock);
 375  375                          return (ENXIO);
 376  376                  }
 377  377          }
 378  378  
 379  379          /*
 380  380           * get a per-stream structure and link things together so we
 381  381           * can easily find them later.
 382  382           */
 383  383  
 384  384          llc1 = kmem_zalloc(sizeof (llc1_t), KM_SLEEP);
 385  385          llc1->llc_qptr = q;
 386  386          WR(q)->q_ptr = q->q_ptr = (caddr_t)llc1;
 387  387          /*
 388  388           * fill in the structure and state info
 389  389           */
 390  390          llc1->llc_state = DL_UNATTACHED;
 391  391          llc1->llc_style = DL_STYLE2;
 392  392          llc1->llc_minor = minordev;
 393  393  
 394  394          mutex_init(&llc1->llc_lock, NULL, MUTEX_DRIVER, NULL);
 395  395          llc1insque(llc1, llc1_device_list.llc1_str_prev);
 396  396          rw_exit(&llc1_device_list.llc1_rwlock);
 397  397          qprocson(q);            /* start the queues running */
 398  398          return (status);
 399  399  }
 400  400  
 401  401  /*
 402  402   * llc1_close(q)
 403  403   * normal stream close call checks current status and cleans up
 404  404   * data structures that were dynamically allocated
 405  405   */
 406  406  /*ARGSUSED1*/
 407  407  static int
 408  408  llc1_close(queue_t *q, int flag, cred_t *cred)
 409  409  {
 410  410          llc1_t *llc1;
 411  411  
 412  412          ASSERT(q);
 413  413          ASSERT(q->q_ptr);
 414  414  
 415  415          qprocsoff(q);
 416  416          llc1 = (llc1_t *)q->q_ptr;
 417  417          rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
 418  418          /* completely disassociate the stream from the device */
 419  419          q->q_ptr = WR(q)->q_ptr = NULL;
 420  420  
 421  421          (void) llc1remque(llc1); /* remove from active list */
 422  422          rw_exit(&llc1_device_list.llc1_rwlock);
 423  423  
 424  424          mutex_enter(&llc1->llc_lock);
 425  425          if (llc1->llc_state == DL_IDLE || llc1->llc_state == DL_UNBOUND) {
 426  426                  llc1->llc_state = DL_UNBOUND;   /* force the issue */
 427  427          }
 428  428  
 429  429          if (llc1->llc_mcast != NULL) {
 430  430                  int     i;
 431  431  
 432  432                  for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
 433  433                          llc_mcast_t *mcast;
 434  434  
 435  435                          if ((mcast = llc1->llc_mcast[i]) != NULL) {
 436  436                                  /*
 437  437                                   * disable from stream and possibly
 438  438                                   * lower stream
 439  439                                   */
 440  440                                  if (llc1->llc_mac_info &&
 441  441                                      llc1->llc_mac_info->llcp_flags &
 442  442                                      LLC1_AVAILABLE)
 443  443                                          llc1_send_disable_multi(
 444  444                                              llc1->llc_mac_info,
 445  445                                              mcast);
 446  446                                  llc1->llc_mcast[i] = NULL;
 447  447                          }
 448  448                  }
 449  449                  kmem_free(llc1->llc_mcast,
 450  450                      sizeof (llc_mcast_t *) * llc1->llc_multicnt);
 451  451                  llc1->llc_mcast = NULL;
 452  452          }
 453  453          llc1->llc_state = DL_UNATTACHED;
 454  454  
 455  455          mutex_exit(&llc1->llc_lock);
 456  456  
 457  457          mutex_destroy(&llc1->llc_lock);
 458  458  
 459  459          kmem_free(llc1, sizeof (llc1_t));
 460  460  
 461  461          return (0);
 462  462  }
 463  463  
 464  464  /*
 465  465   * llc1_uwput()
 466  466   * general llc stream write put routine. Receives ioctl's from
 467  467   * user level and data from upper modules and processes them immediately.
 468  468   * M_PROTO/M_PCPROTO are queued for later processing by the service
 469  469   * procedure.
 470  470   */
 471  471  
 472  472  static int
 473  473  llc1_uwput(queue_t *q, mblk_t *mp)
 474  474  {
 475  475          llc1_t *ld = (llc1_t *)(q->q_ptr);
 476  476  
 477  477  #ifdef LLC1_DEBUG
 478  478          if (llc1_debug & LLCTRACE)
 479  479                  printf("llc1_wput(%x %x): type %d\n", q, mp, DB_TYPE(mp));
 480  480  #endif
 481  481          switch (DB_TYPE(mp)) {
 482  482  
 483  483          case M_IOCTL:           /* no waiting in ioctl's */
 484  484                  (void) llc1_ioctl(q, mp);
 485  485                  break;
 486  486  
 487  487          case M_FLUSH:           /* canonical flush handling */
 488  488                  if (*mp->b_rptr & FLUSHW)
 489  489                          flushq(q, 0);
 490  490  
 491  491                  if (*mp->b_rptr & FLUSHR) {
 492  492                          flushq(RD(q), 0);
 493  493                          *mp->b_rptr &= ~FLUSHW;
 494  494                          qreply(q, mp);
 495  495                  } else
 496  496                          freemsg(mp);
 497  497                  break;
 498  498  
 499  499                  /* for now, we will always queue */
 500  500          case M_PROTO:
 501  501          case M_PCPROTO:
 502  502                  (void) putq(q, mp);
 503  503                  break;
 504  504  
 505  505          case M_DATA:
 506  506                  /* fast data / raw support */
 507  507                  if ((ld->llc_flags & (LLC_RAW | LLC_FAST)) == 0 ||
 508  508                      ld->llc_state != DL_IDLE) {
 509  509                          (void) merror(q, mp, EPROTO);
 510  510                          break;
 511  511                  }
 512  512                  /* need to do further checking */
 513  513                  (void) putq(q, mp);
 514  514                  break;
 515  515  
 516  516          default:
 517  517  #ifdef LLC1_DEBUG
 518  518                  if (llc1_debug & LLCERRS)
 519  519                          printf("llc1: Unexpected packet type from queue: %d\n",
 520  520                              mp->b_datap->db_type);
 521  521  #endif
 522  522                  freemsg(mp);
 523  523          }
 524  524          return (0);
 525  525  }
 526  526  
 527  527  /*
 528  528   * llc1_lrsrv()
 529  529   * called when data is put into the service queue from below.
 530  530   * Determines additional processing that might be needed and sends the data
 531  531   * upstream in the form of a Data Indication packet.
 532  532   */
 533  533  static int
 534  534  llc1_lrsrv(queue_t *q)
 535  535  {
 536  536          mblk_t *mp;
 537  537          union DL_primitives *prim;
 538  538          llc_mac_info_t *macinfo = (llc_mac_info_t *)q->q_ptr;
 539  539          struct iocblk *iocp;
 540  540  
 541  541  #ifdef LLC1_DEBUG
 542  542          if (llc1_debug & LLCTRACE)
 543  543                  printf("llc1_rsrv(%x)\n", q);
 544  544          if (llc1_debug & LLCRECV) {
 545  545                  printf("llc1_lrsrv: q=%x macinfo=%x", q, macinfo);
 546  546                  if (macinfo == NULL) {
 547  547                          printf("NULL macinfo");
 548  548                          panic("null macinfo in lrsrv");
 549  549                          /*NOTREACHED*/
 550  550                  }
 551  551                  printf("\n");
 552  552          }
 553  553  #endif
 554  554  
 555  555          /*
 556  556           * determine where message goes, then call the proper handler
 557  557           */
 558  558  
 559  559          while ((mp = getq(q)) != NULL) {
 560  560                  switch (DB_TYPE(mp)) {
 561  561                  case M_PROTO:
 562  562                  case M_PCPROTO:
 563  563                          prim = (union DL_primitives *)mp->b_rptr;
 564  564                          /* only some primitives ever get passed through */
 565  565                          switch (prim->dl_primitive) {
 566  566                          case DL_INFO_ACK:
 567  567                                  if (macinfo->llcp_flags & LLC1_LINKED) {
 568  568                                          /*
 569  569                                           * we are in the midst of completing
 570  570                                           * the I_LINK/I_PLINK and needed this
 571  571                                           * info
 572  572                                           */
 573  573                                          macinfo->llcp_flags &= ~LLC1_LINKED;
 574  574                                          macinfo->llcp_flags |= LLC1_AVAILABLE;
 575  575                                          macinfo->llcp_maxpkt =
 576  576                                              prim->info_ack.dl_max_sdu;
 577  577                                          macinfo->llcp_minpkt =
 578  578                                              prim->info_ack.dl_min_sdu;
 579  579                                          macinfo->llcp_type =
 580  580                                              prim->info_ack.dl_mac_type;
 581  581                                          if (macinfo->llcp_type == DL_ETHER) {
 582  582                                                  macinfo->llcp_type = DL_CSMACD;
 583  583                                                  /*
 584  584                                                   * size of max header
 585  585                                                   * (including SNAP)
 586  586                                                   */
 587  587                                                  macinfo->llcp_maxpkt -= 8;
 588  588                                          }
 589  589                                          macinfo->llcp_addrlen =
 590  590                                              prim->info_ack.dl_addr_length -
 591  591                                              ABS(prim->info_ack.dl_sap_length);
 592  592  
 593  593                                          bcopy(mp->b_rptr +
 594  594                                              prim->info_ack.dl_addr_offset,
 595  595                                              macinfo->llcp_macaddr,
 596  596                                              macinfo->llcp_addrlen);
 597  597                                          bcopy(mp->b_rptr +
 598  598                                              prim->info_ack.
 599  599                                              dl_brdcst_addr_offset,
 600  600                                              macinfo->llcp_broadcast,
 601  601                                              prim->info_ack.
 602  602                                              dl_brdcst_addr_length);
 603  603  
 604  604                                          if (prim->info_ack.dl_current_state ==
 605  605                                              DL_UNBOUND)
 606  606                                                  llc1_send_bindreq(macinfo);
 607  607                                          freemsg(mp);
 608  608                                          /*
 609  609                                           * need to put the lower stream into
 610  610                                           * DLRAW mode.  Currently only DL_ETHER
 611  611                                           * or DL_CSMACD
 612  612                                           */
 613  613                                          switch (macinfo->llcp_type) {
 614  614                                          case DL_ETHER:
 615  615                                          case DL_CSMACD:
 616  616                                                  /*
 617  617                                                   * raw mode is optimal so ask
 618  618                                                   * for it * we might not get
 619  619                                                   * it but that's OK
 620  620                                                   */
 621  621                                                  llc1_req_raw(macinfo);
 622  622                                                  break;
 623  623                                          default:
 624  624                                                  /*
 625  625                                                   * don't want raw mode so don't
 626  626                                                   * ask for it
 627  627                                                   */
 628  628                                                  break;
 629  629                                          }
 630  630                                  } else {
 631  631                                          if (prim->info_ack.dl_current_state ==
 632  632                                              DL_IDLE)
 633  633                                          /* address was wrong before */
 634  634                                          bcopy(mp->b_rptr +
 635  635                                              prim->info_ack.dl_addr_offset,
 636  636                                              macinfo->llcp_macaddr,
 637  637                                              macinfo->llcp_addrlen);
 638  638                                          freemsg(mp);
 639  639                                  }
 640  640                                  break;
 641  641                          case DL_BIND_ACK:
 642  642                                  /*
 643  643                                   * if we had to bind, the macaddr is wrong
 644  644                                   * so get it again
 645  645                                   */
 646  646                                  freemsg(mp);
 647  647                                  (void) llc1_req_info(q);
 648  648                                  break;
 649  649                          case DL_UNITDATA_IND:
 650  650                                  /* when not using raw mode we get these */
 651  651                                  (void) llc1_recv(macinfo, mp);
 652  652                                  break;
 653  653                          case DL_ERROR_ACK:
 654  654                                  /* binding is a special case */
 655  655                                  if (prim->error_ack.dl_error_primitive ==
 656  656                                      DL_BIND_REQ) {
 657  657                                          freemsg(mp);
 658  658                                          if (macinfo->llcp_flags & LLC1_BINDING)
 659  659                                                  llc1_send_bindreq(macinfo);
 660  660                                  } else
 661  661                                          llc1_find_waiting(macinfo, mp,
 662  662                                              prim->error_ack.dl_error_primitive);
 663  663                                  break;
 664  664                          case DL_PHYS_ADDR_ACK:
 665  665                                  llc1_find_waiting(macinfo, mp,
 666  666                                      DL_PHYS_ADDR_REQ);
 667  667                                  break;
 668  668                          case DL_OK_ACK:
 669  669                                  if (prim->ok_ack.dl_correct_primitive ==
 670  670                                      DL_BIND_REQ)
 671  671                                          macinfo->llcp_flags &= ~LLC1_BINDING;
 672  672                                  /* FALLTHROUGH */
 673  673                          default:
 674  674                                  freemsg(mp);
 675  675                          }
 676  676                          break;
 677  677  
 678  678                  case M_IOCACK:
 679  679                          /* probably our DLIOCRAW completing */
 680  680                          iocp = (struct iocblk *)mp->b_rptr;
 681  681                          if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
 682  682                              macinfo->llcp_iocid == iocp->ioc_id) {
 683  683                                  macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
 684  684                                  /* we can use this form */
 685  685                                  macinfo->llcp_flags |= LLC1_USING_RAW;
 686  686                                  freemsg(mp);
 687  687                                  break;
 688  688                          }
 689  689                          /* need to find the correct queue */
 690  690                          freemsg(mp);
 691  691                          break;
 692  692                  case M_IOCNAK:
 693  693                          iocp = (struct iocblk *)mp->b_rptr;
 694  694                          if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
 695  695                              macinfo->llcp_iocid == iocp->ioc_id) {
 696  696                                  macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
 697  697                                  freemsg(mp);
 698  698                                  break;
 699  699                          }
 700  700                          /* need to find the correct queue */
 701  701                          freemsg(mp);
 702  702                          break;
 703  703                  case M_DATA:
 704  704                          llc1_recv(macinfo, mp);
 705  705                          break;
 706  706                  }
 707  707          }
 708  708          return (0);
 709  709  }
 710  710  
 711  711  /*
 712  712   * llc1_uwsrv - Incoming messages are processed according to the DLPI
 713  713   * protocol specification
 714  714   */
 715  715  
 716  716  static int
 717  717  llc1_uwsrv(queue_t *q)
 718  718  {
 719  719          mblk_t *mp;
 720  720          llc1_t *lld = (llc1_t *)q->q_ptr;
 721  721          union DL_primitives *prim;
 722  722          int     err;
 723  723  
 724  724  #ifdef LLC1_DEBUG
 725  725          if (llc1_debug & LLCTRACE)
 726  726                  printf("llc1_wsrv(%x)\n", q);
 727  727  #endif
 728  728  
 729  729  
 730  730          while ((mp = getq(q)) != NULL) {
 731  731                  switch (mp->b_datap->db_type) {
 732  732                  case M_PROTO:   /* Will be an DLPI message of some type */
 733  733                  case M_PCPROTO:
 734  734                          if ((err = llc1_cmds(q, mp)) != LLCE_OK) {
 735  735                                  prim = (union DL_primitives *)mp->b_rptr;
 736  736                                  if (err == LLCE_NOBUFFER || err == DL_SYSERR) {
 737  737                                          /* quit while we're ahead */
 738  738                                          lld->llc_stats->llcs_nobuffer++;
 739  739  #ifdef LLC1_DEBUG
 740  740                                          if (llc1_debug & LLCERRS)
 741  741                                                  printf(
 742  742  "llc1_cmds: nonfatal err=%d\n",
 743  743                                                      err);
 744  744  #endif
 745  745                                          (void) putbq(q, mp);
 746  746                                          return (0);
 747  747  
 748  748                                  } else {
 749  749                                          dlerrorack(q, mp,
 750  750                                              prim->dl_primitive,
 751  751                                              err, 0);
 752  752                                  }
 753  753                          }
 754  754                          break;
 755  755                  case M_DATA:
 756  756                          /*
 757  757                           * retry of a previously processed
 758  758                           * UNITDATA_REQ or is a RAW message from
 759  759                           * above
 760  760                           */
 761  761  
 762  762                          mutex_enter(&lld->llc_lock);
 763  763                          putnext(lld->llc_mac_info->llcp_queue, mp);
 764  764                          mutex_exit(&lld->llc_lock);
 765  765                          freemsg(mp);    /* free on success */
 766  766                          break;
 767  767  
 768  768                          /* This should never happen */
 769  769                  default:
 770  770  #ifdef LLC1_DEBUG
 771  771                          if (llc1_debug & LLCERRS)
 772  772                                  printf("llc1_wsrv: type(%x) not supported\n",
 773  773                                      mp->b_datap->db_type);
 774  774  #endif
 775  775                          freemsg(mp);    /* unknown types are discarded */
 776  776                          break;
 777  777                  }
 778  778          }
 779  779          return (0);
 780  780  }
 781  781  
 782  782  /*
 783  783   * llc1_multicast used to determine if the address is a multicast address for
 784  784   * this user.
 785  785   */
 786  786  int
 787  787  llc1_multicast(struct ether_addr *addr, llc1_t *lld)
 788  788  {
 789  789          int i;
 790  790  
 791  791          if (lld->llc_mcast)
 792  792                  for (i = 0; i < lld->llc_multicnt; i++)
 793  793                          if (lld->llc_mcast[i] &&
 794  794                              lld->llc_mcast[i]->llcm_refcnt &&
 795  795                              bcmp(lld->llc_mcast[i]->llcm_addr,
 796  796                              addr->ether_addr_octet, ETHERADDRL) == 0)
 797  797                                  return (1);
 798  798          return (0);
 799  799  }
 800  800  
 801  801  /*
 802  802   * llc1_ioctl handles all ioctl requests passed downstream. This routine is
 803  803   * passed a pointer to the message block with the ioctl request in it, and a
 804  804   * pointer to the queue so it can respond to the ioctl request with an ack.
 805  805   */
 806  806  
 807  807  int     llc1_doreqinfo;
 808  808  
 809  809  static void
 810  810  llc1_ioctl(queue_t *q, mblk_t *mp)
 811  811  {
 812  812          struct iocblk *iocp;
 813  813          llc1_t *lld;
 814  814          struct linkblk *link;
 815  815          llc_mac_info_t *macinfo;
 816  816          mblk_t *tmp;
 817  817          int error;
 818  818  
 819  819  #ifdef LLC1_DEBUG
 820  820          if (llc1_debug & LLCTRACE)
 821  821                  printf("llc1_ioctl(%x %x)\n", q, mp);
 822  822  #endif
 823  823          lld = (llc1_t *)q->q_ptr;
 824  824          iocp = (struct iocblk *)mp->b_rptr;
 825  825          switch (iocp->ioc_cmd) {
 826  826                  /* XXX need to lock the data structures */
 827  827          case I_PLINK:
 828  828          case I_LINK:
 829  829                  link = (struct linkblk *)mp->b_cont->b_rptr;
 830  830                  tmp = allocb(sizeof (llc_mac_info_t), BPRI_MED);
 831  831                  if (tmp == NULL) {
 832  832                          (void) miocnak(q, mp, 0, ENOSR);
 833  833                          return;
 834  834                  }
 835  835                  bzero(tmp->b_rptr, sizeof (llc_mac_info_t));
 836  836                  macinfo = (llc_mac_info_t *)tmp->b_rptr;
 837  837                  macinfo->llcp_mb = tmp;
 838  838                  macinfo->llcp_next = macinfo->llcp_prev = macinfo;
 839  839                  macinfo->llcp_queue = link->l_qbot;
 840  840                  macinfo->llcp_lindex = link->l_index;
 841  841                  /* tentative */
 842  842                  macinfo->llcp_ppa = --llc1_device_list.llc1_nextppa;
 843  843                  llc1_device_list.llc1_ndevice++;
 844  844                  macinfo->llcp_flags |= LLC1_LINKED | LLC1_DEF_PPA;
 845  845                  macinfo->llcp_lqtop = q;
 846  846                  macinfo->llcp_data = NULL;
 847  847  
 848  848                  /* need to do an info_req before an info_req or attach */
 849  849  
 850  850                  rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
 851  851                  llc1insque(macinfo, llc1_device_list.llc1_mac_prev);
 852  852                  macinfo->llcp_queue->q_ptr = RD(macinfo->llcp_queue)->q_ptr =
 853  853                      (caddr_t)macinfo;
 854  854                  llc1_init_kstat(macinfo);
 855  855                  rw_exit(&llc1_device_list.llc1_rwlock);
 856  856  
 857  857                  /* initiate getting the info */
 858  858                  (void) llc1_req_info(macinfo->llcp_queue);
 859  859  
 860  860                  miocack(q, mp, 0, 0);
 861  861                  return;
 862  862  
 863  863          case I_PUNLINK:
 864  864          case I_UNLINK:
 865  865                  link = (struct linkblk *)mp->b_cont->b_rptr;
 866  866                  rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
 867  867                  for (macinfo = llc1_device_list.llc1_mac_next;
 868  868                      macinfo != NULL &&
 869  869                      macinfo !=
 870  870                      (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
 871  871                      macinfo = macinfo->llcp_next) {
 872  872                          if (macinfo->llcp_lindex == link->l_index &&
 873  873                              macinfo->llcp_queue == link->l_qbot) {
 874  874                                  /* found it */
 875  875  
 876  876                                  ASSERT(macinfo->llcp_next);
 877  877  
 878  878                              /* remove from device list */
 879  879                                  llc1_device_list.llc1_ndevice--;
 880  880                                  llc1remque(macinfo);
 881  881  
 882  882                              /* remove any mcast structs */
 883  883                                  if (macinfo->llcp_mcast != NULL) {
 884  884                                  kmem_free(macinfo->llcp_mcast,
 885  885                                      sizeof (llc_mcast_t) *
 886  886                                      llc1_device_list.llc1_multisize);
 887  887                                  macinfo->llcp_mcast = NULL;
 888  888                                  }
 889  889  
 890  890                              /* remove any kstat counters */
 891  891                                  if (macinfo->llcp_kstatp != NULL)
 892  892                                  llc1_uninit_kstat(macinfo);
 893  893                                  if (macinfo->llcp_mb != NULL)
 894  894                                  freeb(macinfo->llcp_mb);
 895  895  
 896  896                                  lld->llc_mac_info = NULL;
 897  897  
 898  898                                  miocack(q, mp, 0, 0);
 899  899  
 900  900                              /* finish any necessary setup */
 901  901                                  if (llc1_device_list.llc1_ndevice == 0)
 902  902                                  llc1_device_list.llc1_nextppa = 0;
 903  903  
 904  904                                  rw_exit(&llc1_device_list.llc1_rwlock);
 905  905                                  return;
 906  906                          }
 907  907                  }
 908  908                  rw_exit(&llc1_device_list.llc1_rwlock);
 909  909                  /*
 910  910                   * what should really be done here -- force errors on all
 911  911                   * streams?
 912  912                   */
 913  913                  miocnak(q, mp, 0, EINVAL);
 914  914                  return;
 915  915  
 916  916          case L_SETPPA:
 917  917                  error = miocpullup(mp, sizeof (struct ll_snioc));
 918  918                  if (error != 0) {
 919  919                          miocnak(q, mp, 0, error);
 920  920                          return;
 921  921                  }
 922  922  
 923  923                  if (llc1_setppa((struct ll_snioc *)mp->b_cont->b_rptr) >= 0) {
 924  924                          miocack(q, mp, 0, 0);
 925  925                          return;
 926  926                  }
 927  927                  miocnak(q, mp, 0, EINVAL);
 928  928                  return;
 929  929  
 930  930          case L_GETPPA:
 931  931                  if (mp->b_cont == NULL) {
 932  932                          mp->b_cont = allocb(sizeof (struct ll_snioc), BPRI_MED);
 933  933                          if (mp->b_cont == NULL) {
 934  934                                  miocnak(q, mp, 0, ENOSR);
 935  935                                  return;
 936  936                          }
 937  937                          mp->b_cont->b_wptr =
 938  938                              mp->b_cont->b_rptr + sizeof (struct ll_snioc);
 939  939                  } else {
 940  940                          error = miocpullup(mp, sizeof (struct ll_snioc));
 941  941                          if (error != 0) {
 942  942                                  miocnak(q, mp, 0, error);
 943  943                                  return;
 944  944                          }
 945  945                  }
 946  946  
 947  947                  lld = (llc1_t *)q->q_ptr;
 948  948                  if (llc1_getppa(lld->llc_mac_info,
 949  949                      (struct ll_snioc *)mp->b_cont->b_rptr) >= 0)
 950  950                          miocack(q, mp, 0, 0);
 951  951                  else
 952  952                          miocnak(q, mp, 0, EINVAL);
 953  953                  return;
 954  954          default:
 955  955                  miocnak(q, mp, 0, EINVAL);
 956  956          }
 957  957  }
 958  958  
 959  959  /*
 960  960   * llc1_setppa(snioc) this function sets the real PPA number for a previously
 961  961   * I_LINKED stream. Be careful to select the macinfo struct associated
 962  962   * with our llc struct, to avoid erroneous references.
 963  963   */
 964  964  
 965  965  static int
 966  966  llc1_setppa(struct ll_snioc *snioc)
 967  967  {
 968  968          llc_mac_info_t *macinfo;
 969  969  
 970  970          for (macinfo = llc1_device_list.llc1_mac_next;
 971  971              macinfo != (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
 972  972              macinfo = macinfo->llcp_next)
 973  973                  if (macinfo->llcp_lindex == snioc->lli_index &&
 974  974                      (macinfo->llcp_flags & LLC1_DEF_PPA)) {
 975  975                          macinfo->llcp_flags &= ~LLC1_DEF_PPA;
 976  976                          macinfo->llcp_ppa = snioc->lli_ppa;
 977  977                          return (0);
 978  978                  }
 979  979          return (-1);
 980  980  }
 981  981  
 982  982  /*
 983  983   * llc1_getppa(macinfo, snioc) returns the PPA for this stream
 984  984   */
 985  985  static int
 986  986  llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc)
 987  987  {
 988  988          if (macinfo == NULL)
 989  989                  return (-1);
 990  990          snioc->lli_ppa = macinfo->llcp_ppa;
 991  991          snioc->lli_index = macinfo->llcp_lindex;
 992  992          return (0);
 993  993  }
 994  994  
 995  995  /*
 996  996   * llc1_cmds - process the DL commands as defined in dlpi.h
 997  997   */
 998  998  static int
 999  999  llc1_cmds(queue_t *q, mblk_t *mp)
1000 1000  {
1001 1001          union DL_primitives *dlp;
1002 1002          llc1_t *llc = (llc1_t *)q->q_ptr;
1003 1003          int     result = 0;
1004 1004          llc_mac_info_t *macinfo = llc->llc_mac_info;
1005 1005  
1006 1006          dlp = (union DL_primitives *)mp->b_rptr;
1007 1007  #ifdef LLC1_DEBUG
1008 1008          if (llc1_debug & LLCTRACE)
1009 1009                  printf("llc1_cmds(%x, %x):dlp=%x, dlp->dl_primitive=%d\n",
1010 1010                      q, mp, dlp, dlp->dl_primitive);
1011 1011  #endif
1012 1012          mutex_enter(&llc->llc_lock);
1013 1013          rw_enter(&llc1_device_list.llc1_rwlock, RW_READER);
1014 1014  
1015 1015          switch (dlp->dl_primitive) {
1016 1016          case DL_BIND_REQ:
1017 1017                  result = llc1_bind(q, mp);
1018 1018                  break;
1019 1019  
1020 1020          case DL_UNBIND_REQ:
1021 1021                  result = llc1_unbind(q, mp);
1022 1022                  break;
1023 1023  
1024 1024          case DL_SUBS_BIND_REQ:
1025 1025                  result = llc1_subs_bind(q, mp);
1026 1026                  break;
1027 1027  
1028 1028          case DL_SUBS_UNBIND_REQ:
1029 1029                  result = llc1_subs_unbind();
1030 1030                  break;
1031 1031  
1032 1032          case DL_UNITDATA_REQ:
1033 1033                  result = llc1_unitdata(q, mp);
1034 1034                  break;
1035 1035  
1036 1036          case DL_INFO_REQ:
1037 1037                  result = llc1_inforeq(q, mp);
1038 1038                  break;
1039 1039  
1040 1040          case DL_ATTACH_REQ:
1041 1041                  result = llc1attach(q, mp);
1042 1042                  break;
1043 1043  
1044 1044          case DL_DETACH_REQ:
1045 1045                  result = llc1unattach(q, mp);
1046 1046                  break;
1047 1047  
1048 1048          case DL_ENABMULTI_REQ:
1049 1049                  result = llc1_enable_multi(q, mp);
1050 1050                  break;
1051 1051  
1052 1052          case DL_DISABMULTI_REQ:
1053 1053                  result = llc1_disable_multi(q, mp);
1054 1054                  break;
1055 1055  
1056 1056          case DL_XID_REQ:
1057 1057                  result = llc1_xid_req_res(q, mp, 0);
1058 1058                  break;
1059 1059  
1060 1060          case DL_XID_RES:
1061 1061                  result = llc1_xid_req_res(q, mp, 1);
1062 1062                  break;
1063 1063  
1064 1064          case DL_TEST_REQ:
1065 1065                  result = llc1_test_req_res(q, mp, 0);
1066 1066                  break;
1067 1067  
1068 1068          case DL_TEST_RES:
1069 1069                  result = llc1_test_req_res(q, mp, 1);
1070 1070                  break;
1071 1071  
1072 1072          case DL_SET_PHYS_ADDR_REQ:
1073 1073                  result = DL_NOTSUPPORTED;
1074 1074                  break;
1075 1075  
1076 1076          case DL_PHYS_ADDR_REQ:
1077 1077                  if (llc->llc_state != DL_UNATTACHED && macinfo) {
1078 1078                          llc->llc_waiting_for = dlp->dl_primitive;
1079 1079                          putnext(WR(macinfo->llcp_queue), mp);
1080 1080                          result = LLCE_OK;
1081 1081                  } else {
1082 1082                          result = DL_OUTSTATE;
1083 1083                  }
1084 1084                  break;
1085 1085  
1086 1086          case DL_PROMISCON_REQ:
1087 1087          case DL_PROMISCOFF_REQ:
1088 1088                  result = DL_NOTSUPPORTED;
1089 1089                  break;
1090 1090  
1091 1091          default:
1092 1092  #ifdef LLC1_DEBUG
1093 1093                  if (llc1_debug & LLCERRS)
1094 1094                          printf("llc1_cmds: Received unknown primitive: %d\n",
1095 1095                              dlp->dl_primitive);
1096 1096  #endif
1097 1097                  result = DL_BADPRIM;
1098 1098                  break;
1099 1099          }
1100 1100          rw_exit(&llc1_device_list.llc1_rwlock);
1101 1101          mutex_exit(&llc->llc_lock);
1102 1102          return (result);
1103 1103  }
1104 1104  
1105 1105  /*
1106 1106   * llc1_bind - determine if a SAP is already allocated and whether it is
1107 1107   * legal to do the bind at this time
1108 1108   */
1109 1109  static int
1110 1110  llc1_bind(queue_t *q, mblk_t *mp)
1111 1111  {
1112 1112          int     sap;
1113 1113          dl_bind_req_t *dlp;
1114 1114          llc1_t *lld = (llc1_t *)q->q_ptr;
1115 1115  
1116 1116          ASSERT(lld);
1117 1117  
1118 1118  #ifdef LLC1_DEBUG
1119 1119          if (llc1_debug & LLCTRACE)
1120 1120                  printf("llc1_bind(%x %x)\n", q, mp);
1121 1121  #endif
1122 1122  
1123 1123          dlp = (dl_bind_req_t *)mp->b_rptr;
1124 1124          sap = dlp->dl_sap;
1125 1125  
1126 1126  #ifdef LLC1_DEBUG
1127 1127          if (llc1_debug & LLCPROT)
1128 1128                  printf("llc1_bind: lsap=%x\n", sap);
1129 1129  #endif
1130 1130  
1131 1131          if (lld->llc_mac_info == NULL)
1132 1132                  return (DL_OUTSTATE);
1133 1133  
1134 1134          if (lld->llc_qptr && lld->llc_state != DL_UNBOUND) {
1135 1135  #ifdef LLC1_DEBUG
1136 1136                  if (llc1_debug & LLCERRS)
1137 1137                          printf("llc1_bind: stream bound/not attached (%d)\n",
1138 1138                              lld->llc_state);
1139 1139  #endif
1140 1140                  return (DL_OUTSTATE);
1141 1141          }
1142 1142  
1143 1143          if (dlp->dl_service_mode != DL_CLDLS || dlp->dl_max_conind != 0) {
1144 1144                  return (DL_UNSUPPORTED);
1145 1145          }
1146 1146          /*
1147 1147           * prohibit group saps. An exception is the broadcast sap which is,
1148 1148           * unfortunately, used by SUNSelect to indicate Novell Netware in
1149 1149           * 802.3 mode.  Really should use a very non-802.2 SAP like 0xFFFF
1150 1150           * or -2.
1151 1151           */
1152 1152  
1153 1153          if (sap == 0 || (sap <= 0xFF && (sap & 1 && sap != 0xFF)) ||
1154 1154              sap > 0xFFFF) {
1155 1155                  return (DL_BADSAP);
1156 1156          }
1157 1157          lld->llc_state = DL_BIND_PENDING;
1158 1158  
1159 1159          /* if we fall through, then the SAP is legal */
1160 1160          if (sap == 0xFF) {
1161 1161                  if (lld->llc_mac_info->llcp_type == DL_CSMACD)
1162 1162                          sap = LLC_NOVELL_SAP;
1163 1163                  else
1164 1164                          return (DL_BADSAP);
1165 1165          }
1166 1166          lld->llc_sap = sap;
1167 1167  
1168 1168          if (sap > 0xFF) {
1169 1169                  ushort_t snapsap = htons(sap);
1170 1170                  /* this is SNAP, so set things up */
1171 1171                  lld->llc_snap[3] = ((uchar_t *)&snapsap)[0];
1172 1172                  lld->llc_snap[4] = ((uchar_t *)&snapsap)[1];
1173 1173                  /* mark as SNAP but allow OID to be added later */
1174 1174                  lld->llc_flags |= LLC_SNAP;
1175 1175                  lld->llc_sap = LLC_SNAP_SAP;
1176 1176          }
1177 1177  
1178 1178  #ifdef LLC1_DEBUG
1179 1179          if (llc1_debug & LLCPROT)
1180 1180                  printf("llc1_bind: ok - type = %d\n", lld->llc_type);
1181 1181  #endif
1182 1182  
1183 1183          if (dlp->dl_xidtest_flg & DL_AUTO_XID)
1184 1184                  lld->llc_flags |= LLC1_AUTO_XID;
1185 1185          if (dlp->dl_xidtest_flg & DL_AUTO_TEST)
1186 1186                  lld->llc_flags |= LLC1_AUTO_TEST;
1187 1187  
1188 1188          /* ACK the BIND, if possible */
1189 1189  
1190 1190          dlbindack(q, mp, sap, lld->llc_mac_info->llcp_macaddr, 6, 0, 0);
1191 1191  
1192 1192          lld->llc_state = DL_IDLE;       /* bound and ready */
1193 1193  
1194 1194          return (LLCE_OK);
1195 1195  }
1196 1196  
1197 1197  /*
1198 1198   * llc1_unbind - perform an unbind of an LSAP or ether type on the stream.
1199 1199   * The stream is still open and can be re-bound.
1200 1200   */
1201 1201  static int
1202 1202  llc1_unbind(queue_t *q, mblk_t *mp)
1203 1203  {
1204 1204          llc1_t *lld;
1205 1205  
1206 1206  #ifdef LLC1_DEBUG
1207 1207          if (llc1_debug & LLCTRACE)
1208 1208                  printf("llc1_unbind(%x %x)\n", q, mp);
1209 1209  #endif
1210 1210          lld = (llc1_t *)q->q_ptr;
1211 1211  
1212 1212          if (lld->llc_mac_info == NULL)
1213 1213                  return (DL_OUTSTATE);
1214 1214  
1215 1215          if (lld->llc_state != DL_IDLE) {
1216 1216  #ifdef LLC1_DEBUG
1217 1217                  if (llc1_debug & LLCERRS)
1218 1218                          printf("llc1_unbind: wrong state (%d)\n",
1219 1219                              lld->llc_state);
1220 1220  #endif
1221 1221                  return (DL_OUTSTATE);
1222 1222          }
1223 1223          lld->llc_state = DL_UNBIND_PENDING;
1224 1224          lld->llc_flags &= ~(LLC_SNAP|LLC_SNAP_OID); /* just in case */
1225 1225          dlokack(q, mp, DL_UNBIND_REQ);
1226 1226          lld->llc_state = DL_UNBOUND;
1227 1227          return (LLCE_OK);
1228 1228  }
1229 1229  
1230 1230  /*
1231 1231   * llc1_inforeq - generate the response to an info request
1232 1232   */
1233 1233  static int
1234 1234  llc1_inforeq(queue_t *q, mblk_t *mp)
1235 1235  {
1236 1236          llc1_t *lld;
1237 1237          mblk_t *nmp;
1238 1238          dl_info_ack_t *dlp;
1239 1239          int     bufsize;
1240 1240  
1241 1241  #ifdef LLC1_DEBUG
1242 1242          if (llc1_debug & LLCTRACE)
1243 1243                  printf("llc1_inforeq(%x %x)\n", q, mp);
1244 1244  #endif
1245 1245          lld = (llc1_t *)q->q_ptr;
1246 1246          ASSERT(lld);
1247 1247          if (lld->llc_mac_info == NULL)
1248 1248                  bufsize = sizeof (dl_info_ack_t) + ETHERADDRL;
1249 1249          else
1250 1250                  bufsize = sizeof (dl_info_ack_t) +
1251 1251                      2 * lld->llc_mac_info->llcp_addrlen + 2;
1252 1252  
1253 1253          nmp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK);
1254 1254  
1255 1255          if (nmp) {
1256 1256                  nmp->b_wptr = nmp->b_rptr + sizeof (dl_info_ack_t);
1257 1257                  dlp = (dl_info_ack_t *)nmp->b_rptr;
1258 1258                  bzero(dlp, DL_INFO_ACK_SIZE);
1259 1259                  dlp->dl_primitive = DL_INFO_ACK;
1260 1260                  if (lld->llc_mac_info)
1261 1261                          dlp->dl_max_sdu = lld->llc_mac_info->llcp_maxpkt;
1262 1262                  dlp->dl_min_sdu = 0;
1263 1263                  dlp->dl_mac_type = lld->llc_type;
1264 1264                  dlp->dl_service_mode = DL_CLDLS;
1265 1265                  dlp->dl_current_state = lld->llc_state;
1266 1266                  dlp->dl_provider_style =
1267 1267                      (lld->llc_style == 0) ? lld->llc_style : DL_STYLE2;
1268 1268  
1269 1269                  /* now append physical address */
1270 1270                  if (lld->llc_mac_info) {
1271 1271                          dlp->dl_addr_length = lld->llc_mac_info->llcp_addrlen;
1272 1272                          dlp->dl_addr_offset = DL_INFO_ACK_SIZE;
1273 1273                          nmp->b_wptr += dlp->dl_addr_length + 1;
1274 1274                          bcopy(lld->llc_mac_info->llcp_macaddr,
1275 1275                              ((caddr_t)dlp) + dlp->dl_addr_offset,
1276 1276                              lld->llc_mac_info->llcp_addrlen);
1277 1277                          if (lld->llc_state == DL_IDLE) {
1278 1278                                  dlp->dl_sap_length = -1; /* 1 byte on end */
1279 1279                                  *(((caddr_t)dlp) + dlp->dl_addr_offset +
1280 1280                                      dlp->dl_addr_length) = lld->llc_sap;
1281 1281                                  dlp->dl_addr_length += 1;
1282 1282                          }
1283 1283                          /* and the broadcast address */
1284 1284                          dlp->dl_brdcst_addr_length =
1285 1285                              lld->llc_mac_info->llcp_addrlen;
1286 1286                          dlp->dl_brdcst_addr_offset =
1287 1287                              dlp->dl_addr_offset + dlp->dl_addr_length;
1288 1288                          nmp->b_wptr += dlp->dl_brdcst_addr_length;
1289 1289                          bcopy(lld->llc_mac_info->llcp_broadcast,
1290 1290                              ((caddr_t)dlp) + dlp->dl_brdcst_addr_offset,
1291 1291                              lld->llc_mac_info->llcp_addrlen);
1292 1292                  } else {
1293 1293                          dlp->dl_addr_length = 0; /* not attached yet */
1294 1294                          dlp->dl_addr_offset = NULL;
1295 1295                          dlp->dl_sap_length = 0; /* 1 bytes on end */
1296 1296                  }
1297 1297                  dlp->dl_version = DL_VERSION_2;
1298 1298                  qreply(q, nmp);
1299 1299          }
1300 1300          return (LLCE_OK);
1301 1301  }
1302 1302  
1303 1303  /*
1304 1304   * llc1_unitdata
1305 1305   * send a datagram.  Destination address/lsap is in M_PROTO
1306 1306   * message (first mblock), data is in remainder of message.
1307 1307   *
1308 1308   * NOTE: We are reusing the DL_unitdata_req mblock; if llc header gets any
1309 1309   * bigger, recheck to make sure it still fits!  We assume that we have a
1310 1310   * 64-byte dblock for this, since a DL_unitdata_req is 20 bytes and the next
1311 1311   * larger dblock size is 64.
1312 1312   */
1313 1313  static int
1314 1314  llc1_unitdata(queue_t *q, mblk_t *mp)
1315 1315  {
1316 1316          llc1_t *lld = (llc1_t *)q->q_ptr;
1317 1317          dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1318 1318          struct ether_header *hdr;
1319 1319          struct llcaddr *llcp;
1320 1320          mblk_t *nmp;
1321 1321          long    msglen;
1322 1322          struct llchdr *llchdr;
1323 1323          llc_mac_info_t *macinfo;
1324 1324          int xmt_type = 0;
1325 1325  
1326 1326  #ifdef LLC1_DEBUG
1327 1327          if (llc1_debug & LLCTRACE)
1328 1328                  printf("llc1_unitdata(%x %x)\n", q, mp);
1329 1329  #endif
1330 1330  
1331 1331          if ((macinfo = lld->llc_mac_info) == NULL)
1332 1332                  return (DL_OUTSTATE);
1333 1333  
1334 1334          if (lld->llc_state != DL_IDLE) {
1335 1335  #ifdef LLC1_DEBUG
1336 1336                  if (llc1_debug & LLCERRS)
1337 1337                          printf("llc1_unitdata: wrong state (%d)\n",
1338 1338                              lld->llc_state);
1339 1339  #endif
1340 1340                  return (DL_OUTSTATE);
1341 1341          }
1342 1342  
1343 1343          /* need the destination address in all cases */
1344 1344          llcp = (struct llcaddr *)((caddr_t)dlp + dlp->dl_dest_addr_offset);
1345 1345  
1346 1346          if (macinfo->llcp_flags & LLC1_USING_RAW) {
1347 1347                  /*
1348 1348                   * make a valid header for transmission
1349 1349                   */
1350 1350  
1351 1351              /* need a buffer big enough for the headers */
1352 1352                  nmp = allocb(macinfo->llcp_addrlen * 2 + 2 + 8, BPRI_MED);
1353 1353                  hdr = (struct ether_header *)nmp->b_rptr;
1354 1354                  msglen = msgdsize(mp);
1355 1355  
1356 1356              /* fill in type dependent fields */
1357 1357                  switch (lld->llc_type) {
1358 1358                  case DL_CSMACD: /* 802.3 CSMA/CD */
1359 1359                  nmp->b_wptr = nmp->b_rptr + LLC1_CSMACD_HDR_SIZE;
1360 1360                  llchdr = (struct llchdr *)nmp->b_wptr;
1361 1361                  bcopy(llcp->llca_addr,
1362 1362                      hdr->ether_dhost.ether_addr_octet,
1363 1363                      ETHERADDRL);
1364 1364                  bcopy(macinfo->llcp_macaddr,
1365 1365                      hdr->ether_shost.ether_addr_octet,
1366 1366                      ETHERADDRL);
1367 1367  
1368 1368                  if (lld->llc_sap != LLC_NOVELL_SAP) {
1369 1369                          /* set length with llc header size */
1370 1370                          hdr->ether_type = ntohs(msglen +
1371 1371                              sizeof (struct llchdr));
1372 1372  
1373 1373                          /* need an LLC header, otherwise is Novell */
1374 1374                          /* bound sap is always source */
1375 1375                          llchdr->llc_ssap = lld->llc_sap;
1376 1376  
1377 1377                          /* destination sap */
1378 1378                          llchdr->llc_dsap = llcp->llca_sap;
1379 1379  
1380 1380                          /* always Unnumbered Information */
1381 1381                          llchdr->llc_ctl = LLC_UI;
1382 1382  
1383 1383                          nmp->b_wptr += sizeof (struct llchdr);
1384 1384  
1385 1385                          if (lld->llc_flags & LLC_SNAP) {
1386 1386                                  bcopy(lld->llc_snap, nmp->b_wptr, 5);
1387 1387                                  llchdr->llc_dsap = LLC_SNAP_SAP;
1388 1388                                  nmp->b_wptr += 5;
1389 1389                          }
1390 1390                  } else {
1391 1391                          /* set length without llc header size */
1392 1392                          hdr->ether_type = ntohs(msglen);
1393 1393  
1394 1394                          /* we don't do anything else for Netware */
1395 1395                  }
1396 1396  
1397 1397                  if (ismulticast(hdr->ether_dhost.ether_addr_octet)) {
1398 1398                          if (bcmp(hdr->ether_dhost.ether_addr_octet,
1399 1399                              macinfo->llcp_broadcast, ETHERADDRL) == 0)
1400 1400                                  xmt_type = 2;
1401 1401                          else
1402 1402                                  xmt_type = 1;
1403 1403                  }
1404 1404  
1405 1405                  break;
1406 1406  
1407 1407                  default:                /* either RAW or unknown, send as is */
1408 1408                  break;
1409 1409                  }
1410 1410                  DB_TYPE(nmp) = M_DATA; /* ether/llc header is data */
1411 1411                  nmp->b_cont = mp->b_cont;       /* use the data given */
1412 1412                  freeb(mp);
1413 1413                  mp = nmp;
1414 1414          } else {
1415 1415              /* need to format a DL_UNITDATA_REQ with LLC1 header inserted */
1416 1416                  nmp = allocb(sizeof (struct llchdr)+sizeof (struct snaphdr),
1417 1417                      BPRI_MED);
1418 1418                  if (nmp == NULL)
1419 1419                  return (DL_UNDELIVERABLE);
1420 1420                  llchdr = (struct llchdr *)(nmp->b_rptr);
1421 1421                  nmp->b_wptr += sizeof (struct llchdr);
1422 1422                  llchdr->llc_dsap = llcp->llca_sap;
1423 1423                  llchdr->llc_ssap = lld->llc_sap;
1424 1424                  llchdr->llc_ctl = LLC_UI;
1425 1425  
1426 1426                  /*
1427 1427                   * if we are using SNAP, insert the header here
1428 1428                   */
1429 1429                  if (lld->llc_flags & LLC_SNAP) {
1430 1430                          bcopy(lld->llc_snap, nmp->b_wptr, 5);
1431 1431                          nmp->b_wptr += 5;
1432 1432                  }
1433 1433                  nmp->b_cont = mp->b_cont;
1434 1434                  mp->b_cont = nmp;
1435 1435                  nmp = mp;
1436 1436                  if (ismulticast(llcp->llca_addr)) {
1437 1437                          if (bcmp(llcp->llca_addr,
1438 1438                              macinfo->llcp_broadcast, ETHERADDRL) == 0)
1439 1439                                  xmt_type = 2;
1440 1440                          else
1441 1441                                  xmt_type = 1;
1442 1442                  }
1443 1443          }
1444 1444          if (canput(macinfo->llcp_queue)) {
1445 1445                  lld->llc_stats->llcs_bytexmt += msgdsize(mp);
1446 1446                  lld->llc_stats->llcs_pktxmt++;
1447 1447                  switch (xmt_type) {
1448 1448                  case 1:
1449 1449                          macinfo->llcp_stats.llcs_multixmt++;
1450 1450                          break;
1451 1451                  case 2:
1452 1452                          macinfo->llcp_stats.llcs_brdcstxmt++;
1453 1453                          break;
1454 1454                  }
1455 1455  
1456 1456                  putnext(macinfo->llcp_queue, mp);
1457 1457                  return (LLCE_OK);       /* this is almost correct, the result */
1458 1458          } else {
1459 1459                  lld->llc_stats->llcs_nobuffer++;
1460 1460          }
1461 1461          if (nmp != NULL)
1462 1462                  freemsg(nmp);   /* free on failure */
1463 1463          return (LLCE_OK);
1464 1464  }
1465 1465  
1466 1466  /*
1467 1467   * llc1_recv(macinfo, mp)
1468 1468   * called with an ethernet packet in a mblock; must decide
1469 1469   * whether packet is for us and which streams to queue it to. This routine is
1470 1470   * called with locally originated packets for loopback.
1471 1471   */
1472 1472  static void
1473 1473  llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp)
1474 1474  {
1475 1475          struct ether_addr *addr;
1476 1476          llc1_t *lld;
1477 1477          mblk_t *nmp, *udmp;
1478 1478          int     i, nmcast = 0, statcnt_normal = 0, statcnt_brdcst = 0;
1479 1479          int valid, msgsap;
1480 1480          struct llchdr *llchdr;
1481 1481  
1482 1482  #ifdef LLC1_DEBUG
1483 1483          if (llc1_debug & LLCTRACE)
1484 1484                  printf("llc1_recv(%x, %x)\n", mp, macinfo);
1485 1485  #endif
1486 1486  
1487 1487          if (DB_TYPE(mp) == M_PROTO) {
1488 1488                  dl_unitdata_ind_t *udata;
1489 1489  
1490 1490                  /* check to see if really LLC1 XXX */
1491 1491                  /* also need to make sure to keep address info */
1492 1492                  nmp = mp;
1493 1493                  udata = (dl_unitdata_ind_t *)(nmp->b_rptr);
1494 1494                  addr = (struct ether_addr *)(nmp->b_rptr +
1495 1495                      udata->dl_dest_addr_offset);
1496 1496                  llchdr = (struct llchdr *)(nmp->b_cont->b_rptr);
1497 1497                  if (macinfo->llcp_type == DL_CSMACD) {
1498 1498                          i = ((struct llcsaddr *)addr)->llca_ssap;
1499 1499                          if (i < 60) {
1500 1500                                  valid = adjmsg(mp->b_cont, i - msgdsize(mp));
1501 1501                          }
1502 1502                  }
1503 1503          } else {
1504 1504                  struct ether_header *hdr;
1505 1505  
1506 1506                  /* Note that raw mode currently assumes Ethernet */
1507 1507                  nmp = NULL;
1508 1508                  hdr = (struct ether_header *)mp->b_rptr;
1509 1509                  addr = &hdr->ether_dhost;
1510 1510                  llchdr = (struct llchdr *)(mp->b_rptr +
1511 1511                      sizeof (struct ether_header));
1512 1512                  i = (ushort_t)ntohs(hdr->ether_type);
1513 1513                  if (i < 60) {
1514 1514                          (void) adjmsg(mp, i + sizeof (struct ether_header) -
1515 1515                              msgdsize(mp));
1516 1516                  }
1517 1517          }
1518 1518          udmp = NULL;
1519 1519  
1520 1520          msgsap = llchdr->llc_dsap;
1521 1521  
1522 1522  #ifdef LLC1_DEBUG
1523 1523          if (llc1_debug & LLCRECV) {
1524 1524                  printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr));
1525 1525          }
1526 1526  #endif
1527 1527  
1528 1528          if (llc1_broadcast(addr, macinfo)) {
1529 1529                  valid = 2;      /* 2 means valid but multicast */
1530 1530                  statcnt_brdcst = 1;
1531 1531          } else {
1532 1532                  valid = llc1_local(addr, macinfo);
1533 1533                  statcnt_normal = msgdsize(mp);
1534 1534          }
1535 1535  
1536 1536          /*
1537 1537           * Note that the NULL SAP is a special case.  It is associated with
1538 1538           * the MAC layer and not the LLC layer so should be handled
1539 1539           * independently of any STREAM.
1540 1540           */
1541 1541          if (msgsap == LLC_NULL_SAP) {
1542 1542                  /* only XID and TEST ever processed, UI is dropped */
1543 1543                  if ((llchdr->llc_ctl & ~LLC_P) == LLC_XID)
1544 1544                          mp = llc1_xid_reply(macinfo, mp, 0);
1545 1545                  else if ((llchdr->llc_ctl & ~LLC_P) == LLC_TEST)
1546 1546                          mp = llc1_test_reply(macinfo, mp, 0);
1547 1547          } else
1548 1548                  for (lld = llc1_device_list.llc1_str_next;
1549 1549                      lld != (llc1_t *)&llc1_device_list.llc1_str_next;
1550 1550                      lld = lld->llc_next) {
1551 1551  
1552 1552                          /*
1553 1553                           * is this a potentially usable SAP on the
1554 1554                           * right MAC layer?
1555 1555                           */
1556 1556                          if (lld->llc_qptr == NULL ||
1557 1557                              lld->llc_state != DL_IDLE ||
1558 1558                              lld->llc_mac_info != macinfo) {
1559 1559                                  continue;
1560 1560                          }
1561 1561  #ifdef LLC1_DEBUG
1562 1562                          if (llc1_debug & LLCRECV)
1563 1563                                  printf(
1564 1564  "llc1_recv: type=%d, sap=%x, pkt-dsap=%x\n",
1565 1565                                      lld->llc_type, lld->llc_sap,
1566 1566                                      msgsap);
1567 1567  #endif
1568 1568                          if (!valid && ismulticast(addr->ether_addr_octet) &&
1569 1569                              lld->llc_multicnt > 0 &&
1570 1570                              llc1_multicast(addr, lld)) {
1571 1571                                  valid |= 4;
1572 1572                          } else if (lld->llc_flags & LLC_PROM)
1573 1573                                  /* promiscuous mode */
1574 1574                                  valid = 1;
1575 1575  
1576 1576                          if ((lld->llc_flags & LLC_PROM) ||
1577 1577                                  /* promiscuous streams */
1578 1578                              (valid &&
1579 1579                              (lld->llc_sap == msgsap ||
1580 1580                              msgsap == LLC_GLOBAL_SAP))) {
1581 1581                                  /* sap matches */
1582 1582                                  if (msgsap == LLC_SNAP_SAP &&
1583 1583                                      (lld->llc_flags & (LLC_SNAP|LLC_PROM)) ==
1584 1584                                      LLC_SNAP) {
1585 1585                                          if (!llc1_snap_match(lld,
1586 1586                                              (struct snaphdr *)(llchdr+1)))
1587 1587                                                  continue;
1588 1588                                  }
1589 1589                                  if (!canputnext(RD(lld->llc_qptr))) {
1590 1590  #ifdef LLC1_DEBUG
1591 1591                                          if (llc1_debug & LLCRECV)
1592 1592                                                  printf(
1593 1593  "llc1_recv: canput failed\n");
1594 1594  #endif
1595 1595                                          lld->llc_stats->llcs_blocked++;
1596 1596                                          continue;
1597 1597                                  }
1598 1598                                  /* check for Novell special handling */
1599 1599                                  if (msgsap == LLC_GLOBAL_SAP &&
1600 1600                                      lld->llc_sap == LLC_NOVELL_SAP &&
1601 1601                                      llchdr->llc_ssap == LLC_GLOBAL_SAP) {
1602 1602  
1603 1603                                          /* A Novell packet */
1604 1604                                          nmp = llc1_form_udata(lld, macinfo, mp);
1605 1605                                          continue;
1606 1606                                  }
1607 1607                                  switch (llchdr->llc_ctl) {
1608 1608                                  case LLC_UI:
1609 1609                                          /*
1610 1610                                           * this is an Unnumbered Information
1611 1611                                           * packet so form a DL_UNITDATA_IND and
1612 1612                                           * send to user
1613 1613                                           */
1614 1614                                          nmp = llc1_form_udata(lld, macinfo, mp);
1615 1615                                          break;
1616 1616  
1617 1617                                  case LLC_XID:
1618 1618                                  case LLC_XID | LLC_P:
1619 1619                                          /*
1620 1620                                           * this is either an XID request or
1621 1621                                           * response. We either handle directly
1622 1622                                           * (if user hasn't requested to handle
1623 1623                                           * itself) or send to user. We also
1624 1624                                           * must check if a response if user
1625 1625                                           * handled so that we can send correct
1626 1626                                           * message form
1627 1627                                           */
1628 1628                                          if (lld->llc_flags & LLC1_AUTO_XID) {
1629 1629                                                  nmp = llc1_xid_reply(macinfo,
1630 1630                                                      mp, lld->llc_sap);
1631 1631                                          } else {
1632 1632                                                  /*
1633 1633                                                   * hand to the user for
1634 1634                                                   * handling. if this is a
1635 1635                                                   * "request", generate a
1636 1636                                                   * DL_XID_IND.  If it is a
1637 1637                                                   * "response" to one of our
1638 1638                                                   * requests, generate a
1639 1639                                                   * DL_XID_CON.
1640 1640                                                   */
1641 1641                                                  nmp = llc1_xid_ind_con(lld,
1642 1642                                                      macinfo, mp);
1643 1643                                          }
1644 1644                                          macinfo->llcp_stats.llcs_xidrcv++;
1645 1645                                          break;
1646 1646  
1647 1647                                  case LLC_TEST:
1648 1648                                  case LLC_TEST | LLC_P:
1649 1649                                          /*
1650 1650                                           * this is either a TEST request or
1651 1651                                           * response.  We either handle
1652 1652                                           * directly (if user hasn't
1653 1653                                           * requested to handle itself)
1654 1654                                           * or send to user.  We also
1655 1655                                           * must check if a response if
1656 1656                                           * user handled so that we can
1657 1657                                           * send correct message form
1658 1658                                           */
1659 1659                                          if (lld->llc_flags & LLC1_AUTO_TEST) {
1660 1660                                                  nmp = llc1_test_reply(macinfo,
1661 1661                                                      mp, lld->llc_sap);
1662 1662                                          } else {
1663 1663                                                  /*
1664 1664                                                   * hand to the user for
1665 1665                                                   * handling. if this is
1666 1666                                                   * a "request",
1667 1667                                                   * generate a
1668 1668                                                   * DL_TEST_IND. If it
1669 1669                                                   * is a "response" to
1670 1670                                                   * one of our requests,
1671 1671                                                   * generate a
1672 1672                                                   * DL_TEST_CON.
1673 1673                                                   */
1674 1674                                                  nmp = llc1_test_ind_con(lld,
1675 1675                                                      macinfo, mp);
1676 1676                                          }
1677 1677                                          macinfo->llcp_stats.llcs_testrcv++;
1678 1678                                          break;
1679 1679                                  default:
1680 1680                                          nmp = mp;
1681 1681                                          break;
1682 1682                                  }
1683 1683                                  mp = nmp;
1684 1684                          }
1685 1685                  }
1686 1686          if (mp != NULL)
1687 1687                  freemsg(mp);
1688 1688          if (udmp != NULL)
1689 1689                  freeb(udmp);
1690 1690          if (nmcast > 0)
1691 1691                  macinfo->llcp_stats.llcs_multircv++;
1692 1692          if (statcnt_brdcst) {
1693 1693                  macinfo->llcp_stats.llcs_brdcstrcv++;
1694 1694          }
1695 1695          if (statcnt_normal) {
1696 1696                  macinfo->llcp_stats.llcs_bytercv += statcnt_normal;
1697 1697                  macinfo->llcp_stats.llcs_pktrcv++;
1698 1698          }
1699 1699  }
1700 1700  
1701 1701  /*
1702 1702   * llc1_local - check to see if the message is addressed to this system by
1703 1703   * comparing with the board's address.
1704 1704   */
1705 1705  static int
1706 1706  llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo)
1707 1707  {
1708 1708          return (bcmp(addr->ether_addr_octet, macinfo->llcp_macaddr,
1709 1709              macinfo->llcp_addrlen) == 0);
1710 1710  }
1711 1711  
1712 1712  /*
1713 1713   * llc1_broadcast - check to see if a broadcast address is the destination of
1714 1714   * this received packet
1715 1715   */
1716 1716  static int
1717 1717  llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo)
1718 1718  {
1719 1719          return (bcmp(addr->ether_addr_octet, macinfo->llcp_broadcast,
1720 1720              macinfo->llcp_addrlen) == 0);
1721 1721  }
1722 1722  
1723 1723  /*
1724 1724   * llc1attach(q, mp) DLPI DL_ATTACH_REQ this attaches the stream to a PPA
1725 1725   */
1726 1726  static int
1727 1727  llc1attach(queue_t *q, mblk_t *mp)
1728 1728  {
1729 1729          dl_attach_req_t *at;
1730 1730          llc_mac_info_t *mac;
1731 1731          llc1_t *llc = (llc1_t *)q->q_ptr;
1732 1732  
1733 1733          at = (dl_attach_req_t *)mp->b_rptr;
1734 1734  
1735 1735          if (llc->llc_state != DL_UNATTACHED) {
1736 1736                  return (DL_OUTSTATE);
1737 1737          }
1738 1738          llc->llc_state = DL_ATTACH_PENDING;
1739 1739  
1740 1740          if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
1741 1741                  /*
1742 1742                   * someone else has a lock held.  To avoid deadlock,
1743 1743                   * release the READER lock and block on a WRITER
1744 1744                   * lock.  This will let things continue safely.
1745 1745                   */
1746 1746                  rw_exit(&llc1_device_list.llc1_rwlock);
1747 1747                  rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
1748 1748          }
1749 1749  
1750 1750          for (mac = llc1_device_list.llc1_mac_next;
1751 1751              mac != (llc_mac_info_t *)(&llc1_device_list.llc1_mac_next);
1752 1752              mac = mac->llcp_next) {
1753 1753                  ASSERT(mac);
1754 1754                  if (mac->llcp_ppa == at->dl_ppa && mac->llcp_lqtop == q) {
1755 1755                          /*
1756 1756                           * We may have found the correct PPA
1757 1757                           * check to see if linking has finished.
1758 1758                           * Use explicit flag checks for incorrect
1759 1759                           * state, and use negative values for "tenative"
1760 1760                           * llcp_ppas, to avoid erroneous attaches.
1761 1761                           */
1762 1762                          if (mac->llcp_flags &
1763 1763                              (LLC1_LINKED|LLC1_DEF_PPA)) {
1764 1764                                  return (DL_INITFAILED);
1765 1765                          } else if (!(mac->llcp_flags & LLC1_AVAILABLE)) {
1766 1766                                  return (DL_BADPPA);
1767 1767                          }
1768 1768  
1769 1769                          /* this links us to the PPA */
1770 1770                          mac->llcp_nstreams++;
1771 1771                          llc->llc_mac_info = mac;
1772 1772  
1773 1773                          llc->llc_state = DL_UNBOUND; /* now ready for action */
1774 1774                          llc->llc_stats = &mac->llcp_stats;
1775 1775                          dlokack(q, mp, DL_ATTACH_REQ);
1776 1776  
1777 1777                          return (LLCE_OK);
1778 1778                  }
1779 1779          }
1780 1780          llc->llc_state = DL_UNATTACHED;
1781 1781          return (DL_BADPPA);
1782 1782  }
1783 1783  
1784 1784  /*
1785 1785   * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the
1786 1786   * stream
1787 1787   */
1788 1788  static int
1789 1789  llc1unattach(queue_t *q, mblk_t *mp)
1790 1790  {
1791 1791          llc1_t *llc = (llc1_t *)q->q_ptr;
1792 1792          int     state;
1793 1793          int     i;
1794 1794  
1795 1795          state = llc->llc_state;
1796 1796          if (state != DL_UNBOUND)
1797 1797                  return (DL_OUTSTATE);
1798 1798  
1799 1799          /* can now detach from the PPA */
1800 1800          llc->llc_state = DL_DETACH_PENDING;
1801 1801  
1802 1802          if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
1803 1803                  /*
1804 1804                   * someone else has a lock held.  To avoid deadlock,
1805 1805                   * release the READER lock and block on a WRITER
1806 1806                   * lock.  This will let things continue safely.
1807 1807                   */
1808 1808                  rw_exit(&llc1_device_list.llc1_rwlock);
1809 1809                  rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
1810 1810          }
1811 1811  
1812 1812          if (llc->llc_mcast) {
1813 1813                  for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1814 1814                          llc_mcast_t *mcast;
1815 1815  
1816 1816                          if ((mcast = llc->llc_mcast[i]) != NULL) {
1817 1817                                  /* disable from stream and possibly lower */
1818 1818                                  llc1_send_disable_multi(llc->llc_mac_info,
1819 1819                                      mcast);
1820 1820                                  llc->llc_mcast[i] = NULL;
1821 1821                          }
1822 1822                  }
1823 1823                  kmem_free(llc->llc_mcast,
1824 1824                      sizeof (llc_mcast_t *) * llc->llc_multicnt);
1825 1825                  llc->llc_mcast = NULL;
1826 1826          }
1827 1827          if (llc->llc_mac_info)
1828 1828                  llc->llc_mac_info->llcp_nstreams--;
1829 1829          llc->llc_sap = 0;
1830 1830          llc->llc_state = DL_UNATTACHED;
1831 1831          if (mp) {
1832 1832                  dlokack(q, mp, DL_DETACH_REQ);
1833 1833          }
1834 1834          return (LLCE_OK);
1835 1835  }
1836 1836  
1837 1837  /*
1838 1838   * llc1_enable_multi enables multicast address on the stream if the mac layer
1839 1839   * isn't enabled for this address, enable at that level as well.
1840 1840   */
1841 1841  static int
1842 1842  llc1_enable_multi(queue_t *q, mblk_t *mp)
1843 1843  {
1844 1844          llc1_t *llc;
1845 1845          llc_mac_info_t *macinfo;
1846 1846          struct ether_addr *maddr;
1847 1847          dl_enabmulti_req_t *multi;
1848 1848          llc_mcast_t *mcast;
1849 1849          int     status = DL_BADADDR;
1850 1850          int     i;
1851 1851  
1852 1852  #if defined(LLC1_DEBUG)
1853 1853          if (llc1_debug & LLCPROT) {
1854 1854                  printf("llc1_enable_multi(%x, %x)\n", q, mp);
1855 1855          }
1856 1856  #endif
1857 1857  
1858 1858          llc = (llc1_t *)q->q_ptr;
1859 1859  
1860 1860          if (llc->llc_state == DL_UNATTACHED)
1861 1861                  return (DL_OUTSTATE);
1862 1862  
1863 1863          macinfo = llc->llc_mac_info;
1864 1864          multi = (dl_enabmulti_req_t *)mp->b_rptr;
1865 1865          maddr = (struct ether_addr *)(mp->b_rptr + multi->dl_addr_offset);
1866 1866  
1867 1867          /*
1868 1868           * check to see if this multicast address is valid if it is, then
1869 1869           * check to see if it is already in the per stream table and the per
1870 1870           * device table if it is already in the per stream table, if it isn't
1871 1871           * in the per device, add it.  If it is, just set a pointer.  If it
1872 1872           * isn't, allocate what's necessary.
1873 1873           */
1874 1874  
1875 1875          if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
1876 1876              MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) &&
1877 1877              multi->dl_addr_length == macinfo->llcp_addrlen &&
1878 1878              ismulticast(maddr->ether_addr_octet)) {
1879 1879                  /* request appears to be valid */
1880 1880                  /* does this address appear in current table? */
1881 1881                  if (llc->llc_mcast == NULL) {
1882 1882                          /* no mcast addresses -- allocate table */
1883 1883                          llc->llc_mcast =
1884 1884                              GETSTRUCT(llc_mcast_t *,
1885 1885                              llc1_device_list.llc1_multisize);
1886 1886                          if (llc->llc_mcast == NULL)
1887 1887                                  return (DL_SYSERR);
1888 1888                          llc->llc_multicnt = llc1_device_list.llc1_multisize;
1889 1889                  } else {
1890 1890                          for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1891 1891                                  if (llc->llc_mcast[i] &&
1892 1892                                      bcmp(llc->llc_mcast[i]->llcm_addr,
1893 1893                                      maddr->ether_addr_octet, ETHERADDRL)) {
1894 1894                                          /* this is a match -- just succeed */
1895 1895                                          dlokack(q, mp, DL_ENABMULTI_REQ);
1896 1896                                          return (LLCE_OK);
1897 1897                                  }
1898 1898                          }
1899 1899                  }
1900 1900                  /*
1901 1901                   * there wasn't one so check to see if the mac layer has one
1902 1902                   */
1903 1903                  if (macinfo->llcp_mcast == NULL) {
1904 1904                          macinfo->llcp_mcast =
1905 1905                              GETSTRUCT(llc_mcast_t,
1906 1906                              llc1_device_list.llc1_multisize);
1907 1907                          if (macinfo->llcp_mcast == NULL)
1908 1908                                  return (DL_SYSERR);
1909 1909                  }
1910 1910                  for (mcast = NULL, i = 0;
1911 1911                      i < llc1_device_list.llc1_multisize; i++) {
1912 1912                          if (macinfo->llcp_mcast[i].llcm_refcnt &&
1913 1913                              bcmp(macinfo->llcp_mcast[i].llcm_addr,
1914 1914                              maddr->ether_addr_octet, ETHERADDRL) == 0) {
1915 1915                                  mcast = &macinfo->llcp_mcast[i];
1916 1916                                  break;
1917 1917                          }
1918 1918                  }
1919 1919                  if (mcast == NULL) {
1920 1920                          mblk_t *nmp;
1921 1921  
1922 1922                          nmp = dupmsg(mp);
1923 1923                          if (nmp) {
1924 1924                                  nmp->b_cont = NULL;
1925 1925                                  DB_TYPE(nmp) = M_PROTO;
1926 1926                                  putnext(WR(macinfo->llcp_queue), nmp);
1927 1927                          }
1928 1928                          /* find an empty slot to fill in */
1929 1929                          for (mcast = macinfo->llcp_mcast, i = 0;
1930 1930                              i < llc1_device_list.llc1_multisize; i++, mcast++) {
1931 1931                                  if (mcast->llcm_refcnt == 0) {
1932 1932                                          bcopy(maddr->ether_addr_octet,
1933 1933                                              mcast->llcm_addr, ETHERADDRL);
1934 1934                                          break;
1935 1935                                  }
1936 1936                          }
1937 1937                  }
1938 1938                  if (mcast != NULL) {
1939 1939                          for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1940 1940                                  if (llc->llc_mcast[i] == NULL) {
1941 1941                                          llc->llc_mcast[i] = mcast;
1942 1942                                          mcast->llcm_refcnt++;
1943 1943                                          dlokack(q, mp, DL_ENABMULTI_REQ);
1944 1944                                          return (LLCE_OK);
1945 1945                                  }
1946 1946                          }
1947 1947                  }
1948 1948                  status = DL_TOOMANY;
1949 1949          }
1950 1950          return (status);
1951 1951  }
1952 1952  
1953 1953  /*
1954 1954   * llc1_disable_multi disable the multicast address on the stream if last
1955 1955   * reference for the mac layer, disable there as well
1956 1956   */
1957 1957  static int
1958 1958  llc1_disable_multi(queue_t *q, mblk_t *mp)
1959 1959  {
1960 1960          llc1_t *llc;
1961 1961          llc_mac_info_t *macinfo;
1962 1962          struct ether_addr *maddr;
1963 1963          dl_enabmulti_req_t *multi;
1964 1964          int     status = DL_BADADDR, i;
1965 1965          llc_mcast_t *mcast;
1966 1966  
1967 1967  #if defined(LLC1_DEBUG)
1968 1968          if (llc1_debug & LLCPROT) {
1969 1969                  printf("llc1_enable_multi(%x, %x)\n", q, mp);
1970 1970          }
1971 1971  #endif
1972 1972  
1973 1973          llc = (llc1_t *)q->q_ptr;
1974 1974  
1975 1975          if (llc->llc_state == DL_UNATTACHED)
1976 1976                  return (DL_OUTSTATE);
1977 1977  
1978 1978          macinfo = llc->llc_mac_info;
1979 1979          multi = (dl_enabmulti_req_t *)mp->b_rptr;
1980 1980          maddr = (struct ether_addr *)(multi + 1);
1981 1981  
1982 1982          if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
1983 1983              MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length)) {
1984 1984                  /* request appears to be valid */
1985 1985                  /* does this address appear in current table? */
1986 1986                  if (llc->llc_mcast != NULL) {
1987 1987                          for (i = 0; i < llc->llc_multicnt; i++)
1988 1988                                  if (((mcast = llc->llc_mcast[i]) != NULL) &&
1989 1989                                      mcast->llcm_refcnt &&
1990 1990                                      bcmp(mcast->llcm_addr,
1991 1991                                      maddr->ether_addr_octet, ETHERADDRL) == 0) {
1992 1992                                          llc1_send_disable_multi(macinfo,
1993 1993                                              mcast);
1994 1994                                          llc->llc_mcast[i] = NULL;
1995 1995                                          dlokack(q, mp, DL_DISABMULTI_REQ);
1996 1996                                          return (LLCE_OK);
1997 1997                                  }
1998 1998                          status = DL_NOTENAB;
1999 1999                  }
2000 2000          }
2001 2001          return (status);
2002 2002  }
2003 2003  
2004 2004  /*
2005 2005   * llc1_send_disable_multi(llc, macinfo, mcast) this function is used to
2006 2006   * disable a multicast address if the reference count goes to zero. The
2007 2007   * disable request will then be forwarded to the lower stream.
2008 2008   */
2009 2009  static void
2010 2010  llc1_send_disable_multi(llc_mac_info_t *macinfo, llc_mcast_t *mcast)
2011 2011  {
2012 2012          mblk_t *mp;
2013 2013          dl_disabmulti_req_t *dis;
2014 2014  
2015 2015          if (mcast == NULL) {
2016 2016                  return;
2017 2017          }
2018 2018          if (macinfo == NULL || macinfo->llcp_queue == NULL) {
2019 2019                  return;
2020 2020          }
2021 2021          if (--mcast->llcm_refcnt > 0)
2022 2022                  return;
2023 2023  
2024 2024          mp = allocb(sizeof (dl_disabmulti_req_t) + ETHERADDRL, BPRI_MED);
2025 2025          if (mp) {
2026 2026                  dis = (dl_disabmulti_req_t *)mp->b_rptr;
2027 2027                  mp->b_wptr =
2028 2028                      mp->b_rptr + sizeof (dl_disabmulti_req_t) + ETHERADDRL;
2029 2029                  dis->dl_primitive = DL_DISABMULTI_REQ;
2030 2030                  dis->dl_addr_offset = sizeof (dl_disabmulti_req_t);
2031 2031                  dis->dl_addr_length = ETHERADDRL;
2032 2032                  bcopy(mcast->llcm_addr,
2033 2033                      (mp->b_rptr + sizeof (dl_disabmulti_req_t)), ETHERADDRL);
2034 2034                  DB_TYPE(mp) = M_PROTO;
2035 2035                  putnext(WR(macinfo->llcp_queue), mp);
2036 2036          }
2037 2037  }
2038 2038  
2039 2039  /*
2040 2040   * llc1_findminor(device) searches the per device class list of STREAMS for
2041 2041   * the first minor number not used.  Note that we currently don't allocate
2042 2042   * minor 0.
2043 2043   */
2044 2044  
2045 2045  static minor_t
2046 2046  llc1_findminor(llc1dev_t *device)
2047 2047  {
2048 2048          llc1_t *next;
2049 2049          minor_t minor;
2050 2050  
2051 2051          ASSERT(device != NULL);
2052 2052          for (minor = 1; minor <= MAXMIN32; minor++) {
2053 2053                  for (next = device->llc1_str_next;
2054 2054                      next != NULL && next != (llc1_t *)&device->llc1_str_next;
2055 2055                      next = next->llc_next) {
2056 2056                          if (minor == next->llc_minor)
2057 2057                                  goto nextminor;
2058 2058                  }
2059 2059                  return (minor);
2060 2060  nextminor:
2061 2061                  /* don't need to do anything */
2062 2062                  ;
2063 2063          }
2064 2064          /*NOTREACHED*/
2065 2065          return (0);
2066 2066  }
2067 2067  
2068 2068  /*
2069 2069   * llc1_req_info(q) simply construct a DL_INFO_REQ to be sent to the lower
2070 2070   * stream this is used to populate the macinfo structure.
2071 2071   */
2072 2072  static int
2073 2073  llc1_req_info(queue_t *q)
2074 2074  {
2075 2075          dl_info_req_t *info;
2076 2076          mblk_t *mp;
2077 2077  
2078 2078          mp = allocb(DL_INFO_REQ_SIZE, BPRI_MED);
2079 2079          if (mp == NULL)
2080 2080                  return (-1);
2081 2081          DB_TYPE(mp) = M_PCPROTO;
2082 2082          info = (dl_info_req_t *)mp->b_rptr;
2083 2083          mp->b_wptr = mp->b_rptr + DL_INFO_REQ_SIZE;
2084 2084          info->dl_primitive = DL_INFO_REQ;
2085 2085          putnext(q, mp);
2086 2086          return (0);
2087 2087  }
2088 2088  
2089 2089  /*
2090 2090   * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode
2091 2091   */
2092 2092  static void
2093 2093  llc1_req_raw(llc_mac_info_t *macinfo)
2094 2094  {
2095 2095          mblk_t *mp;
2096 2096  
2097 2097          mp = mkiocb(DLIOCRAW);
2098 2098          if (mp == NULL)
2099 2099                  return;
2100 2100  
2101 2101          macinfo->llcp_iocid = ((struct iocblk *)mp->b_rptr)->ioc_id;
2102 2102  
2103 2103          putnext(macinfo->llcp_queue, mp);
2104 2104          macinfo->llcp_flags |= LLC1_RAW_WAIT;
2105 2105  }
2106 2106  
2107 2107  /*
2108 2108   * llc1_send_bindreq
2109 2109   * if lower stream isn't bound, bind it to something appropriate
2110 2110   */
2111 2111  static void
2112 2112  llc1_send_bindreq(llc_mac_info_t *macinfo)
2113 2113  {
2114 2114          mblk_t *mp;
2115 2115          dl_bind_req_t *bind;
2116 2116  
2117 2117          if (macinfo->llcp_sap >= 0xFF) {
2118 2118                  /* have to quite sometime if the world is failing */
2119 2119                  macinfo->llcp_sap &= ~(LLC1_BINDING|LLC1_AVAILABLE);
2120 2120                  return;
2121 2121          }
2122 2122  
2123 2123          mp = allocb(sizeof (dl_bind_req_t), BPRI_MED);
2124 2124          if (mp == NULL)
2125 2125                  return;
2126 2126  
2127 2127          bind = (dl_bind_req_t *)mp->b_rptr;
2128 2128          mp->b_wptr = mp->b_rptr + sizeof (dl_bind_req_t);
2129 2129  
2130 2130          bind->dl_primitive = DL_BIND_REQ;
2131 2131          bind->dl_sap = macinfo->llcp_sap += 2; /* starts at 2, inc by 2  */
2132 2132          macinfo->llcp_flags |= LLC1_BINDING;
2133 2133          bind->dl_max_conind = 0;
2134 2134          bind->dl_service_mode = DL_CLDLS;
2135 2135          bind->dl_conn_mgmt = 0;
2136 2136          bind->dl_xidtest_flg = 0;
2137 2137          putnext(macinfo->llcp_queue, mp);
2138 2138  }
2139 2139  
2140 2140  /*
2141 2141   * llc1_form_udata(lld, macinfo, mp) format a DL_UNITDATA_IND message to be
2142 2142   * sent to the user
2143 2143   */
2144 2144  static mblk_t *
2145 2145  llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2146 2146  {
2147 2147          mblk_t *udmp, *nmp;
2148 2148          dl_unitdata_ind_t *udata;
2149 2149          struct ether_header *hdr;
2150 2150          struct llchdr *llchdr;
2151 2151          struct snaphdr *snap;
2152 2152  
2153 2153          if (macinfo->llcp_flags & LLC1_USING_RAW) {
2154 2154                  hdr = (struct ether_header *)mp->b_rptr;
2155 2155                  llchdr = (struct llchdr *)(hdr + 1);
2156 2156  
2157 2157              /* allocate the DL_UNITDATA_IND M_PROTO header */
2158 2158                  udmp = allocb(sizeof (dl_unitdata_ind_t) +
2159 2159                      2 * (macinfo->llcp_addrlen + 5), BPRI_MED);
2160 2160                  if (udmp == NULL) {
2161 2161                  /* might as well discard since we can't go further */
2162 2162                  freemsg(mp);
2163 2163                  return (NULL);
2164 2164                  }
2165 2165                  udata = (dl_unitdata_ind_t *)udmp->b_rptr;
2166 2166                  udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2167 2167  
2168 2168                  nmp = dupmsg(mp);       /* make a copy for future streams */
2169 2169                  if (lld->llc_sap != LLC_NOVELL_SAP)
2170 2170                          mp->b_rptr += sizeof (struct ether_header) +
2171 2171                              sizeof (struct llchdr);
2172 2172                  else
2173 2173                          mp->b_rptr += sizeof (struct ether_header);
2174 2174  
2175 2175                  if (lld->llc_flags & LLC_SNAP) {
2176 2176                          mp->b_rptr += sizeof (struct snaphdr);
2177 2177                          snap = (struct snaphdr *)(llchdr + 1);
2178 2178                  }
2179 2179  
2180 2180                  /*
2181 2181                   * now setup the DL_UNITDATA_IND header
2182 2182                   */
2183 2183                  DB_TYPE(udmp) = M_PROTO;
2184 2184                  udata->dl_primitive = DL_UNITDATA_IND;
2185 2185                  udata->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2186 2186                  bcopy(hdr->ether_dhost.ether_addr_octet,
2187 2187                      LLCADDR(udata, udata->dl_dest_addr_offset)->llca_addr,
2188 2188                      macinfo->llcp_addrlen);
2189 2189  
2190 2190                  if (lld->llc_flags & LLC_SNAP) {
2191 2191                          udata->dl_dest_addr_length = macinfo->llcp_addrlen + 2;
2192 2192                          LLCSADDR(udata, udata->dl_dest_addr_offset)->llca_ssap =
2193 2193                              ntohs(*(ushort_t *)snap->snap_type);
2194 2194                  } else {
2195 2195                          udata->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2196 2196                          LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
2197 2197                              llchdr->llc_dsap;
2198 2198                  }
2199 2199                  udmp->b_wptr += udata->dl_dest_addr_length;
2200 2200                  udata->dl_src_addr_offset = udata->dl_dest_addr_length +
2201 2201                      udata->dl_dest_addr_offset;
2202 2202                  bcopy(hdr->ether_shost.ether_addr_octet,
2203 2203                      LLCADDR(udata, udata->dl_src_addr_offset)->llca_addr,
2204 2204                      macinfo->llcp_addrlen);
2205 2205                  if (lld->llc_flags & LLC_SNAP) {
2206 2206                          udata->dl_src_addr_length = macinfo->llcp_addrlen + 2;
2207 2207                          LLCSADDR(udata, udata->dl_src_addr_offset)->llca_ssap =
2208 2208                              ntohs(*(ushort_t *)snap->snap_type);
2209 2209                  } else {
2210 2210                          udata->dl_src_addr_length = macinfo->llcp_addrlen + 1;
2211 2211                          LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2212 2212                              llchdr->llc_ssap;
2213 2213                  }
2214 2214                  udata->dl_group_address = hdr->ether_dhost.ether_addr_octet[0] &
2215 2215                      0x1;
2216 2216                  udmp->b_wptr += udata->dl_src_addr_length;
2217 2217                  udmp->b_cont = mp;
2218 2218          } else {
2219 2219                  dl_unitdata_ind_t *ud2;
2220 2220                  if (mp->b_cont == NULL) {
2221 2221                  return (mp);    /* we can't do anything */
2222 2222                  }
2223 2223              /* if we end up here, we only want to patch the existing M_PROTO */
2224 2224                  nmp = dupmsg(mp);       /* make a copy for future streams */
2225 2225                  udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2226 2226                  udmp = allocb(MBLKL(mp) + 4, BPRI_MED);
2227 2227                  bcopy(mp->b_rptr, udmp->b_rptr, sizeof (dl_unitdata_ind_t));
2228 2228                  ud2 = (dl_unitdata_ind_t *)(udmp->b_rptr);
2229 2229                  udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2230 2230                  bcopy((caddr_t)mp->b_rptr + udata->dl_dest_addr_offset,
2231 2231                      udmp->b_wptr, macinfo->llcp_addrlen);
2232 2232                  ud2->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2233 2233                  ud2->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2234 2234                  udmp->b_wptr += ud2->dl_dest_addr_length;
2235 2235                  bcopy((caddr_t)udmp->b_rptr + udata->dl_src_addr_offset,
2236 2236                      udmp->b_wptr, macinfo->llcp_addrlen);
2237 2237                  ud2->dl_src_addr_length = ud2->dl_dest_addr_length;
2238 2238                  udmp->b_wptr += ud2->dl_src_addr_length;
2239 2239                  udmp->b_cont = mp->b_cont;
2240 2240                  if (lld->llc_sap != LLC_NOVELL_SAP)
2241 2241                          mp->b_cont->b_rptr += sizeof (struct llchdr);
2242 2242                  freeb(mp);
2243 2243  
2244 2244                  DB_TYPE(udmp) = M_PROTO;
2245 2245                  udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2246 2246                  llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
2247 2247                  LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
2248 2248                      llchdr->llc_dsap;
2249 2249                  LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2250 2250                      llchdr->llc_ssap;
2251 2251          }
2252 2252  #ifdef LLC1_DEBUG
2253 2253                  if (llc1_debug & LLCRECV)
2254 2254                  printf("llc1_recv: queued message to %x (%d)\n",
2255 2255                      lld->llc_qptr, lld->llc_minor);
2256 2256  #endif
2257 2257          /* enqueue for the service routine to process */
2258 2258          putnext(RD(lld->llc_qptr), udmp);
2259 2259          mp = nmp;
2260 2260          return (mp);
2261 2261  }
2262 2262  
2263 2263  /*
2264 2264   * llc1_xid_reply(macinfo, mp) automatic reply to an XID command
2265 2265   */
2266 2266  static mblk_t *
2267 2267  llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2268 2268  {
2269 2269          mblk_t *nmp, *rmp;
2270 2270          struct ether_header *hdr, *msgether;
2271 2271          struct llchdr *llchdr;
2272 2272          struct llchdr *msgllc;
2273 2273          struct llchdr_xid *xid;
2274 2274  
2275 2275          if (DB_TYPE(mp) == M_DATA) {
2276 2276                  hdr = (struct ether_header *)mp->b_rptr;
2277 2277                  llchdr = (struct llchdr *)(hdr + 1);
2278 2278          } else {
2279 2279                  if (mp->b_cont == NULL)
2280 2280                          return (mp);
2281 2281                  llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
2282 2282          }
2283 2283  
2284 2284          /* we only want to respond to commands to avoid response loops */
2285 2285          if (llchdr->llc_ssap & LLC_RESPONSE)
2286 2286                  return (mp);
2287 2287  
2288 2288          nmp = allocb(msgdsize(mp) + LLC_XID_INFO_SIZE, BPRI_MED);
2289 2289          if (nmp == NULL) {
2290 2290                  return (mp);
2291 2291          }
2292 2292  
2293 2293          /*
2294 2294           * now construct the XID reply frame
2295 2295           */
2296 2296          if (DB_TYPE(mp) == M_DATA) {
2297 2297                  msgether = (struct ether_header *)nmp->b_rptr;
2298 2298                  nmp->b_wptr += sizeof (struct ether_header);
2299 2299                  bcopy(hdr->ether_shost.ether_addr_octet,
2300 2300                      msgether->ether_dhost.ether_addr_octet,
2301 2301                      macinfo->llcp_addrlen);
2302 2302                  bcopy(macinfo->llcp_macaddr,
2303 2303                      msgether->ether_shost.ether_addr_octet,
2304 2304                      macinfo->llcp_addrlen);
2305 2305                  msgether->ether_type = htons(sizeof (struct llchdr_xid) +
2306 2306                      sizeof (struct llchdr));
2307 2307                  rmp = nmp;
2308 2308          } else {
2309 2309                  dl_unitdata_req_t *ud;
2310 2310                  dl_unitdata_ind_t *rud;
2311 2311                  rud = (dl_unitdata_ind_t *)mp->b_rptr;
2312 2312  
2313 2313                  rmp = allocb(sizeof (dl_unitdata_req_t) +
2314 2314                      macinfo->llcp_addrlen + 5, BPRI_MED);
2315 2315                  if (rmp == NULL)
2316 2316                          return (mp);
2317 2317  
2318 2318                  DB_TYPE(rmp) = M_PROTO;
2319 2319                  bzero(rmp->b_rptr, sizeof (dl_unitdata_req_t));
2320 2320                  ud = (dl_unitdata_req_t *)rmp->b_rptr;
2321 2321                  ud->dl_primitive = DL_UNITDATA_REQ;
2322 2322                  ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2323 2323                  ud->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2324 2324  
2325 2325                  rmp->b_wptr += sizeof (dl_unitdata_req_t);
2326 2326                  bcopy(LLCADDR(mp->b_rptr, rud->dl_src_addr_offset),
2327 2327                      LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset),
2328 2328                      macinfo->llcp_addrlen);
2329 2329                  LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset)->llca_sap =
2330 2330                      LLCADDR(mp->b_rptr, rud->dl_src_addr_offset)->llca_sap;
2331 2331                  rmp->b_wptr += sizeof (struct llcaddr);
2332 2332                  rmp->b_cont = nmp;
2333 2333          }
2334 2334  
2335 2335          msgllc = (struct llchdr *)nmp->b_wptr;
2336 2336          xid = (struct llchdr_xid *)(msgllc + 1);
2337 2337          nmp->b_wptr += sizeof (struct llchdr);
2338 2338  
2339 2339          msgllc->llc_dsap = llchdr->llc_ssap;
2340 2340  
2341 2341          /* mark it a response */
2342 2342          msgllc->llc_ssap = sap | LLC_RESPONSE;
2343 2343  
2344 2344          msgllc->llc_ctl = llchdr->llc_ctl;
2345 2345          xid->llcx_format = LLC_XID_FMTID;
2346 2346          xid->llcx_class = LLC_XID_TYPE_1;
2347 2347          xid->llcx_window = 0;   /* we don't have connections yet */
2348 2348  
2349 2349          nmp->b_wptr += sizeof (struct llchdr_xid);
2350 2350          macinfo->llcp_stats.llcs_xidxmt++;
2351 2351          putnext(WR(macinfo->llcp_queue), rmp);
2352 2352          return (mp);
2353 2353  }
2354 2354  
2355 2355  /*
2356 2356   * llc1_xid_ind_con(lld, macinfo, mp) form a DL_XID_IND or DL_XID_CON message
2357 2357   * to send to the user since it was requested that the user process these
2358 2358   * messages
2359 2359   */
2360 2360  static mblk_t *
2361 2361  llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2362 2362  {
2363 2363          mblk_t *nmp;
2364 2364          dl_xid_ind_t *xid;
2365 2365          struct ether_header *hdr;
2366 2366          struct llchdr *llchdr;
2367 2367          int raw;
2368 2368  
2369 2369          nmp = allocb(sizeof (dl_xid_ind_t) + 2 * (macinfo->llcp_addrlen + 1),
2370 2370              BPRI_MED);
2371 2371          if (nmp == NULL)
2372 2372                  return (mp);
2373 2373  
2374 2374          if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
2375 2375                  hdr = (struct ether_header *)mp->b_rptr;
2376 2376                  llchdr = (struct llchdr *)(hdr + 1);
2377 2377          } else {
2378 2378                  if (mp->b_rptr == NULL)
2379 2379                          return (mp);
2380 2380                  llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2381 2381          }
2382 2382  
2383 2383          xid = (dl_xid_ind_t *)nmp->b_rptr;
2384 2384          xid->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
2385 2385          xid->dl_dest_addr_offset = sizeof (dl_xid_ind_t);
2386 2386          xid->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2387 2387  
2388 2388          if (raw) {
2389 2389                  bcopy(hdr->ether_dhost.ether_addr_octet,
2390 2390                      (nmp->b_rptr + xid->dl_dest_addr_offset),
2391 2391                      xid->dl_dest_addr_length);
2392 2392          } else {
2393 2393                  dl_unitdata_ind_t *ind;
2394 2394                  ind = (dl_unitdata_ind_t *)mp->b_rptr;
2395 2395                  bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
2396 2396                      (nmp->b_rptr + xid->dl_dest_addr_offset),
2397 2397                      xid->dl_dest_addr_length);
2398 2398          }
2399 2399  
2400 2400          LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap =
2401 2401              llchdr->llc_dsap;
2402 2402  
2403 2403          xid->dl_src_addr_offset =
2404 2404              xid->dl_dest_addr_offset + xid->dl_dest_addr_length;
2405 2405          xid->dl_src_addr_length = xid->dl_dest_addr_length;
2406 2406  
2407 2407          if (raw) {
2408 2408                  bcopy(hdr->ether_shost.ether_addr_octet,
2409 2409                      (nmp->b_rptr + xid->dl_src_addr_offset),
2410 2410                      xid->dl_src_addr_length);
2411 2411          } else {
2412 2412                  dl_unitdata_ind_t *ind;
2413 2413                  ind = (dl_unitdata_ind_t *)mp->b_rptr;
2414 2414                  bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
2415 2415                      (nmp->b_rptr + xid->dl_src_addr_offset),
2416 2416                      ind->dl_src_addr_length);
2417 2417          }
2418 2418          LLCADDR(nmp->b_rptr, xid->dl_src_addr_offset)->llca_sap =
2419 2419              llchdr->llc_ssap & ~LLC_RESPONSE;
2420 2420  
2421 2421          nmp->b_wptr = nmp->b_rptr + sizeof (dl_xid_ind_t) +
2422 2422              2 * xid->dl_dest_addr_length;
2423 2423  
2424 2424          if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2425 2425                  xid->dl_primitive = DL_XID_IND;
2426 2426          } else {
2427 2427                  xid->dl_primitive = DL_XID_CON;
2428 2428          }
2429 2429  
2430 2430          DB_TYPE(nmp) = M_PROTO;
2431 2431          if (raw) {
2432 2432                  if (MBLKL(mp) >
2433 2433                      (sizeof (struct ether_header) + sizeof (struct llchdr))) {
2434 2434                          nmp->b_cont = dupmsg(mp);
2435 2435                          if (nmp->b_cont) {
2436 2436                                  nmp->b_cont->b_rptr +=
2437 2437                                          sizeof (struct ether_header) +
2438 2438                                          sizeof (struct llchdr);
2439 2439                          }
2440 2440                  }
2441 2441          } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
2442 2442                                                  sizeof (struct llchdr)) {
2443 2443                  nmp->b_cont = dupmsg(mp->b_cont);
2444 2444                  (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
2445 2445          }
2446 2446          putnext(RD(lld->llc_qptr), nmp);
2447 2447          return (mp);
2448 2448  }
2449 2449  
2450 2450  /*
2451 2451   * llc1_xid_req_res(q, mp, req_or_res) the user wants to send an XID message
2452 2452   * or response construct a proper message and put on the net
2453 2453   */
2454 2454  static int
2455 2455  llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res)
2456 2456  {
2457 2457          dl_xid_req_t *xid = (dl_xid_req_t *)mp->b_rptr;
2458 2458          llc1_t *llc = (llc1_t *)q->q_ptr;
2459 2459          llc_mac_info_t *macinfo;
2460 2460          mblk_t *nmp, *rmp;
2461 2461          struct ether_header *hdr;
2462 2462          struct llchdr *llchdr;
2463 2463  
2464 2464          if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2465 2465                  return (DL_OUTSTATE);
2466 2466  
2467 2467          if (llc->llc_sap == LLC_NOVELL_SAP)
2468 2468                  return (DL_NOTSUPPORTED);
2469 2469  
2470 2470          if (llc->llc_flags & DL_AUTO_XID)
2471 2471                  return (DL_XIDAUTO);
2472 2472  
2473 2473          macinfo = llc->llc_mac_info;
2474 2474          if (MBLKL(mp) < sizeof (dl_xid_req_t) ||
2475 2475              !MBLKIN(mp, xid->dl_dest_addr_offset, xid->dl_dest_addr_length)) {
2476 2476                  return (DL_BADPRIM);
2477 2477          }
2478 2478  
2479 2479          nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr) +
2480 2480              sizeof (struct llchdr_xid), BPRI_MED);
2481 2481  
2482 2482          if (nmp == NULL)
2483 2483                  return (LLCE_NOBUFFER);
2484 2484  
2485 2485          if (macinfo->llcp_flags & LLC1_USING_RAW) {
2486 2486                  hdr = (struct ether_header *)nmp->b_rptr;
2487 2487                  bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
2488 2488                      hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
2489 2489                  bcopy(macinfo->llcp_macaddr,
2490 2490                      hdr->ether_shost.ether_addr_octet, ETHERADDRL);
2491 2491                  hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
2492 2492                  nmp->b_wptr = nmp->b_rptr +
2493 2493                      sizeof (struct ether_header) + sizeof (struct llchdr);
2494 2494                  llchdr = (struct llchdr *)(hdr + 1);
2495 2495                  rmp = nmp;
2496 2496          } else {
2497 2497                  dl_unitdata_req_t *ud;
2498 2498                  rmp = allocb(sizeof (dl_unitdata_req_t) +
2499 2499                      (macinfo->llcp_addrlen + 2), BPRI_MED);
2500 2500                  if (rmp == NULL) {
2501 2501                          freemsg(nmp);
2502 2502                          return (LLCE_NOBUFFER);
2503 2503                  }
2504 2504                  ud = (dl_unitdata_req_t *)rmp->b_rptr;
2505 2505                  DB_TYPE(rmp) = M_PROTO;
2506 2506                  ud->dl_primitive = DL_UNITDATA_REQ;
2507 2507                  ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2508 2508                  ud->dl_dest_addr_length = xid->dl_dest_addr_length;
2509 2509                  rmp->b_wptr += sizeof (dl_unitdata_req_t);
2510 2510                  bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
2511 2511                      LLCADDR(ud, ud->dl_dest_addr_offset),
2512 2512                      xid->dl_dest_addr_length);
2513 2513                  LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2514 2514                      msgdsize(mp);
2515 2515                  rmp->b_wptr += xid->dl_dest_addr_length;
2516 2516                  rmp->b_cont = nmp;
2517 2517                  llchdr = (struct llchdr *)nmp->b_rptr;
2518 2518                  nmp->b_wptr += sizeof (struct llchdr);
2519 2519          }
2520 2520  
2521 2521          llchdr->llc_dsap = LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap;
2522 2522          llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
2523 2523          llchdr->llc_ctl =
2524 2524              LLC_XID | ((xid->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
2525 2525  
2526 2526          nmp->b_cont = mp->b_cont;
2527 2527          mp->b_cont = NULL;
2528 2528          freeb(mp);
2529 2529          macinfo->llcp_stats.llcs_xidxmt++;
2530 2530          putnext(WR(macinfo->llcp_queue), rmp);
2531 2531          return (LLCE_OK);
2532 2532  }
2533 2533  
2534 2534  /*
2535 2535   * llc1_test_reply(macinfo, mp)
2536 2536   * automatic reply to a TEST message
2537 2537   */
2538 2538  static mblk_t *
2539 2539  llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2540 2540  {
2541 2541          mblk_t *nmp;
2542 2542          struct ether_header *hdr, *msgether;
2543 2543          struct llchdr *llchdr;
2544 2544          struct llchdr *msgllc;
2545 2545          int poll_final;
2546 2546  
2547 2547          if (DB_TYPE(mp) == M_PROTO) {
2548 2548                  if (mp->b_cont == NULL)
2549 2549                          return (mp);
2550 2550                  llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2551 2551                  hdr = NULL;
2552 2552          } else {
2553 2553                  hdr = (struct ether_header *)mp->b_rptr;
2554 2554                  llchdr = (struct llchdr *)(hdr + 1);
2555 2555          }
2556 2556  
2557 2557          /* we only want to respond to commands to avoid response loops */
2558 2558          if (llchdr->llc_ssap & LLC_RESPONSE)
2559 2559                  return (mp);
2560 2560  
2561 2561          nmp = copymsg(mp);      /* so info field is duplicated */
2562 2562          if (nmp == NULL) {
2563 2563                  nmp = mp;
2564 2564                  mp = NULL;
2565 2565          }
2566 2566          /*
2567 2567           * now construct the TEST reply frame
2568 2568           */
2569 2569  
2570 2570  
2571 2571          poll_final = llchdr->llc_ctl & LLC_P;
2572 2572  
2573 2573          if (DB_TYPE(nmp) == M_PROTO) {
2574 2574                  dl_unitdata_req_t *udr = (dl_unitdata_req_t *)nmp->b_rptr;
2575 2575                  dl_unitdata_ind_t *udi = (dl_unitdata_ind_t *)nmp->b_rptr;
2576 2576  
2577 2577                  /* make into a request */
2578 2578                  udr->dl_primitive = DL_UNITDATA_REQ;
2579 2579                  udr->dl_dest_addr_offset = udi->dl_src_addr_offset;
2580 2580                  udr->dl_dest_addr_length = udi->dl_src_addr_length;
2581 2581                  udr->dl_priority.dl_min = udr->dl_priority.dl_max = 0;
2582 2582                  msgllc = (struct llchdr *)nmp->b_cont->b_rptr;
2583 2583          } else {
2584 2584                  msgether = (struct ether_header *)nmp->b_rptr;
2585 2585                  bcopy(hdr->ether_shost.ether_addr_octet,
2586 2586                      msgether->ether_dhost.ether_addr_octet,
2587 2587                      macinfo->llcp_addrlen);
2588 2588                  bcopy(macinfo->llcp_macaddr,
2589 2589                      msgether->ether_shost.ether_addr_octet,
2590 2590                      macinfo->llcp_addrlen);
2591 2591                  msgllc = (struct llchdr *)(msgether+1);
2592 2592          }
2593 2593  
2594 2594          msgllc->llc_dsap = llchdr->llc_ssap;
2595 2595  
2596 2596          /* mark it as a response */
2597 2597          msgllc->llc_ssap = sap |  LLC_RESPONSE;
2598 2598          msgllc->llc_ctl = LLC_TEST | poll_final;
2599 2599  
2600 2600          macinfo->llcp_stats.llcs_testxmt++;
2601 2601          putnext(WR(macinfo->llcp_queue), nmp);
2602 2602          return (mp);
2603 2603  }
2604 2604  
2605 2605  /*
2606 2606   * llc1_test_ind_con(lld, macinfo, mp) form a DL_TEST_IND or DL_TEST_CON
2607 2607   * message to send to the user since it was requested that the user process
2608 2608   * these messages
2609 2609   */
2610 2610  static mblk_t *
2611 2611  llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2612 2612  {
2613 2613          mblk_t *nmp;
2614 2614          dl_test_ind_t *test;
2615 2615          struct ether_header *hdr;
2616 2616          struct llchdr *llchdr;
2617 2617          int raw;
2618 2618  
2619 2619          nmp = allocb(sizeof (dl_test_ind_t) + 2 * (ETHERADDRL + 1), BPRI_MED);
2620 2620          if (nmp == NULL)
2621 2621                  return (NULL);
2622 2622  
2623 2623          if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
2624 2624                  hdr = (struct ether_header *)mp->b_rptr;
2625 2625                  llchdr = (struct llchdr *)(hdr + 1);
2626 2626          } else {
2627 2627                  if (mp->b_rptr == NULL)
2628 2628                          return (mp);
2629 2629                  llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2630 2630          }
2631 2631  
2632 2632          test = (dl_test_ind_t *)nmp->b_rptr;
2633 2633          test->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
2634 2634          test->dl_dest_addr_offset = sizeof (dl_test_ind_t);
2635 2635          test->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2636 2636  
2637 2637          if (raw) {
2638 2638                  bcopy(hdr->ether_dhost.ether_addr_octet,
2639 2639                      LLCADDR(nmp->b_rptr, test->dl_dest_addr_offset)->llca_addr,
2640 2640                      test->dl_dest_addr_length);
2641 2641          } else {
2642 2642                  dl_unitdata_ind_t *ind;
2643 2643                  ind = (dl_unitdata_ind_t *)mp->b_rptr;
2644 2644                  bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
2645 2645                      (nmp->b_rptr + test->dl_dest_addr_offset),
2646 2646                      test->dl_dest_addr_length);
2647 2647          }
2648 2648  
2649 2649          LLCADDR(test, test->dl_dest_addr_offset)->llca_sap =
2650 2650              llchdr->llc_dsap;
2651 2651  
2652 2652          test->dl_src_addr_offset = test->dl_dest_addr_offset +
2653 2653              test->dl_dest_addr_length;
2654 2654          test->dl_src_addr_length = test->dl_dest_addr_length;
2655 2655  
2656 2656          if (raw) {
2657 2657                  bcopy(hdr->ether_shost.ether_addr_octet,
2658 2658                      LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_addr,
2659 2659                      test->dl_src_addr_length);
2660 2660          } else {
2661 2661                  dl_unitdata_ind_t *ind;
2662 2662                  ind = (dl_unitdata_ind_t *)mp->b_rptr;
2663 2663                  bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
2664 2664                      (nmp->b_rptr + test->dl_src_addr_offset),
2665 2665                      ind->dl_src_addr_length);
2666 2666          }
2667 2667          LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_sap =
2668 2668              llchdr->llc_ssap & ~LLC_RESPONSE;
2669 2669  
2670 2670          nmp->b_wptr = nmp->b_rptr + sizeof (dl_test_ind_t) +
2671 2671              2 * test->dl_dest_addr_length;
2672 2672  
2673 2673          if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2674 2674                  test->dl_primitive = DL_TEST_IND;
2675 2675          } else {
2676 2676                  test->dl_primitive = DL_TEST_CON;
2677 2677          }
2678 2678  
2679 2679          DB_TYPE(nmp) = M_PROTO;
2680 2680          if (raw) {
2681 2681                  if (MBLKL(mp) >
2682 2682                      (sizeof (struct ether_header) + sizeof (struct llchdr))) {
2683 2683                          nmp->b_cont = dupmsg(mp);
2684 2684                          if (nmp->b_cont) {
2685 2685                                  nmp->b_cont->b_rptr +=
2686 2686                                          sizeof (struct ether_header) +
2687 2687                                          sizeof (struct llchdr);
2688 2688                          }
2689 2689                  }
2690 2690          } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
2691 2691                                          sizeof (struct llchdr)) {
2692 2692                  nmp->b_cont = dupmsg(mp->b_cont);
2693 2693                  (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
2694 2694          }
2695 2695          putnext(RD(lld->llc_qptr), nmp);
2696 2696          return (mp);
2697 2697  }
2698 2698  
2699 2699  /*
2700 2700   * llc1_test_req_res(q, mp, req_or_res) the user wants to send a TEST
2701 2701   * message or response construct a proper message and put on the net
2702 2702   */
2703 2703  static int
2704 2704  llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res)
2705 2705  {
2706 2706          dl_test_req_t *test = (dl_test_req_t *)mp->b_rptr;
2707 2707          llc1_t *llc = (llc1_t *)q->q_ptr;
2708 2708          llc_mac_info_t *macinfo;
2709 2709          mblk_t *nmp, *rmp;
2710 2710          struct ether_header *hdr;
2711 2711          struct llchdr *llchdr;
2712 2712  
2713 2713          if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2714 2714                  return (DL_OUTSTATE);
2715 2715  
2716 2716          if (llc->llc_sap == LLC_NOVELL_SAP)
2717 2717                  return (DL_NOTSUPPORTED);
2718 2718  
2719 2719          if (llc->llc_flags & DL_AUTO_TEST)
2720 2720                  return (DL_TESTAUTO);
2721 2721  
2722 2722          macinfo = llc->llc_mac_info;
2723 2723          if (MBLKL(mp) < sizeof (dl_test_req_t) ||
2724 2724              !MBLKIN(mp, test->dl_dest_addr_offset,
2725 2725              test->dl_dest_addr_length)) {
2726 2726                  return (DL_BADPRIM);
2727 2727          }
2728 2728  
2729 2729          nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr),
2730 2730              BPRI_MED);
2731 2731  
2732 2732          if (nmp == NULL)
2733 2733                  return (LLCE_NOBUFFER);
2734 2734  
2735 2735          if (macinfo->llcp_flags & LLC1_USING_RAW) {
2736 2736                  hdr = (struct ether_header *)nmp->b_rptr;
2737 2737                  bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
2738 2738                      hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
2739 2739                  bcopy(macinfo->llcp_macaddr,
2740 2740                      hdr->ether_shost.ether_addr_octet, ETHERADDRL);
2741 2741                  hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
2742 2742                  nmp->b_wptr = nmp->b_rptr +
2743 2743                      sizeof (struct ether_header) + sizeof (struct llchdr);
2744 2744                  llchdr = (struct llchdr *)(hdr + 1);
2745 2745                  rmp = nmp;
2746 2746          } else {
2747 2747                  dl_unitdata_req_t *ud;
2748 2748  
2749 2749                  rmp = allocb(sizeof (dl_unitdata_req_t) +
2750 2750                      (macinfo->llcp_addrlen + 2), BPRI_MED);
2751 2751                  if (rmp == NULL) {
2752 2752                          freemsg(nmp);
2753 2753                          return (LLCE_NOBUFFER);
2754 2754  
2755 2755                  }
2756 2756                  ud = (dl_unitdata_req_t *)rmp->b_rptr;
2757 2757                  DB_TYPE(rmp) = M_PROTO;
2758 2758                  ud->dl_primitive = DL_UNITDATA_REQ;
2759 2759                  ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2760 2760                  ud->dl_dest_addr_length = test->dl_dest_addr_length;
2761 2761                  rmp->b_wptr += sizeof (dl_unitdata_req_t);
2762 2762                  bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
2763 2763                      LLCADDR(ud, ud->dl_dest_addr_offset),
2764 2764                      test->dl_dest_addr_length);
2765 2765                  LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2766 2766                      msgdsize(mp);
2767 2767                  rmp->b_wptr += test->dl_dest_addr_length;
2768 2768                  rmp->b_cont = nmp;
2769 2769                  llchdr = (struct llchdr *)nmp->b_rptr;
2770 2770                  nmp->b_wptr += sizeof (struct llchdr);
2771 2771          }
2772 2772  
2773 2773          llchdr->llc_dsap = LLCADDR(test, test->dl_dest_addr_offset)->llca_sap;
2774 2774          llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
2775 2775          llchdr->llc_ctl =
2776 2776              LLC_TEST | ((test->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
2777 2777  
2778 2778          nmp->b_cont = mp->b_cont;
2779 2779          mp->b_cont = NULL;
2780 2780          freeb(mp);
2781 2781          macinfo->llcp_stats.llcs_testxmt++;
2782 2782          putnext(WR(macinfo->llcp_queue), rmp);
2783 2783          return (LLCE_OK);
2784 2784  }
2785 2785  
2786 2786  /*
2787 2787   * llc1_find_waiting(macinfo, mp, prim) look for a stream waiting for a
2788 2788   * response to a message identified by prim and send it to the user.
2789 2789   */
2790 2790  static void
2791 2791  llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim)
2792 2792  {
2793 2793          llc1_t *llc;
2794 2794  
2795 2795          for (llc = llc1_device_list.llc1_str_next;
2796 2796              llc != (llc1_t *)&llc1_device_list.llc1_str_next;
2797 2797              llc = llc->llc_next)
2798 2798                  if (llc->llc_mac_info == macinfo &&
2799 2799                      prim == llc->llc_waiting_for) {
2800 2800                          putnext(RD(llc->llc_qptr), mp);
2801 2801                          llc->llc_waiting_for = -1;
2802 2802                          return;
2803 2803                  }
2804 2804          freemsg(mp);
2805 2805  }
2806 2806  
2807 2807  static void
2808 2808  llc1insque(void *elem, void *pred)
2809 2809  {
2810 2810          struct qelem *pelem = elem;
2811 2811          struct qelem *ppred = pred;
2812 2812          struct qelem *pnext = ppred->q_forw;
2813 2813  
2814 2814          pelem->q_forw = pnext;
2815 2815          pelem->q_back = ppred;
2816 2816          ppred->q_forw = pelem;
2817 2817          pnext->q_back = pelem;
2818 2818  }
2819 2819  
2820 2820  static void
2821 2821  llc1remque(void *arg)
2822 2822  {
2823 2823          struct qelem *pelem = arg;
2824 2824          struct qelem *elem = arg;
2825 2825  
2826 2826          ASSERT(pelem->q_forw != NULL);
2827 2827          pelem->q_forw->q_back = pelem->q_back;
2828 2828          pelem->q_back->q_forw = pelem->q_forw;
2829 2829          elem->q_back = elem->q_forw = NULL;
2830 2830  }
2831 2831  
2832 2832  /* VARARGS */
2833 2833  static void
2834 2834  llc1error(dip, fmt, a1, a2, a3, a4, a5, a6)
2835 2835          dev_info_t *dip;
2836 2836          char   *fmt, *a1, *a2, *a3, *a4, *a5, *a6;
2837 2837  {
2838 2838          static long last;
2839 2839          static char *lastfmt;
2840 2840          time_t now;
2841 2841  
2842 2842          /*
2843 2843           * Don't print same error message too often.
2844 2844           */
2845 2845          now = gethrestime_sec();
2846 2846          if ((last == (now & ~1)) && (lastfmt == fmt))
2847 2847                  return;
2848 2848          last = now & ~1;
2849 2849          lastfmt = fmt;
2850 2850  
2851 2851          cmn_err(CE_CONT, "%s%d:  ",
2852 2852                  ddi_get_name(dip), ddi_get_instance(dip));
2853 2853          cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5, a6);
2854 2854          cmn_err(CE_CONT, "\n");
2855 2855  }
2856 2856  
2857 2857  /*ARGSUSED1*/
2858 2858  static int
2859 2859  llc1_update_kstat(kstat_t *ksp, int rw)
2860 2860  {
2861 2861          llc_mac_info_t *macinfo;
2862 2862          kstat_named_t *kstat;
2863 2863          struct llc_stats *stats;
2864 2864  
2865 2865          if (ksp == NULL)
2866 2866                  return (0);
2867 2867  
2868 2868          kstat = (kstat_named_t *)(ksp->ks_data);
2869 2869          macinfo = (llc_mac_info_t *)(ksp->ks_private);
2870 2870          stats = &macinfo->llcp_stats;
2871 2871  
2872 2872          kstat[LLCS_NOBUFFER].value.ul = stats->llcs_nobuffer;
2873 2873          kstat[LLCS_MULTIXMT].value.ul = stats->llcs_multixmt;
2874 2874          kstat[LLCS_MULTIRCV].value.ul = stats->llcs_multircv;
2875 2875          kstat[LLCS_BRDCSTXMT].value.ul = stats->llcs_brdcstxmt;
2876 2876          kstat[LLCS_BRDCSTRCV].value.ul = stats->llcs_brdcstrcv;
2877 2877          kstat[LLCS_BLOCKED].value.ul = stats->llcs_blocked;
2878 2878          kstat[LLCS_PKTXMT].value.ul = stats->llcs_pktxmt;
2879 2879          kstat[LLCS_PKTRCV].value.ul = stats->llcs_pktrcv;
2880 2880          kstat[LLCS_BYTEXMT].value.ul = stats->llcs_bytexmt;
2881 2881          kstat[LLCS_BYTERCV].value.ul = stats->llcs_bytercv;
2882 2882          kstat[LLCS_XIDXMT].value.ul = stats->llcs_xidxmt;
2883 2883          kstat[LLCS_XIDRCV].value.ul = stats->llcs_xidrcv;
2884 2884          kstat[LLCS_TESTXMT].value.ul = stats->llcs_testxmt;
2885 2885          kstat[LLCS_TESTRCV].value.ul = stats->llcs_testrcv;
2886 2886          kstat[LLCS_IERRORS].value.ul = stats->llcs_ierrors;
2887 2887          kstat[LLCS_OERRORS].value.ul = stats->llcs_oerrors;
2888 2888          return (0);
2889 2889  }
2890 2890  
2891 2891  static void
2892 2892  llc1_init_kstat(llc_mac_info_t *macinfo)
2893 2893  {
2894 2894          kstat_named_t *ksp;
2895 2895  
2896 2896          /*
2897 2897           * Note that the temporary macinfo->llcp_ppa number is negative.
2898 2898           */
2899 2899          macinfo->llcp_kstatp = kstat_create("llc", (-macinfo->llcp_ppa - 1),
2900 2900              NULL, "net", KSTAT_TYPE_NAMED,
2901 2901              sizeof (struct llc_stats) / sizeof (long), 0);
2902 2902          if (macinfo->llcp_kstatp == NULL)
2903 2903                  return;
2904 2904  
2905 2905          macinfo->llcp_kstatp->ks_update = llc1_update_kstat;
2906 2906          macinfo->llcp_kstatp->ks_private = (void *)macinfo;
2907 2907  
2908 2908          ksp = (kstat_named_t *)(macinfo->llcp_kstatp->ks_data);
2909 2909  
2910 2910          kstat_named_init(&ksp[LLCS_NOBUFFER], "nobuffer", KSTAT_DATA_ULONG);
2911 2911          kstat_named_init(&ksp[LLCS_MULTIXMT], "multixmt", KSTAT_DATA_ULONG);
2912 2912          kstat_named_init(&ksp[LLCS_MULTIRCV], "multircv", KSTAT_DATA_ULONG);
2913 2913          kstat_named_init(&ksp[LLCS_BRDCSTXMT], "brdcstxmt", KSTAT_DATA_ULONG);
2914 2914          kstat_named_init(&ksp[LLCS_BRDCSTRCV], "brdcstrcv", KSTAT_DATA_ULONG);
2915 2915          kstat_named_init(&ksp[LLCS_BLOCKED], "blocked", KSTAT_DATA_ULONG);
2916 2916          kstat_named_init(&ksp[LLCS_PKTXMT], "pktxmt", KSTAT_DATA_ULONG);
2917 2917          kstat_named_init(&ksp[LLCS_PKTRCV], "pktrcv", KSTAT_DATA_ULONG);
2918 2918          kstat_named_init(&ksp[LLCS_BYTEXMT], "bytexmt", KSTAT_DATA_ULONG);
2919 2919          kstat_named_init(&ksp[LLCS_BYTERCV], "bytercv", KSTAT_DATA_ULONG);
2920 2920          kstat_named_init(&ksp[LLCS_XIDXMT], "xidxmt", KSTAT_DATA_ULONG);
2921 2921          kstat_named_init(&ksp[LLCS_XIDRCV], "xidrcv", KSTAT_DATA_ULONG);
2922 2922          kstat_named_init(&ksp[LLCS_TESTXMT], "testxmt", KSTAT_DATA_ULONG);
2923 2923          kstat_named_init(&ksp[LLCS_TESTRCV], "testrcv", KSTAT_DATA_ULONG);
2924 2924          kstat_named_init(&ksp[LLCS_IERRORS], "ierrors", KSTAT_DATA_ULONG);
2925 2925          kstat_named_init(&ksp[LLCS_OERRORS], "oerrors", KSTAT_DATA_ULONG);
2926 2926          kstat_install(macinfo->llcp_kstatp);
2927 2927  }
2928 2928  
2929 2929  static void
2930 2930  llc1_uninit_kstat(llc_mac_info_t *macinfo)
2931 2931  {
2932 2932          if (macinfo->llcp_kstatp) {
2933 2933                  kstat_delete(macinfo->llcp_kstatp);
2934 2934                  macinfo->llcp_kstatp = NULL;
2935 2935          }
2936 2936  }
2937 2937  
2938 2938  /*
2939 2939   * llc1_subs_bind(q, mp)
2940 2940   *      implements the DL_SUBS_BIND_REQ primitive
2941 2941   *      this only works for a STREAM bound to LLC_SNAP_SAP
2942 2942   *      or one bound to the automatic SNAP mode.
2943 2943   *      If bound to LLC_SNAP_SAP, the subs bind can be:
2944 2944   *      - 2 octets treated as a native byte order short (ethertype)
2945 2945   *      - 3 octets treated as a network order byte string (OID part)
2946 2946   *      - 5 octets treated as a network order byte string (full SNAP header)
2947 2947   *      If bound to an automatic SNAP mode sap, then only the 3 octet
2948 2948   *      form is allowed
2949 2949   */
2950 2950  static int
2951 2951  llc1_subs_bind(queue_t *q, mblk_t *mp)
2952 2952  {
2953 2953          llc1_t *lld = (llc1_t *)q->q_ptr;
2954 2954          dl_subs_bind_req_t *subs = (dl_subs_bind_req_t *)mp->b_rptr;
2955 2955          ushort_t subssap;
2956 2956          uchar_t *sapstr;
2957 2957          int result;
2958 2958  
2959 2959  
2960 2960  #if defined(LLC1_DEBUG)
2961 2961          if (llc1_debug & (LLCTRACE|LLCPROT)) {
2962 2962                          printf("llc1_subs_bind (%x, %x)\n", q, mp);
2963 2963          }
2964 2964  #endif
2965 2965  
2966 2966          if (lld == NULL || lld->llc_state != DL_IDLE) {
2967 2967                  result = DL_OUTSTATE;
2968 2968          } else if (lld->llc_sap != LLC_SNAP_SAP ||
2969 2969              subs->dl_subs_bind_class != DL_HIERARCHICAL_BIND) {
2970 2970                  /* we only want to support this for SNAP at present */
2971 2971                  result = DL_UNSUPPORTED;
2972 2972          } else {
2973 2973  
2974 2974                  lld->llc_state = DL_SUBS_BIND_PND;
2975 2975  
2976 2976                  sapstr = (uchar_t *)(mp->b_rptr + subs->dl_subs_sap_offset);
2977 2977  
2978 2978                  result = LLCE_OK;
2979 2979                  switch (subs->dl_subs_sap_length) {
2980 2980                  case 2:         /* just the ethertype part */
2981 2981                          if (lld->llc_flags & LLC_SNAP) {
2982 2982                                  result = DL_BADADDR;
2983 2983                                  break;
2984 2984                          }
2985 2985                          ((uchar_t *)&subssap)[0] = sapstr[0];
2986 2986                          ((uchar_t *)&subssap)[1] = sapstr[1];
2987 2987                          subssap = htons(subssap);
2988 2988                          lld->llc_snap[3] = ((uchar_t *)&subssap)[0];
2989 2989                          lld->llc_snap[4] = ((uchar_t *)&subssap)[1];
2990 2990                          lld->llc_flags |= LLC_SNAP;
2991 2991                          break;
2992 2992  
2993 2993                  case 3:         /* just the OID part */
2994 2994                          if ((lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) ==
2995 2995                              (LLC_SNAP|LLC_SNAP_OID)) {
2996 2996                                  result = DL_BADADDR;
2997 2997                                  break;
2998 2998                          }
2999 2999                          bcopy(sapstr, lld->llc_snap, 3);
3000 3000                          lld->llc_flags |= LLC_SNAP_OID;
3001 3001                          break;
3002 3002  
3003 3003                  case 5:         /* full SNAP header */
3004 3004                          if (lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) {
3005 3005                                  result = DL_BADADDR;
3006 3006                                  break;
3007 3007                          }
3008 3008                          bcopy(sapstr, lld->llc_snap, 5);
3009 3009                          lld->llc_flags |= LLC_SNAP|LLC_SNAP_OID;
3010 3010                          break;
3011 3011                  }
3012 3012                  /* if successful, acknowledge and enter the proper state */
3013 3013                  if (result == LLCE_OK) {
3014 3014                          mblk_t *nmp = mp;
3015 3015                          dl_subs_bind_ack_t *ack;
3016 3016  
3017 3017                          if (DB_REF(mp) != 1 ||
3018 3018                              MBLKL(mp) < (sizeof (dl_subs_bind_ack_t) + 5)) {
3019 3019                                  freemsg(mp);
3020 3020                                  nmp = allocb(sizeof (dl_subs_bind_ack_t) + 5,
3021 3021                                      BPRI_MED);
3022 3022                          }
3023 3023                          ack = (dl_subs_bind_ack_t *)nmp->b_rptr;
3024 3024                          nmp->b_wptr = nmp->b_rptr +
3025 3025                              sizeof (dl_subs_bind_ack_t) + 5;
3026 3026                          ack->dl_primitive = DL_SUBS_BIND_ACK;
3027 3027                          ack->dl_subs_sap_offset = sizeof (dl_subs_bind_ack_t);
3028 3028                          ack->dl_subs_sap_length = 5;
3029 3029                          bcopy(lld->llc_snap,
3030 3030                              (caddr_t)nmp->b_rptr + ack->dl_subs_sap_offset + 5,
3031 3031                              5);
3032 3032                          DB_TYPE(nmp) = M_PCPROTO;
3033 3033                          qreply(q, nmp);
3034 3034  
3035 3035                  }
3036 3036                  lld->llc_state = DL_IDLE;
3037 3037          }
3038 3038          return (result);
3039 3039  }
3040 3040  
3041 3041  /*
3042 3042   *
3043 3043   */
3044 3044  static int
3045 3045  llc1_subs_unbind(void)
3046 3046  {
3047 3047          return (DL_UNSUPPORTED);
3048 3048  }
3049 3049  
3050 3050  char *
3051 3051  snapdmp(uchar_t *bstr)
3052 3052  {
3053 3053          static char buff[32];
3054 3054  
3055 3055          (void) sprintf(buff, "%x.%x.%x.%x.%x",
3056 3056              bstr[0],
3057 3057              bstr[1],
3058 3058              bstr[2],
3059 3059              bstr[3],
3060 3060              bstr[4]);
3061 3061          return (buff);
3062 3062  }
3063 3063  
3064 3064  static int
3065 3065  llc1_snap_match(llc1_t *lld, struct snaphdr *snap)
3066 3066  {
3067 3067          return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0);
3068 3068  }
  
    | 
      ↓ open down ↓ | 
    2862 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX