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