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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  22  * Use is subject to license terms.
  23  */
  24 
  25 #pragma ident   "%Z%%M% %I%     %E% SMI"
  26 
  27 /*
  28  * gld - Generic LAN Driver
  29  * media dependent routines
  30  */
  31 
  32 #include <sys/types.h>
  33 #include <sys/errno.h>
  34 #include <sys/stropts.h>
  35 #include <sys/stream.h>
  36 #include <sys/kmem.h>
  37 #include <sys/stat.h>
  38 #include <sys/modctl.h>
  39 #include <sys/kstat.h>
  40 #include <sys/debug.h>
  41 
  42 #include <sys/byteorder.h>
  43 #include <sys/strsun.h>
  44 #include <sys/dlpi.h>
  45 #include <sys/ethernet.h>
  46 #include <sys/multidata.h>
  47 #include <sys/gld.h>
  48 #include <sys/gldpriv.h>
  49 #include <sys/ddi.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/sysmacros.h>
  52 #include <sys/ib/clients/ibd/ibd.h>
  53 #include <sys/pattr.h>
  54 
  55 #define DLSAPLENGTH(macinfo) \
  56         ((macinfo)->gldm_addrlen + ABS((macinfo)->gldm_saplen))
  57 
  58 #ifdef GLD_DEBUG
  59 extern int gld_debug;
  60 #endif
  61 
  62 extern void gld_bitrevcopy(caddr_t src, caddr_t target, size_t n);
  63 extern char *gld_macaddr_sprintf(char *, unsigned char *, int);
  64 extern gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
  65 extern uint32_t gld_global_options;
  66 
  67 static struct   llc_snap_hdr llc_snap_def = {
  68         LSAP_SNAP,              /* DLSAP 0xaa */
  69         LSAP_SNAP,              /* SLSAP 0xaa */
  70         CNTL_LLC_UI,            /* Control 0x03 */
  71         0x00, 0x00, 0x00,       /* Org[3] */
  72         0x00                    /* Type */
  73 };
  74 
  75 #define ISETHERTYPE(snaphdr) \
  76         (snaphdr->d_lsap == LSAP_SNAP && \
  77         snaphdr->s_lsap == LSAP_SNAP && \
  78         snaphdr->control == CNTL_LLC_UI && \
  79         snaphdr->org[0] == 0 && \
  80         snaphdr->org[1] == 0 && \
  81         snaphdr->org[2] == 0)
  82 
  83 /* ======== */
  84 /* Ethernet */
  85 /* ======== */
  86 
  87 static mac_addr_t ether_broadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  88 
  89 void
  90 gld_init_ether(gld_mac_info_t *macinfo)
  91 {
  92         struct gldkstats *sp =
  93             ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
  94 
  95         /* Assumptions we make for this medium */
  96         ASSERT(macinfo->gldm_type == DL_ETHER);
  97         ASSERT(macinfo->gldm_addrlen == 6);
  98         ASSERT(macinfo->gldm_saplen == -2);
  99 #ifndef lint
 100         ASSERT(sizeof (struct ether_header) == 14);
 101         ASSERT(sizeof (mac_addr_t) == 6);
 102 #endif
 103 
 104         kstat_named_init(&sp->glds_frame, "align_errors", KSTAT_DATA_ULONG);
 105         kstat_named_init(&sp->glds_crc, "fcs_errors", KSTAT_DATA_ULONG);
 106         kstat_named_init(&sp->glds_collisions, "collisions", KSTAT_DATA_ULONG);
 107         kstat_named_init(&sp->glds_nocarrier, "carrier_errors",
 108             KSTAT_DATA_ULONG);
 109         kstat_named_init(&sp->glds_defer, "defer_xmts", KSTAT_DATA_ULONG);
 110         kstat_named_init(&sp->glds_xmtlatecoll, "tx_late_collisions",
 111                                         KSTAT_DATA_ULONG);
 112         kstat_named_init(&sp->glds_short, "runt_errors", KSTAT_DATA_ULONG);
 113         kstat_named_init(&sp->glds_excoll, "ex_collisions", KSTAT_DATA_ULONG);
 114 
 115         /*
 116          * only initialize the new statistics if the driver
 117          * knows about them.
 118          */
 119         if (macinfo->gldm_driver_version != GLD_VERSION_200)
 120                 return;
 121 
 122         kstat_named_init(&sp->glds_dot3_first_coll,
 123             "first_collisions", KSTAT_DATA_UINT32);
 124         kstat_named_init(&sp->glds_dot3_multi_coll,
 125             "multi_collisions", KSTAT_DATA_UINT32);
 126         kstat_named_init(&sp->glds_dot3_sqe_error,
 127             "sqe_errors", KSTAT_DATA_UINT32);
 128         kstat_named_init(&sp->glds_dot3_mac_xmt_error,
 129             "macxmt_errors", KSTAT_DATA_UINT32);
 130         kstat_named_init(&sp->glds_dot3_mac_rcv_error,
 131             "macrcv_errors", KSTAT_DATA_UINT32);
 132         kstat_named_init(&sp->glds_dot3_frame_too_long,
 133             "toolong_errors", KSTAT_DATA_UINT32);
 134         kstat_named_init(&sp->glds_duplex, "duplex", KSTAT_DATA_CHAR);
 135 }
 136 
 137 /*ARGSUSED*/
 138 void
 139 gld_uninit_ether(gld_mac_info_t *macinfo)
 140 {
 141 }
 142 
 143 int
 144 gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
 145     packet_flag_t flags)
 146 {
 147         struct ether_header *mh;
 148         gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
 149         struct llc_snap_hdr *snaphdr;
 150         mblk_t *pmp = NULL, *savemp = mp;
 151         unsigned short typelen;
 152         int ret = 0;
 153 
 154         /*
 155          * Quickly handle receive fastpath for IPQ hack.
 156          */
 157         if (flags == GLD_RXQUICK) {
 158                 pktinfo->pktLen = msgdsize(mp);
 159                 /*
 160                  * Check whether the header is contiguous, which
 161                  * also implicitly makes sure the packet is big enough.
 162                  */
 163                 if (MBLKL(mp) < sizeof (struct ether_header))
 164                         return (-1);
 165                 mh = (struct ether_header *)mp->b_rptr;
 166                 pktinfo->ethertype = REF_NET_USHORT(mh->ether_type);
 167                 pktinfo->isForMe = mac_eq(&mh->ether_dhost,
 168                     mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
 169                 pktinfo->macLen = sizeof (struct ether_header);
 170 
 171                 return (0);
 172         }
 173 
 174         bzero((void *)pktinfo, sizeof (*pktinfo));
 175 
 176         pktinfo->pktLen = msgdsize(mp);
 177 
 178         /* make sure packet has at least a whole mac header */
 179         if (pktinfo->pktLen < sizeof (struct ether_header))
 180                 return (-1);
 181 
 182         /* make sure the mac header falls into contiguous memory */
 183         if (MBLKL(mp) < sizeof (struct ether_header)) {
 184                 if ((pmp = msgpullup(mp, -1)) == NULL) {
 185 #ifdef GLD_DEBUG
 186                         if (gld_debug & GLDERRS)
 187                                 cmn_err(CE_WARN,
 188                                     "GLD: interpret_ether cannot msgpullup");
 189 #endif
 190                         return (-1);
 191                 }
 192                 mp = pmp;       /* this mblk contains the whole mac header */
 193         }
 194 
 195         mh = (struct ether_header *)mp->b_rptr;
 196 
 197         /* Check to see if the mac is a broadcast or multicast address. */
 198         if (mac_eq(&mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen))
 199                 pktinfo->isBroadcast = 1;
 200         else if (mh->ether_dhost.ether_addr_octet[0] & 1)
 201                 pktinfo->isMulticast = 1;
 202 
 203         typelen = REF_NET_USHORT(mh->ether_type);
 204         /*
 205          * If the hardware is capable of VLAN tag insertion
 206          * strip out the VLAN tag info. Knowing hardware is
 207          * capable of VLAN can be established by the presance
 208          * of non null 'macinfo->gldm_send_tagged'.
 209          */
 210         if (flags == GLD_TX) {
 211                 if ((typelen == ETHERTYPE_VLAN) &&
 212                     (macinfo->gldm_send_tagged != NULL)) {
 213                         struct ether_vlan_header *evhp;
 214                         uint16_t tci;
 215 
 216                         if ((MBLKL(mp) < sizeof (struct ether_vlan_header)) &&
 217                             (pullupmsg(mp, sizeof (struct ether_vlan_header))
 218                             == 0)) {
 219                                 ret = -1;
 220                                 goto out;
 221                         }
 222                         evhp = (struct ether_vlan_header *)mp->b_rptr;
 223                         tci = REF_NET_USHORT(evhp->ether_tci);
 224 
 225                         /*
 226                          * We don't allow the VID and priority are both zero.
 227                          */
 228                         if ((GLD_VTAG_PRI((int32_t)tci) == 0 &&
 229                             GLD_VTAG_VID((int32_t)tci) == VLAN_VID_NONE) ||
 230                             (GLD_VTAG_CFI((uint32_t)tci)) != VLAN_CFI_ETHER) {
 231                                 ret = -1;
 232                                 goto out;
 233                         }
 234 
 235                         /*
 236                          * Remember the VTAG info in order to reinsert it,
 237                          * Then strip the tag. This is required because some
 238                          * drivers do not allow the size of message (passed
 239                          * by the gldm_send_tagged() function) to be greater
 240                          * than ETHERMAX.
 241                          */
 242                         GLD_SAVE_MBLK_VTAG(savemp, GLD_TCI2VTAG(tci));
 243                         ovbcopy(mp->b_rptr, mp->b_rptr + VTAG_SIZE,
 244                             2 * ETHERADDRL);
 245                         mp->b_rptr += VTAG_SIZE;
 246                 }
 247                 goto out;       /* Got all info we need for xmit case */
 248         }
 249 
 250         ASSERT(GLDM_LOCK_HELD(macinfo));
 251 
 252         /*
 253          * Deal with the mac header
 254          */
 255 
 256         mac_copy(&mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
 257         mac_copy(&mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen);
 258 
 259         pktinfo->isLooped = mac_eq(pktinfo->shost,
 260             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
 261         pktinfo->isForMe = mac_eq(pktinfo->dhost,
 262             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
 263 
 264         pktinfo->macLen = sizeof (struct ether_header);
 265 
 266         if (typelen > ETHERMTU) {
 267                 pktinfo->ethertype = typelen; /* use type interpretation */
 268                 goto out;
 269         }
 270 
 271         /*
 272          * Packet is 802.3 so the ether type/length field
 273          * specifies the number of bytes that should be present
 274          * in the data field.  Additional bytes are padding, and
 275          * should be removed
 276          */
 277         {
 278         int delta = pktinfo->pktLen -
 279             (sizeof (struct ether_header) + typelen);
 280 
 281         if (delta > 0 && adjmsg(mp, -delta))
 282                 pktinfo->pktLen -= delta;
 283         }
 284 
 285         /*
 286          * Before trying to look beyond the MAC header, make sure the LLC
 287          * header exists, and that both it and any SNAP header are contiguous.
 288          */
 289         if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
 290                 goto out;       /* LLC hdr should have been there! */
 291 
 292         pktinfo->isLLC = 1;
 293 
 294         if (gld_global_options & GLD_OPT_NO_ETHRXSNAP ||
 295             pktinfo->pktLen <  pktinfo->macLen + LLC_SNAP_HDR_LEN)
 296                 goto out;
 297 
 298         if (MBLKL(mp) < sizeof (struct ether_header) + LLC_SNAP_HDR_LEN &&
 299             MBLKL(mp) < pktinfo->pktLen) {
 300                 /*
 301                  * we don't have the entire packet within the first mblk (and
 302                  * therefore we didn't do the msgpullup above), AND the first
 303                  * mblk may not contain all the data we need to look at.
 304                  */
 305                 ASSERT(pmp == NULL);    /* couldn't have done msgpullup above */
 306                 if ((pmp = msgpullup(mp, -1)) == NULL) {
 307 #ifdef GLD_DEBUG
 308                         if (gld_debug & GLDERRS)
 309                                 cmn_err(CE_WARN,
 310                                     "GLD: interpret_ether cannot msgpullup2");
 311 #endif
 312                         goto out;       /* can't interpret this pkt further */
 313                 }
 314                 mp = pmp;       /* this mblk should contain everything needed */
 315         }
 316 
 317         /*
 318          * Check SAP/SNAP information for EtherType.
 319          */
 320 
 321         snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
 322         if (ISETHERTYPE(snaphdr)) {
 323                 pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
 324                 pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
 325         }
 326 out:
 327         if (pmp != NULL)
 328                 freemsg(pmp);
 329 
 330         return (ret);
 331 }
 332 
 333 mblk_t *
 334 gld_unitdata_ether(gld_t *gld, mblk_t *mp)
 335 {
 336         gld_mac_info_t *macinfo = gld->gld_mac_info;
 337         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
 338         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
 339         mac_addr_t dhost;
 340         unsigned short typelen;
 341         mblk_t *nmp;
 342         struct ether_header *mh;
 343         int hdrlen;
 344         uint32_t vptag;
 345         gld_vlan_t *gld_vlan;
 346 
 347         ASSERT(macinfo);
 348 
 349         /* extract needed info from the mblk before we maybe reuse it */
 350         mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
 351 
 352         /* look in the unitdata request for a sap, else use bound one */
 353         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
 354             REF_HOST_USHORT(gldp->glda_sap) != 0)
 355                 typelen = REF_HOST_USHORT(gldp->glda_sap);
 356         else
 357                 typelen = gld->gld_sap;
 358 
 359         /*
 360          * We take values less than or equal to ETHERMTU to mean that the
 361          * packet should not have an encoded EtherType and so we use the
 362          * IEEE 802.3 length interpretation of the type/length field.
 363          */
 364         if (typelen <= ETHERMTU)
 365                 typelen = msgdsize(mp);
 366 
 367         hdrlen = sizeof (struct ether_header);
 368 
 369         /*
 370          * Check to see if VLAN is enabled on this stream
 371          * if so then make the header bigger to hold a clone
 372          * vlan tag.
 373          */
 374         gld_vlan = (gld_vlan_t *)gld->gld_vlan;
 375         if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
 376                 hdrlen += VTAG_SIZE;
 377                 vptag = gld_vlan->gldv_ptag;
 378         }
 379 
 380         /* need a buffer big enough for the headers */
 381         nmp = mp->b_cont;    /* where the packet payload M_DATA is */
 382         if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
 383                 /* it fits at the beginning of the first M_DATA block */
 384                 freeb(mp);      /* don't need the M_PROTO anymore */
 385         } else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
 386                 /* we can reuse the dl_unitdata_req M_PROTO mblk */
 387                 nmp = mp;
 388                 DB_TYPE(nmp) = M_DATA;
 389                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 390         } else {
 391                 /* we need to allocate one */
 392                 if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
 393                         return (NULL);
 394                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 395                 linkb(nmp, mp->b_cont);
 396                 freeb(mp);
 397         }
 398 
 399         /* Got the space, now copy in the header components */
 400 
 401         nmp->b_rptr -= sizeof (typelen);
 402         SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
 403         if (hdrlen > sizeof (struct ether_header)) {
 404                 nmp->b_rptr -= sizeof (uint16_t);
 405                 SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
 406                 vptag >>= 16;
 407                 nmp->b_rptr -= sizeof (uint16_t);
 408                 SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
 409         }
 410         nmp->b_rptr -= (ETHERADDRL * 2);
 411         mh = (struct ether_header *)nmp->b_rptr;
 412         mac_copy(dhost, &mh->ether_dhost, macinfo->gldm_addrlen);
 413 
 414         /*
 415          * We access the mac address without the mutex to prevent
 416          * mutex contention (BUG 4211361)
 417          */
 418         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
 419             &mh->ether_shost, macinfo->gldm_addrlen);
 420 
 421         return (nmp);
 422 }
 423 
 424 /*
 425  * Insert the VLAN tag into the packet. The packet now is an Ethernet header
 426  * without VLAN tag information.
 427  */
 428 mblk_t *
 429 gld_insert_vtag_ether(mblk_t *mp, uint32_t vtag)
 430 {
 431         struct ether_vlan_header *evhp;
 432         struct ether_header *ehp;
 433         mblk_t *nmp;
 434 
 435         if (vtag == VLAN_VID_NONE)
 436                 return (mp);
 437 
 438         if (DB_REF(mp) == 1 && MBLKHEAD(mp) >= VTAG_SIZE) {
 439                 /* it fits at the beginning of the message block */
 440                 nmp = mp;
 441                 ovbcopy(nmp->b_rptr, nmp->b_rptr - VTAG_SIZE, 2 * ETHERADDRL);
 442                 nmp->b_rptr -= VTAG_SIZE;
 443                 evhp = (struct ether_vlan_header *)nmp->b_rptr;
 444         } else {
 445                 /* we need to allocate one */
 446                 if ((nmp = allocb(sizeof (struct ether_vlan_header),
 447                     BPRI_MED)) == NULL) {
 448                         return (NULL);
 449                 }
 450                 nmp->b_wptr += sizeof (struct ether_vlan_header);
 451 
 452                 /* transfer the ether_header fields */
 453                 evhp = (struct ether_vlan_header *)nmp->b_rptr;
 454                 ehp = (struct ether_header *)mp->b_rptr;
 455                 mac_copy(&ehp->ether_dhost, &evhp->ether_dhost, ETHERADDRL);
 456                 mac_copy(&ehp->ether_shost, &evhp->ether_shost, ETHERADDRL);
 457                 bcopy(&ehp->ether_type, &evhp->ether_type, sizeof (uint16_t));
 458 
 459                 /* offset the mp of the MAC header length. */
 460                 mp->b_rptr += sizeof (struct ether_header);
 461                 if (MBLKL(mp) == 0) {
 462                         nmp->b_cont = mp->b_cont;
 463                         freeb(mp);
 464                 } else {
 465                         nmp->b_cont = mp;
 466                 }
 467         }
 468 
 469         SET_NET_USHORT(evhp->ether_tci, vtag);
 470         vtag >>= 16;
 471         SET_NET_USHORT(evhp->ether_tpid, vtag);
 472         return (nmp);
 473 }
 474 
 475 mblk_t *
 476 gld_fastpath_ether(gld_t *gld, mblk_t *mp)
 477 {
 478         gld_mac_info_t *macinfo = gld->gld_mac_info;
 479         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
 480         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
 481         unsigned short typelen;
 482         mblk_t *nmp;
 483         struct ether_header *mh;
 484         int hdrlen;
 485         uint32_t vptag;
 486         gld_vlan_t *gld_vlan;
 487 
 488         ASSERT(macinfo);
 489 
 490         /* look in the unitdata request for a sap, else use bound one */
 491         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
 492             REF_HOST_USHORT(gldp->glda_sap) != 0)
 493                 typelen = REF_HOST_USHORT(gldp->glda_sap);
 494         else
 495                 typelen = gld->gld_sap;
 496 
 497         /*
 498          * We only do fast-path for EtherType encoding because this is the only
 499          * case where the media header will be consistent from packet to packet.
 500          */
 501         if (typelen <= ETHERMTU)
 502                 return (NULL);
 503 
 504         /*
 505          * Initialize the fast path header to include the
 506          * basic source address information and type field.
 507          */
 508         hdrlen = sizeof (struct ether_header);
 509 
 510         /*
 511          * Check to see if VLAN is enabled on this stream
 512          * if so then make the header bigger to hold a clone
 513          * vlan tag.
 514          */
 515         gld_vlan = (gld_vlan_t *)gld->gld_vlan;
 516         if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
 517                 hdrlen += VTAG_SIZE;
 518                 vptag = gld_vlan->gldv_ptag;
 519         }
 520 
 521         if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
 522                 return (NULL);
 523 
 524         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 525 
 526         /* Got the space, now copy in the header components */
 527 
 528         nmp->b_rptr -= sizeof (typelen);
 529         SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
 530 
 531         /*
 532          * If the header is for a VLAN stream, then add
 533          * in the VLAN tag to the clone header.
 534          */
 535         if (hdrlen > sizeof (struct ether_header)) {
 536                 nmp->b_rptr -= sizeof (uint16_t);
 537                 SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
 538                 vptag >>= 16;
 539                 nmp->b_rptr -= sizeof (uint16_t);
 540                 SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
 541         }
 542         nmp->b_rptr -= (ETHERADDRL * 2);
 543         mh = (struct ether_header *)nmp->b_rptr;
 544         mac_copy(gldp->glda_addr, &mh->ether_dhost, macinfo->gldm_addrlen);
 545 
 546         GLDM_LOCK(macinfo, RW_WRITER);
 547         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
 548             &mh->ether_shost, macinfo->gldm_addrlen);
 549         GLDM_UNLOCK(macinfo);
 550 
 551         return (nmp);
 552 }
 553 
 554 /* == */
 555 /* IB */
 556 /* == */
 557 
 558 void
 559 gld_init_ib(gld_mac_info_t *macinfo)
 560 {
 561         /*
 562          * Currently, the generic stats maintained by GLD is
 563          * sufficient for IPoIB.
 564          */
 565 
 566         /* Assumptions we make for this medium */
 567         ASSERT(macinfo->gldm_type == DL_IB);
 568         ASSERT(macinfo->gldm_addrlen == IPOIB_ADDRL);
 569         ASSERT(macinfo->gldm_saplen == -2);
 570 }
 571 
 572 /* ARGSUSED */
 573 void
 574 gld_uninit_ib(gld_mac_info_t *macinfo)
 575 {
 576 }
 577 
 578 /*
 579  * The packet format sent to the driver is:
 580  * IPOIB_ADDRL bytes dest addr :: 2b sap :: 2b 0s :: data
 581  * The packet format received from the driver is:
 582  * IPOIB_GRH_SIZE bytes pseudo GRH :: 2b sap :: 2b 0s :: data.
 583  */
 584 int
 585 gld_interpret_ib(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
 586     packet_flag_t flags)
 587 {
 588         ipoib_pgrh_t *grh;
 589         ipoib_ptxhdr_t *gldp;
 590         mblk_t *pmp = NULL;
 591         gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
 592 
 593         /*
 594          * Quickly handle receive fastpath for IPQ hack.
 595          */
 596         if (flags == GLD_RXQUICK) {
 597                 pktinfo->pktLen = msgdsize(mp) - IPOIB_GRH_SIZE;
 598 
 599                 /*
 600                  * Check whether the header is contiguous, which
 601                  * also implicitly makes sure the packet is big enough.
 602                  */
 603                 if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
 604                         return (-1);
 605 
 606                 /*
 607                  * Almost all times, unicast will not have
 608                  * a valid pgrh; quickly identify and ask for
 609                  * IPQ hack optimization only in that case.
 610                  */
 611                 grh = (ipoib_pgrh_t *)mp->b_rptr;
 612                 if (grh->ipoib_vertcflow == 0) {
 613                         struct ipoib_header *ihp = (struct ipoib_header *)
 614                             (mp->b_rptr + IPOIB_GRH_SIZE);
 615 
 616                         pktinfo->isForMe = 1;
 617                         pktinfo->ethertype = REF_NET_USHORT(ihp->ipoib_type);
 618                         pktinfo->macLen = IPOIB_GRH_SIZE + IPOIB_HDRSIZE;
 619                         return (0);
 620                 } else {
 621                         return (-1);
 622                 }
 623         }
 624 
 625         /*
 626          * Handle the GLD_TX, GLD_RX, GLD_RXLOOP cases now.
 627          */
 628         ASSERT(flags != GLD_RXQUICK);
 629         bzero((void *)pktinfo, sizeof (*pktinfo));
 630 
 631         if (flags != GLD_RX) {
 632                 /*
 633                  * GLD_TX and GLD_RXLOOP cases.
 634                  */
 635                 gldp = (ipoib_ptxhdr_t *)mp->b_rptr;
 636                 pktinfo->pktLen = msgdsize(mp);
 637 
 638                 /* make sure packet has at least a pseudo header */
 639                 if (pktinfo->pktLen < sizeof (ipoib_ptxhdr_t))
 640                         return (-1);
 641 
 642                 /* make sure the mac header falls into contiguous memory */
 643                 if (MBLKL(mp) < sizeof (ipoib_ptxhdr_t)) {
 644                         if ((pmp = msgpullup(mp, -1)) == NULL) {
 645 #ifdef GLD_DEBUG
 646                                 if (gld_debug & GLDERRS)
 647                                         cmn_err(CE_WARN,
 648                                             "GLD: interpret_ib "
 649                                             "cannot msgpullup");
 650 #endif
 651                                 return (-1);
 652                         }
 653                         /* this mblk contains the whole mac header */
 654                         mp = pmp;
 655                 }
 656 
 657                 /*
 658                  * Check if mac is broadcast or multicast address; all these
 659                  * types of address have the top 4 bytes as 0x00FFFFFF.
 660                  */
 661                 if (mac_eq(&gldp->ipoib_dest, macinfo->gldm_broadcast_addr,
 662                     sizeof (uint32_t))) {
 663                         if (mac_eq(&gldp->ipoib_dest,
 664                             macinfo->gldm_broadcast_addr, IPOIB_ADDRL))
 665                                 pktinfo->isBroadcast = 1;
 666                         else
 667                                 pktinfo->isMulticast = 1;
 668                 }
 669 
 670                 /*
 671                  * Only count bytes we will be sending over the wire
 672                  * or looping back.
 673                  */
 674                 pktinfo->pktLen -= IPOIB_ADDRL;
 675                 if (flags == GLD_TX)
 676                         goto out;       /* Got all info we need for xmit case */
 677 
 678                 /*
 679                  * Loopback case: this is a dup'ed message.
 680                  */
 681                 mp->b_rptr += IPOIB_ADDRL;
 682                 mac_copy(&gldp->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
 683                 mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
 684         } else {
 685                 /*
 686                  * GLD_RX case; process packet sent from driver.
 687                  */
 688                 ipoib_mac_t *mact, *tact;
 689                 ib_qpn_t dqpn;
 690 
 691                 pktinfo->pktLen = msgdsize(mp);
 692                 /* make sure packet has at least pgrh and mac header */
 693                 if (pktinfo->pktLen < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
 694                         return (-1);
 695 
 696                 /* make sure the header falls into contiguous memory */
 697                 if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE)) {
 698                         if ((pmp = msgpullup(mp, -1)) == NULL) {
 699 #ifdef GLD_DEBUG
 700                                 if (gld_debug & GLDERRS)
 701                                         cmn_err(CE_WARN,
 702                                             "GLD: interpret_ib "
 703                                             "cannot msgpullup2");
 704 #endif
 705                                 return (-1);
 706                         }
 707                         /* this mblk contains the whole mac header */
 708                         mp = pmp;
 709                 }
 710 
 711                 grh = (ipoib_pgrh_t *)mp->b_rptr;
 712                 mp->b_rptr += IPOIB_GRH_SIZE;
 713                 pktinfo->pktLen -= IPOIB_GRH_SIZE;
 714                 if (grh->ipoib_vertcflow) {
 715                         /*
 716                          * First, copy source address from grh.
 717                          */
 718                         mact = (ipoib_mac_t *)pktinfo->shost;
 719                         mac_copy(&grh->ipoib_sqpn, &mact->ipoib_qpn,
 720                             IPOIB_ADDRL);
 721 
 722                         /*
 723                          * Then copy destination address from grh;
 724                          * first, the 16 bytes of GID.
 725                          */
 726                         mact = (ipoib_mac_t *)pktinfo->dhost;
 727                         mac_copy(&grh->ipoib_dgid_pref,
 728                             &mact->ipoib_gidpref, IPOIB_ADDRL -
 729                             sizeof (mact->ipoib_qpn));
 730                         tact = (ipoib_mac_t *)mac_pvt->curr_macaddr;
 731 
 732                         /* Is this a multicast address */
 733                         if (*(uchar_t *)(grh->ipoib_dgid_pref) == 0xFF) {
 734                                 /*
 735                                  * Only check for hardware looping in
 736                                  * multicast case. It is assumed higher
 737                                  * layer code (IP) will stop unicast loops;
 738                                  * ie will prevent a transmit to self.
 739                                  */
 740                                 if (bcmp(&grh->ipoib_sqpn, tact,
 741                                     IPOIB_ADDRL) == 0)
 742                                         pktinfo->isLooped = 1;
 743 
 744                                 tact = (ipoib_mac_t *)macinfo->
 745                                     gldm_broadcast_addr;
 746                                 if (mac_eq(tact->ipoib_gidpref,
 747                                     grh->ipoib_dgid_pref,
 748                                     IPOIB_ADDRL - sizeof (tact->ipoib_qpn)))
 749                                         pktinfo->isBroadcast = 1;
 750                                 else
 751                                         pktinfo->isMulticast = 1;
 752                                 /*
 753                                  * Now copy the 4 bytes QPN part of the
 754                                  * destination address.
 755                                  */
 756                                 dqpn = htonl(IB_MC_QPN);
 757                                 mac_copy(&dqpn, &mact->ipoib_qpn,
 758                                     sizeof (mact->ipoib_qpn));
 759                         } else {
 760                                 /*
 761                                  * Now copy the 4 bytes QPN part of the
 762                                  * destination address.
 763                                  */
 764                                 mac_copy(&tact->ipoib_qpn, &mact->ipoib_qpn,
 765                                     sizeof (mact->ipoib_qpn));
 766                                 /*
 767                                  * Any unicast packets received on IBA are
 768                                  * for the node.
 769                                  */
 770                                 pktinfo->isForMe = 1;
 771                         }
 772                 } else {
 773                         /*
 774                          * It can not be a IBA multicast packet.
 775                          * Must have been unicast to us. We do not
 776                          * have shost information, which is used in
 777                          * gld_addudind(); IP/ARP does not care.
 778                          */
 779                         pktinfo->nosource = 1;
 780                         mac_copy(mac_pvt->curr_macaddr, pktinfo->dhost,
 781                             IPOIB_ADDRL);
 782                         /*
 783                          * Any unicast packets received on IBA are
 784                          * for the node.
 785                          */
 786                         pktinfo->isForMe = 1;
 787                 }
 788         }
 789 
 790         ASSERT((flags == GLD_RX) || (flags == GLD_RXLOOP));
 791         ASSERT(GLDM_LOCK_HELD(macinfo));
 792         pktinfo->ethertype = REF_NET_USHORT(((ipoib_hdr_t *)
 793             (mp->b_rptr))->ipoib_type);
 794         pktinfo->macLen = IPOIB_HDRSIZE;
 795 
 796 out:
 797         if (pmp != NULL)
 798                 freemsg(pmp);
 799 
 800         return (0);
 801 }
 802 
 803 /*
 804  * The packet format sent to the driver is: 2b sap :: 2b 0s :: data
 805  */
 806 void
 807 gld_interpret_mdt_ib(gld_mac_info_t *macinfo, mblk_t *mp, pdescinfo_t *pinfo,
 808     pktinfo_t *pktinfo, mdt_packet_flag_t flags)
 809 {
 810         gld_mac_pvt_t *mac_pvt;
 811         multidata_t *dlmdp;
 812         pattrinfo_t attr_info = { PATTR_DSTADDRSAP, };
 813         pattr_t *patr;
 814         ipoib_ptxhdr_t *dlap = NULL;
 815 
 816         /*
 817          * Per packet formatting.
 818          */
 819         if (flags == GLD_MDT_TXPKT) {
 820                 ipoib_hdr_t *hptr;
 821                 uint_t seg;
 822 
 823                 if (PDESC_HDRL(pinfo) == 0)
 824                         return;
 825 
 826                 /*
 827                  * Update packet's link header.
 828                  */
 829                 pinfo->hdr_rptr -= IPOIB_HDRSIZE;
 830                 hptr = (ipoib_hdr_t *)pinfo->hdr_rptr;
 831                 hptr->ipoib_mbz = htons(0);
 832                 hptr->ipoib_type = pktinfo->ethertype;
 833 
 834                 /*
 835                  * Total #bytes that will be put on wire.
 836                  */
 837                 pktinfo->pktLen = PDESC_HDRL(pinfo);
 838                 for (seg = 0; seg < pinfo->pld_cnt; seg++)
 839                         pktinfo->pktLen += PDESC_PLDL(pinfo, seg);
 840 
 841                 return;
 842         }
 843 
 844         /*
 845          * The following two cases of GLD_MDT_TX and GLD_MDT_RXLOOP are per
 846          * MDT message processing.
 847          */
 848         dlmdp = mmd_getmultidata(mp);
 849         patr = mmd_getpattr(dlmdp, NULL, &attr_info);
 850         ASSERT(patr != NULL);
 851         ASSERT(macinfo->gldm_saplen == -2);
 852         if (patr != NULL)
 853                 dlap = (ipoib_ptxhdr_t *)((pattr_addr_t *)attr_info.buf)->addr;
 854 
 855         if (flags == GLD_MDT_TX) {
 856                 bzero((void *)pktinfo, sizeof (*pktinfo));
 857                 if (dlap == NULL)
 858                         return;
 859 
 860                 /*
 861                  * Check if mac is broadcast or multicast address; all these
 862                  * types of address have the top 4 bytes as 0x00FFFFFF.
 863                  */
 864                 if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
 865                     sizeof (uint32_t))) {
 866                         if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
 867                             IPOIB_ADDRL))
 868                                 pktinfo->isBroadcast = 1;
 869                         else
 870                                 pktinfo->isMulticast = 1;
 871                 }
 872                 pktinfo->ethertype = REF_NET_USHORT(dlap->
 873                     ipoib_rhdr.ipoib_type);
 874         } else {
 875                 ASSERT(flags == GLD_MDT_RXLOOP);
 876                 pktinfo->macLen = IPOIB_HDRSIZE;
 877                 mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
 878                 mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
 879                 if (dlap == NULL)
 880                         return;
 881                 mac_copy(&dlap->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
 882         }
 883 }
 884 
 885 mblk_t *
 886 gld_unitdata_ib(gld_t *gld, mblk_t *mp)
 887 {
 888         gld_mac_info_t *macinfo = gld->gld_mac_info;
 889         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
 890         ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
 891         ipoib_mac_t dhost;
 892         unsigned short type;
 893         mblk_t *nmp;
 894         int hdrlen;
 895 
 896         ASSERT(macinfo != NULL);
 897 
 898         /* extract needed info from the mblk before we maybe reuse it */
 899         mac_copy(&gldp->ipoib_dest, &dhost, IPOIB_ADDRL);
 900 
 901         /* look in the unitdata request for a sap, else use bound one */
 902         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
 903             REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
 904                 type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
 905         else
 906                 type = gld->gld_sap;
 907 
 908         hdrlen = sizeof (ipoib_ptxhdr_t);
 909 
 910         /* need a buffer big enough for the headers */
 911         nmp = mp->b_cont;    /* where the packet payload M_DATA is */
 912         if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
 913                 /* it fits at the beginning of the first M_DATA block */
 914                 freeb(mp);      /* don't need the M_PROTO anymore */
 915         } else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
 916                 /* we can reuse the dl_unitdata_req M_PROTO mblk */
 917                 nmp = mp;
 918                 DB_TYPE(nmp) = M_DATA;
 919                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 920         } else {
 921                 /* we need to allocate one */
 922                 if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
 923                         return (NULL);
 924                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 925                 linkb(nmp, mp->b_cont);
 926                 freeb(mp);
 927         }
 928 
 929         /* Got the space, now copy in the header components */
 930 
 931         nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
 932         gldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
 933         SET_NET_USHORT(gldp->ipoib_rhdr.ipoib_type, type);
 934         gldp->ipoib_rhdr.ipoib_mbz = 0;
 935         mac_copy(&dhost, &gldp->ipoib_dest, IPOIB_ADDRL);
 936 
 937         return (nmp);
 938 }
 939 
 940 mblk_t *
 941 gld_fastpath_ib(gld_t *gld, mblk_t *mp)
 942 {
 943         gld_mac_info_t *macinfo = gld->gld_mac_info;
 944         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
 945         ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
 946         unsigned short type;
 947         mblk_t *nmp;
 948         ipoib_ptxhdr_t *tgldp;
 949         int hdrlen;
 950 
 951         ASSERT(macinfo != NULL);
 952 
 953         /* look in the unitdata request for a sap, else use bound one */
 954         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
 955             REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
 956                 type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
 957         else
 958                 type = gld->gld_sap;
 959 
 960         hdrlen = sizeof (ipoib_ptxhdr_t);
 961 
 962         if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
 963                 return (NULL);
 964 
 965         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
 966 
 967         /* Got the space, now copy in the header components */
 968 
 969         nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
 970         tgldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
 971         tgldp->ipoib_rhdr.ipoib_type = htons(type);
 972         tgldp->ipoib_rhdr.ipoib_mbz = 0;
 973         mac_copy(&gldp->ipoib_dest, &tgldp->ipoib_dest, IPOIB_ADDRL);
 974 
 975         return (nmp);
 976 }
 977 
 978 /* ==== */
 979 /* FDDI */
 980 /* ==== */
 981 
 982 void
 983 gld_init_fddi(gld_mac_info_t *macinfo)
 984 {
 985         struct gldkstats *sp =
 986             ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
 987 
 988         /* Assumptions we make for this medium */
 989         ASSERT(macinfo->gldm_type == DL_FDDI);
 990         ASSERT(macinfo->gldm_addrlen == 6);
 991         ASSERT(macinfo->gldm_saplen == -2);
 992 #ifndef lint
 993         ASSERT(sizeof (struct fddi_mac_frm) == 13);
 994         ASSERT(sizeof (mac_addr_t) == 6);
 995 #endif
 996 
 997         /* Wire address format is bit reversed from canonical format */
 998         macinfo->gldm_options |= GLDOPT_CANONICAL_ADDR;
 999 
1000         kstat_named_init(&sp->glds_fddi_mac_error,
1001             "mac_errors", KSTAT_DATA_UINT32);
1002         kstat_named_init(&sp->glds_fddi_mac_lost,
1003             "mac_lost_errors", KSTAT_DATA_UINT32);
1004         kstat_named_init(&sp->glds_fddi_mac_token,
1005             "mac_tokens", KSTAT_DATA_UINT32);
1006         kstat_named_init(&sp->glds_fddi_mac_tvx_expired,
1007             "mac_tvx_expired", KSTAT_DATA_UINT32);
1008         kstat_named_init(&sp->glds_fddi_mac_late,
1009             "mac_late", KSTAT_DATA_UINT32);
1010         kstat_named_init(&sp->glds_fddi_mac_ring_op,
1011             "mac_ring_ops", KSTAT_DATA_UINT32);
1012 }
1013 
1014 /*ARGSUSED*/
1015 void
1016 gld_uninit_fddi(gld_mac_info_t *macinfo)
1017 {
1018 }
1019 
1020 int
1021 gld_interpret_fddi(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
1022     packet_flag_t flags)
1023 {
1024         struct fddi_mac_frm *mh;
1025         gld_mac_pvt_t *mac_pvt;
1026         struct llc_snap_hdr *snaphdr;
1027         mblk_t *pmp = NULL;
1028 
1029         /*
1030          * Quickly handle receive fastpath; FDDI does not support IPQ hack.
1031          */
1032         if (flags == GLD_RXQUICK) {
1033                 pktinfo->pktLen = msgdsize(mp);
1034                 return (-1);
1035         }
1036 
1037         bzero((void *)pktinfo, sizeof (*pktinfo));
1038 
1039         pktinfo->pktLen = msgdsize(mp);
1040 
1041         /* make sure packet has at least a whole mac header */
1042         if (pktinfo->pktLen < sizeof (struct fddi_mac_frm))
1043                 return (-1);
1044 
1045         /* make sure the mac header falls into contiguous memory */
1046         if (MBLKL(mp) < sizeof (struct fddi_mac_frm)) {
1047                 if ((pmp = msgpullup(mp, -1)) == NULL) {
1048 #ifdef GLD_DEBUG
1049                         if (gld_debug & GLDERRS)
1050                                 cmn_err(CE_WARN,
1051                                     "GLD: interpret_fddi cannot msgpullup");
1052 #endif
1053                         return (-1);
1054                 }
1055                 mp = pmp;       /* this mblk contains the whole mac header */
1056         }
1057 
1058         mh = (struct fddi_mac_frm *)mp->b_rptr;
1059 
1060         /* Check to see if the mac is a broadcast or multicast address. */
1061         /* NB we are still in wire format (non canonical) */
1062         /* mac_eq works because ether_broadcast is the same either way */
1063         if (mac_eq(mh->fddi_dhost, ether_broadcast, macinfo->gldm_addrlen))
1064                 pktinfo->isBroadcast = 1;
1065         else if (mh->fddi_dhost[0] & 0x80)
1066                 pktinfo->isMulticast = 1;
1067 
1068         if (flags == GLD_TX)
1069                 goto out;       /* Got all info we need for xmit case */
1070 
1071         ASSERT(GLDM_LOCK_HELD(macinfo));
1072 
1073         /*
1074          * Deal with the mac header
1075          */
1076 
1077         cmac_copy(mh->fddi_dhost, pktinfo->dhost,
1078             macinfo->gldm_addrlen, macinfo);
1079         cmac_copy(mh->fddi_shost, pktinfo->shost,
1080             macinfo->gldm_addrlen, macinfo);
1081 
1082         mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1083         pktinfo->isLooped = mac_eq(pktinfo->shost,
1084             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1085         pktinfo->isForMe = mac_eq(pktinfo->dhost,
1086             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1087 
1088         pktinfo->macLen = sizeof (struct fddi_mac_frm);
1089 
1090         /*
1091          * Before trying to look beyond the MAC header, make sure the LLC
1092          * header exists, and that both it and any SNAP header are contiguous.
1093          */
1094         if (MBLKL(mp) < sizeof (struct fddi_mac_frm) + LLC_SNAP_HDR_LEN &&
1095             MBLKL(mp) < pktinfo->pktLen) {
1096                 /*
1097                  * we don't have the entire packet within the first mblk (and
1098                  * therefore we didn't do the msgpullup above), AND the first
1099                  * mblk may not contain all the data we need to look at.
1100                  */
1101                 ASSERT(pmp == NULL);    /* couldn't have done msgpullup above */
1102                 if ((pmp = msgpullup(mp, -1)) == NULL) {
1103 #ifdef GLD_DEBUG
1104                         if (gld_debug & GLDERRS)
1105                                 cmn_err(CE_WARN,
1106                                     "GLD: interpret_fddi cannot msgpullup2");
1107 #endif
1108                         goto out;       /* can't interpret this pkt further */
1109                 }
1110                 mp = pmp;       /* this mblk should contain everything needed */
1111         }
1112 
1113         /*
1114          * Check SAP/SNAP information.
1115          */
1116         if ((mh->fddi_fc & 0x70) == 0x50) {
1117                 if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
1118                         goto out;
1119 
1120                 pktinfo->isLLC = 1;
1121 
1122                 if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
1123                         goto out;
1124 
1125                 snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
1126                 if (ISETHERTYPE(snaphdr)) {
1127                         pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
1128                         pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
1129                 }
1130         }
1131 out:
1132         if (pmp != NULL)
1133                 freemsg(pmp);
1134 
1135         return (0);
1136 }
1137 
1138 mblk_t *
1139 gld_unitdata_fddi(gld_t *gld, mblk_t *mp)
1140 {
1141         gld_mac_info_t *macinfo = gld->gld_mac_info;
1142         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1143         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1144         mac_addr_t dhost;
1145         unsigned short type;
1146         mblk_t *nmp;
1147         struct fddi_mac_frm *mh;
1148         int hdrlen;
1149 
1150         ASSERT(macinfo);
1151 
1152         /* extract needed info from the mblk before we maybe reuse it */
1153         mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
1154 
1155         /* look in the unitdata request for a sap, else use bound one */
1156         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1157             REF_HOST_USHORT(gldp->glda_sap) != 0)
1158                 type = REF_HOST_USHORT(gldp->glda_sap);
1159         else
1160                 type = gld->gld_sap;
1161 
1162 
1163         hdrlen = sizeof (struct fddi_mac_frm);
1164 
1165         /*
1166          * Check whether we need to do EtherType encoding or whether the packet
1167          * is LLC.
1168          */
1169         if (type > GLD_MAX_802_SAP)
1170                 hdrlen += sizeof (struct llc_snap_hdr);
1171 
1172         /* need a buffer big enough for the headers */
1173         nmp = mp->b_cont;    /* where the packet payload M_DATA is */
1174         if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
1175                 /* it fits at the beginning of the first M_DATA block */
1176                 freeb(mp);      /* don't need the M_PROTO anymore */
1177         } else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
1178                 /* we can reuse the dl_unitdata_req M_PROTO mblk */
1179                 nmp = mp;
1180                 DB_TYPE(nmp) = M_DATA;
1181                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1182         } else {
1183                 /* we need to allocate one */
1184                 if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1185                         return (NULL);
1186                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1187                 linkb(nmp, mp->b_cont);
1188                 freeb(mp);
1189         }
1190 
1191 
1192         /* Got the space, now copy in the header components */
1193         if (type > GLD_MAX_802_SAP) {
1194                 /* create the snap header */
1195                 struct llc_snap_hdr *snap;
1196                 nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1197                 snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1198                 *snap = llc_snap_def;
1199                 SET_NET_USHORT(snap->type, type);
1200         }
1201 
1202         nmp->b_rptr -= sizeof (struct fddi_mac_frm);
1203 
1204         mh = (struct fddi_mac_frm *)nmp->b_rptr;
1205 
1206         mh->fddi_fc = 0x50;
1207         cmac_copy(dhost, mh->fddi_dhost, macinfo->gldm_addrlen, macinfo);
1208 
1209         /*
1210          * We access the mac address without the mutex to prevent
1211          * mutex contention (BUG 4211361)
1212          */
1213         cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1214             mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
1215         return (nmp);
1216 }
1217 
1218 mblk_t *
1219 gld_fastpath_fddi(gld_t *gld, mblk_t *mp)
1220 {
1221         gld_mac_info_t *macinfo = gld->gld_mac_info;
1222         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
1223         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1224         unsigned short type;
1225         mblk_t *nmp;
1226         struct fddi_mac_frm *mh;
1227         int hdrlen;
1228 
1229         ASSERT(macinfo);
1230 
1231         /* look in the unitdata request for a sap, else use bound one */
1232         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1233             REF_HOST_USHORT(gldp->glda_sap) != 0)
1234                 type = REF_HOST_USHORT(gldp->glda_sap);
1235         else
1236                 type = gld->gld_sap;
1237 
1238         hdrlen = sizeof (struct fddi_mac_frm);
1239 
1240         /*
1241          * Check whether we need to do EtherType encoding or whether the packet
1242          * will be LLC.
1243          */
1244         if (type > GLD_MAX_802_SAP)
1245                 hdrlen += sizeof (struct llc_snap_hdr);
1246 
1247         if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1248                 return (NULL);
1249 
1250         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1251 
1252         /* Got the space, now copy in the header components */
1253 
1254         if (type > GLD_MAX_802_SAP) {
1255                 /* create the snap header */
1256                 struct llc_snap_hdr *snap;
1257                 nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1258                 snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1259                 *snap = llc_snap_def;
1260                 snap->type = htons(type);    /* we know it's aligned */
1261         }
1262 
1263         nmp->b_rptr -= sizeof (struct fddi_mac_frm);
1264 
1265         mh = (struct fddi_mac_frm *)nmp->b_rptr;
1266         mh->fddi_fc = 0x50;
1267         cmac_copy(gldp->glda_addr, mh->fddi_dhost,
1268             macinfo->gldm_addrlen, macinfo);
1269 
1270         GLDM_LOCK(macinfo, RW_WRITER);
1271         cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1272             mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
1273         GLDM_UNLOCK(macinfo);
1274 
1275         return (nmp);
1276 }
1277 
1278 /* ========== */
1279 /* Token Ring */
1280 /* ========== */
1281 
1282 #define GLD_SR_VAR(macinfo)     \
1283         (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->data)
1284 
1285 #define GLD_SR_HASH(macinfo)    ((struct srtab **)GLD_SR_VAR(macinfo))
1286 
1287 #define GLD_SR_MUTEX(macinfo)   \
1288         (&((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->datalock)
1289 
1290 static void gld_sr_clear(gld_mac_info_t *);
1291 static void gld_rcc_receive(gld_mac_info_t *, pktinfo_t *, struct gld_ri *,
1292     uchar_t *, int);
1293 static void gld_rcc_send(gld_mac_info_t *, queue_t *, uchar_t *,
1294     struct gld_ri **, uchar_t *);
1295 
1296 static mac_addr_t tokenbroadcastaddr2 = { 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff };
1297 static struct gld_ri ri_ste_def;
1298 
1299 void
1300 gld_init_tr(gld_mac_info_t *macinfo)
1301 {
1302         struct gldkstats *sp =
1303             ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
1304 
1305         /* avoid endian-dependent code by initializing here instead of static */
1306         ri_ste_def.len = 2;
1307         ri_ste_def.rt = RT_STE;
1308         ri_ste_def.mtu = RT_MTU_MAX;
1309         ri_ste_def.dir = 0;
1310         ri_ste_def.res = 0;
1311 
1312         /* Assumptions we make for this medium */
1313         ASSERT(macinfo->gldm_type == DL_TPR);
1314         ASSERT(macinfo->gldm_addrlen == 6);
1315         ASSERT(macinfo->gldm_saplen == -2);
1316 #ifndef lint
1317         ASSERT(sizeof (struct tr_mac_frm_nori) == 14);
1318         ASSERT(sizeof (mac_addr_t) == 6);
1319 #endif
1320 
1321         mutex_init(GLD_SR_MUTEX(macinfo), NULL, MUTEX_DRIVER, NULL);
1322 
1323         GLD_SR_VAR(macinfo) = kmem_zalloc(sizeof (struct srtab *)*SR_HASH_SIZE,
1324                                 KM_SLEEP);
1325 
1326         /* Default is RDE enabled for this medium */
1327         ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled =
1328             ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1329             "gld_rde_enable", 1);
1330 
1331         /*
1332          * Default is to use STE for unknown paths if RDE is enabled.
1333          * If RDE is disabled, default is to use NULL RIF fields.
1334          *
1335          * It's possible to force use of STE for ALL packets:
1336          * disable RDE but enable STE.  This may be useful for
1337          * non-transparent bridges, when it is not desired to run
1338          * the RDE algorithms.
1339          */
1340         ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste =
1341             ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1342             "gld_rde_str_indicator_ste",
1343             ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled);
1344 
1345         /* Default 10 second route timeout on lack of activity */
1346         {
1347         int t = ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1348             "gld_rde_timeout", 10);
1349         if (t < 1)
1350                 t = 1;          /* Let's be reasonable */
1351         if (t > 600)
1352                 t = 600;        /* Let's be reasonable */
1353         /* We're using ticks (lbolts) for our timeout -- convert from seconds */
1354         t = drv_usectohz(1000000 * t);
1355         ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout = t;
1356         }
1357 
1358         kstat_named_init(&sp->glds_dot5_line_error,
1359             "line_errors", KSTAT_DATA_UINT32);
1360         kstat_named_init(&sp->glds_dot5_burst_error,
1361             "burst_errors", KSTAT_DATA_UINT32);
1362         kstat_named_init(&sp->glds_dot5_signal_loss,
1363             "signal_losses", KSTAT_DATA_UINT32);
1364 
1365         /*
1366          * only initialize the new statistics if the driver
1367          * knows about them.
1368          */
1369         if (macinfo->gldm_driver_version != GLD_VERSION_200)
1370                 return;
1371 
1372         kstat_named_init(&sp->glds_dot5_ace_error,
1373             "ace_errors", KSTAT_DATA_UINT32);
1374         kstat_named_init(&sp->glds_dot5_internal_error,
1375             "internal_errors", KSTAT_DATA_UINT32);
1376         kstat_named_init(&sp->glds_dot5_lost_frame_error,
1377             "lost_frame_errors", KSTAT_DATA_UINT32);
1378         kstat_named_init(&sp->glds_dot5_frame_copied_error,
1379             "frame_copied_errors", KSTAT_DATA_UINT32);
1380         kstat_named_init(&sp->glds_dot5_token_error,
1381             "token_errors", KSTAT_DATA_UINT32);
1382         kstat_named_init(&sp->glds_dot5_freq_error,
1383             "freq_errors", KSTAT_DATA_UINT32);
1384 }
1385 
1386 void
1387 gld_uninit_tr(gld_mac_info_t *macinfo)
1388 {
1389         mutex_destroy(GLD_SR_MUTEX(macinfo));
1390         gld_sr_clear(macinfo);
1391         kmem_free(GLD_SR_VAR(macinfo), sizeof (struct srtab *) * SR_HASH_SIZE);
1392 }
1393 
1394 int
1395 gld_interpret_tr(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
1396     packet_flag_t flags)
1397 {
1398         struct tr_mac_frm *mh;
1399         gld_mac_pvt_t *mac_pvt;
1400         struct llc_snap_hdr *snaphdr;
1401         mblk_t *pmp = NULL;
1402         struct gld_ri *rh;
1403 
1404         /*
1405          * Quickly handle receive fastpath; TR does not support IPQ hack.
1406          */
1407         if (flags == GLD_RXQUICK) {
1408                 pktinfo->pktLen = msgdsize(mp);
1409                 return (-1);
1410         }
1411 
1412         bzero((void *)pktinfo, sizeof (*pktinfo));
1413 
1414         pktinfo->pktLen = msgdsize(mp);
1415 
1416         /* make sure packet has at least a whole mac header */
1417         if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori))
1418                 return (-1);
1419 
1420         /* make sure the mac header falls into contiguous memory */
1421         if (MBLKL(mp) < sizeof (struct tr_mac_frm_nori)) {
1422                 if ((pmp = msgpullup(mp, -1)) == NULL) {
1423 #ifdef GLD_DEBUG
1424                         if (gld_debug & GLDERRS)
1425                                 cmn_err(CE_WARN,
1426                                     "GLD: interpret_tr cannot msgpullup");
1427 #endif
1428                         return (-1);
1429                 }
1430                 mp = pmp;       /* this mblk contains the whole mac header */
1431         }
1432 
1433         mh = (struct tr_mac_frm *)mp->b_rptr;
1434 
1435         /* Check to see if the mac is a broadcast or multicast address. */
1436         if (mac_eq(mh->tr_dhost, ether_broadcast, macinfo->gldm_addrlen) ||
1437             mac_eq(mh->tr_dhost, tokenbroadcastaddr2, macinfo->gldm_addrlen))
1438                 pktinfo->isBroadcast = 1;
1439         else if (mh->tr_dhost[0] & 0x80)
1440                 pktinfo->isMulticast = 1;
1441 
1442         if (flags == GLD_TX)
1443                 goto out;       /* Got all info we need for xmit case */
1444 
1445         ASSERT(GLDM_LOCK_HELD(macinfo));
1446 
1447         /*
1448          * Deal with the mac header
1449          */
1450 
1451         mac_copy(mh->tr_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
1452         mac_copy(mh->tr_shost, pktinfo->shost, macinfo->gldm_addrlen);
1453         pktinfo->shost[0] &= ~0x80;      /* turn off RIF indicator */
1454 
1455         mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1456         pktinfo->isLooped = mac_eq(pktinfo->shost,
1457             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1458         pktinfo->isForMe = mac_eq(pktinfo->dhost,
1459             mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1460 
1461         rh = (struct gld_ri *)NULL;
1462         pktinfo->macLen = sizeof (struct tr_mac_frm_nori);
1463 
1464         /*
1465          * Before trying to look beyond the MAC header, make sure the data
1466          * structures are all contiguously where we can conveniently look at
1467          * them.  We'll use a worst-case estimate of how many bytes into the
1468          * packet data we'll be needing to look.  Things will be more efficient
1469          * if the driver puts at least this much into the first mblk.
1470          *
1471          * Even after this, we still will have to do checks against the total
1472          * length of the packet.  A bad incoming packet may not hold all the
1473          * data structures it says it does.
1474          */
1475         if (MBLKL(mp) < sizeof (struct tr_mac_frm) +
1476             LLC_HDR1_LEN + sizeof (struct rde_pdu) &&
1477             MBLKL(mp) < pktinfo->pktLen) {
1478                 /*
1479                  * we don't have the entire packet within the first mblk (and
1480                  * therefore we didn't do the msgpullup above), AND the first
1481                  * mblk may not contain all the data we need to look at.
1482                  */
1483                 ASSERT(pmp == NULL);    /* couldn't have done msgpullup above */
1484                 if ((pmp = msgpullup(mp, -1)) == NULL) {
1485 #ifdef GLD_DEBUG
1486                         if (gld_debug & GLDERRS)
1487                                 cmn_err(CE_WARN,
1488                                     "GLD: interpret_tr cannot msgpullup2");
1489 #endif
1490                         goto out;       /* can't interpret this pkt further */
1491                 }
1492                 mp = pmp;       /* this mblk should contain everything needed */
1493                 mh = (struct tr_mac_frm *)mp->b_rptr;        /* to look at RIF */
1494         }
1495 
1496         if (mh->tr_shost[0] & 0x80) {
1497                 /* Routing Information Field (RIF) is present */
1498                 if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + 2)
1499                         goto out;       /* RIF should have been there! */
1500                 rh = (struct gld_ri *)&mh->tr_ri;
1501                 if ((rh->len & 1) || rh->len < 2) {
1502                         /* Bogus RIF, don't handle this packet */
1503 #ifdef GLD_DEBUG
1504                         if (gld_debug & GLDERRS)
1505                                 cmn_err(CE_WARN,
1506                                     "GLD: received TR packet with "
1507                                     "bogus RIF length %d",
1508                                     rh->len);
1509 #endif
1510                         goto out;
1511                 }
1512                 if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + rh->len)
1513                         goto out;       /* RIF should have been there! */
1514                 pktinfo->macLen += rh->len;
1515         }
1516 
1517         if ((mh->tr_fc & 0xc0) == 0x40) {
1518                 if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
1519                         goto out;
1520 
1521                 pktinfo->isLLC = 1;
1522 
1523                 if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
1524                         goto out;
1525 
1526                 snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
1527                 if (ISETHERTYPE(snaphdr)) {
1528                         pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
1529                         pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
1530                 }
1531 
1532                 /* Inform the Route Control Component of received LLC frame */
1533                 gld_rcc_receive(macinfo, pktinfo, rh,
1534                     mp->b_rptr + pktinfo->macLen,
1535                     pktinfo->pktLen - pktinfo->macLen);
1536         }
1537 out:
1538         if (pmp != NULL)
1539                 freemsg(pmp);
1540 
1541         return (0);
1542 }
1543 
1544 mblk_t *
1545 gld_unitdata_tr(gld_t *gld, mblk_t *mp)
1546 {
1547         gld_mac_info_t *macinfo = gld->gld_mac_info;
1548         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1549         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1550         mac_addr_t dhost;
1551         unsigned short type;
1552         mblk_t *nmp, *llcmp, *pmp = NULL;
1553         struct tr_mac_frm_nori *mh;
1554         int hdrlen;
1555         struct gld_ri *rh;
1556 
1557         ASSERT(macinfo);
1558 
1559         /* extract needed info from the mblk before we maybe reuse it */
1560         mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
1561 
1562         /* look in the unitdata request for a sap, else use bound one */
1563         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1564             REF_HOST_USHORT(gldp->glda_sap) != 0)
1565                 type = REF_HOST_USHORT(gldp->glda_sap);
1566         else
1567                 type = gld->gld_sap;
1568 
1569         /* includes maximum possible Routing Information Field (RIF) size */
1570         hdrlen = sizeof (struct tr_mac_frm);
1571 
1572         /*
1573          * Check whether we need to do EtherType encoding or whether the packet
1574          * is LLC.
1575          */
1576         if (type > GLD_MAX_802_SAP)
1577                 hdrlen += sizeof (struct llc_snap_hdr);
1578 
1579         /* need a buffer big enough for the headers */
1580         llcmp = nmp = mp->b_cont; /* where the packet payload M_DATA is */
1581 
1582         /*
1583          * We are going to need to look at the LLC header, so make sure it
1584          * is contiguously in a single mblk.  If we're the ones who create
1585          * the LLC header (below, in the case where sap > 0xff) then we don't
1586          * have to worry about it here.
1587          */
1588         ASSERT(nmp != NULL);    /* gld_unitdata guarantees msgdsize > 0 */
1589         if (type <= GLD_MAX_802_SAP) {
1590                 if (MBLKL(llcmp) < LLC_HDR1_LEN) {
1591                         llcmp = pmp = msgpullup(nmp, LLC_HDR1_LEN);
1592                         if (pmp == NULL) {
1593 #ifdef GLD_DEBUG
1594                                 if (gld_debug & GLDERRS)
1595                                         cmn_err(CE_WARN,
1596                                             "GLD: unitdata_tr "
1597                                             "cannot msgpullup");
1598 #endif
1599                                 return (NULL);
1600                         }
1601                 }
1602         }
1603 
1604         if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
1605                 /* it fits at the beginning of the first M_DATA block */
1606                 freeb(mp);      /* don't need the M_PROTO anymore */
1607         } else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
1608                 /* we can reuse the dl_unitdata_req M_PROTO mblk */
1609                 nmp = mp;
1610                 DB_TYPE(nmp) = M_DATA;
1611                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1612         } else {
1613                 /* we need to allocate one */
1614                 if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL) {
1615                         if (pmp != NULL)
1616                                 freemsg(pmp);
1617                         return (NULL);
1618                 }
1619                 nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1620                 linkb(nmp, mp->b_cont);
1621                 freeb(mp);
1622         }
1623 
1624         /* Got the space, now copy in the header components */
1625         if (type > GLD_MAX_802_SAP) {
1626                 /* create the snap header */
1627                 struct llc_snap_hdr *snap;
1628                 llcmp = nmp;    /* LLC header is going to be in this mblk */
1629                 nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1630                 snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1631                 *snap = llc_snap_def;
1632                 SET_NET_USHORT(snap->type, type);
1633         }
1634 
1635         /* Hold SR tables still while we maybe point at an entry */
1636         mutex_enter(GLD_SR_MUTEX(macinfo));
1637 
1638         gld_rcc_send(macinfo, WR(gld->gld_qptr), dhost, &rh, llcmp->b_rptr);
1639 
1640         if (rh != NULL) {
1641                 /* copy in the RIF */
1642                 ASSERT(rh->len <= sizeof (struct gld_ri));
1643                 nmp->b_rptr -= rh->len;
1644                 bcopy((caddr_t)rh, (caddr_t)nmp->b_rptr, rh->len);
1645         }
1646 
1647         mutex_exit(GLD_SR_MUTEX(macinfo));
1648 
1649         /* no longer need the pulled-up mblk */
1650         if (pmp != NULL)
1651                 freemsg(pmp);
1652 
1653         /*
1654          * fill in token ring header
1655          */
1656         nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1657         mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
1658         mh->tr_ac = 0x10;
1659         mh->tr_fc = 0x40;
1660         mac_copy(dhost, mh->tr_dhost, macinfo->gldm_addrlen);
1661 
1662         /*
1663          * We access the mac address without the mutex to prevent
1664          * mutex contention (BUG 4211361)
1665          */
1666         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1667             mh->tr_shost, macinfo->gldm_addrlen);
1668 
1669         if (rh != NULL)
1670                 mh->tr_shost[0] |= 0x80;
1671         else
1672                 mh->tr_shost[0] &= ~0x80;
1673 
1674         return (nmp);
1675 }
1676 
1677 /*
1678  * We cannot have our client sending us "fastpath" M_DATA messages,
1679  * because to do that we must provide to him a fixed MAC header to
1680  * be prepended to each outgoing packet.  But with Source Routing
1681  * media, the length and content of the MAC header changes as the
1682  * routes change, so there is no fixed header we can provide.  So
1683  * we decline to accept M_DATA messages if Source Routing is enabled.
1684  */
1685 mblk_t *
1686 gld_fastpath_tr(gld_t *gld, mblk_t *mp)
1687 {
1688         gld_mac_info_t *macinfo = gld->gld_mac_info;
1689         dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
1690         struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1691         unsigned short type;
1692         mblk_t *nmp;
1693         struct tr_mac_frm_nori *mh;
1694         int hdrlen;
1695 
1696         ASSERT(macinfo);
1697 
1698         /*
1699          * If we are doing Source Routing, then we cannot provide a fixed
1700          * MAC header, so fail.
1701          */
1702         if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
1703                 return (NULL);
1704 
1705         /* look in the unitdata request for a sap, else use bound one */
1706         if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1707             REF_HOST_USHORT(gldp->glda_sap) != 0)
1708                 type = REF_HOST_USHORT(gldp->glda_sap);
1709         else
1710                 type = gld->gld_sap;
1711 
1712         hdrlen = sizeof (struct tr_mac_frm_nori);
1713 
1714         if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
1715                 hdrlen += ri_ste_def.len;
1716 
1717         /*
1718          * Check whether we need to do EtherType encoding or whether the packet
1719          * will be LLC.
1720          */
1721         if (type > GLD_MAX_802_SAP)
1722                 hdrlen += sizeof (struct llc_snap_hdr);
1723 
1724         if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1725                 return (NULL);
1726 
1727         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1728 
1729         /* Got the space, now copy in the header components */
1730 
1731         if (type > GLD_MAX_802_SAP) {
1732                 /* create the snap header */
1733                 struct llc_snap_hdr *snap;
1734                 nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1735                 snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1736                 *snap = llc_snap_def;
1737                 snap->type = htons(type);    /* we know it's aligned */
1738         }
1739 
1740         /* RDE is disabled, use NULL RIF, or STE RIF */
1741         if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
1742                 nmp->b_rptr -= ri_ste_def.len;
1743                 bcopy((caddr_t)&ri_ste_def, (caddr_t)nmp->b_rptr,
1744                     ri_ste_def.len);
1745         }
1746 
1747         /*
1748          * fill in token ring header
1749          */
1750         nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1751         mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
1752         mh->tr_ac = 0x10;
1753         mh->tr_fc = 0x40;
1754         mac_copy(gldp->glda_addr, mh->tr_dhost, macinfo->gldm_addrlen);
1755 
1756         GLDM_LOCK(macinfo, RW_WRITER);
1757         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1758             mh->tr_shost, macinfo->gldm_addrlen);
1759         GLDM_UNLOCK(macinfo);
1760 
1761         if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
1762                 mh->tr_shost[0] |= 0x80;
1763         else
1764                 mh->tr_shost[0] &= ~0x80;
1765 
1766         return (nmp);
1767 }
1768 
1769 /*
1770  * Route Determination Entity (ISO 8802-2 / IEEE 802.2 : 1994, Section 9)
1771  *
1772  * RDE is an LLC layer entity.  GLD is a MAC layer entity.  The proper
1773  * solution to this architectural anomaly is to move RDE support out of GLD
1774  * and into LLC where it belongs.  In particular, only LLC has the knowledge
1775  * necessary to reply to XID and TEST packets.  If and when it comes time to
1776  * move RDE out of GLD to LLC, the LLC-to-GLD interface should be modified
1777  * to use MA_UNITDATA structures rather than DL_UNITDATA structures.  Of
1778  * course, GLD will still have to continue to also support the DL_ structures
1779  * as long as IP is not layered over LLC.  Another, perhaps better, idea
1780  * would be to make RDE an autopush module on top of the token ring drivers:
1781  * RDE would sit between LLC and GLD.  It would then also sit between IP and
1782  * GLD, providing services to all clients of GLD/tokenring.  In that case,
1783  * GLD would still have to continue to support the DL_ interface for non-
1784  * Token Ring interfaces, using the MA_ interface only for media supporting
1785  * Source Routing media.
1786  *
1787  * At present, Token Ring is the only source routing medium we support.
1788  * Since Token Ring is not at this time a strategic network medium for Sun,
1789  * rather than devote a large amount of resources to creating a proper
1790  * architecture and implementation of RDE, we do the minimum necessary to
1791  * get it to work.  The interface between the above token ring code and the
1792  * below RDE code is designed to make it relatively easy to change to an
1793  * MA_UNITDATA model later should this ever become a priority.
1794  */
1795 
1796 static void gld_send_rqr(gld_mac_info_t *, uchar_t *, struct gld_ri *,
1797     struct rde_pdu *, int);
1798 static void gld_rde_pdu_req(gld_mac_info_t *, queue_t *, uchar_t *,
1799     struct gld_ri *, uchar_t, uchar_t, uchar_t);
1800 static void gld_get_route(gld_mac_info_t *, queue_t *, uchar_t *,
1801     struct gld_ri **, uchar_t, uchar_t);
1802 static void gld_reset_route(gld_mac_info_t *, queue_t *,
1803     uchar_t *, uchar_t, uchar_t);
1804 static void gld_rde_pdu_ind(gld_mac_info_t *, struct gld_ri *, struct rde_pdu *,
1805     int);
1806 static void gld_rif_ind(gld_mac_info_t *, struct gld_ri *, uchar_t *,
1807     uchar_t, uchar_t);
1808 static struct srtab **gld_sr_hash(struct srtab **, uchar_t *, int);
1809 static struct srtab *gld_sr_lookup_entry(gld_mac_info_t *, uchar_t *);
1810 static struct srtab *gld_sr_create_entry(gld_mac_info_t *, uchar_t *);
1811 
1812 /*
1813  * This routine implements a modified subset of the 802.2 RDE RCC receive
1814  * actions:
1815  *   we implement RCC receive events 3 to 12 (ISO 8802-2:1994 9.6.3.4);
1816  *   we omit special handling for the NULL SAP;
1817  *   we omit XID/TEST handling;
1818  *   we pass all packets (including RDE) upstream to LLC.
1819  */
1820 static void
1821 gld_rcc_receive(gld_mac_info_t *macinfo, pktinfo_t *pktinfo, struct gld_ri *rh,
1822     uchar_t *llcpkt, int llcpktlen)
1823 {
1824         struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
1825 
1826         if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
1827                 return;
1828 
1829         /*
1830          * First, ensure this packet wasn't something we received just
1831          * because we were in promiscuous mode.  Since none of the below
1832          * code wants to see group addressed packets anyway, we can do
1833          * this check up front.  Since we're doing that, we can omit the
1834          * checks for group addressed packets below.
1835          */
1836         if (!pktinfo->isForMe)
1837                 return;         /* Event 6 */
1838 
1839         /* Process a subset of Route Determination Entity (RDE) packets */
1840         if (snaphdr->d_lsap == LSAP_RDE) {
1841                 struct rde_pdu *pdu = (struct rde_pdu *)(llcpkt + LLC_HDR1_LEN);
1842                 int pdulen = llcpktlen - LLC_HDR1_LEN;
1843 
1844                 /* sanity check the PDU */
1845                 if ((pdulen < sizeof (struct rde_pdu)) ||
1846                     (snaphdr->s_lsap != LSAP_RDE))
1847                         return;
1848 
1849                 /* we only handle route discovery PDUs, not XID/TEST/other */
1850                 if (snaphdr->control != CNTL_LLC_UI)
1851                         return;
1852 
1853                 switch (pdu->rde_ptype) {
1854                 case RDE_RQC:   /* Route Query Command; Events 8 - 11 */
1855                         gld_send_rqr(macinfo, pktinfo->shost, rh, pdu, pdulen);
1856                         /* FALLTHROUGH */
1857                 case RDE_RQR:   /* Route Query Response; Event 12 */
1858                 case RDE_RS:    /* Route Selected; Event 7 */
1859                         gld_rde_pdu_ind(macinfo, rh, pdu, pdulen);
1860                         break;
1861                 default:        /* ignore if unrecognized ptype */
1862                         return;
1863                 }
1864 
1865                 return;
1866         }
1867 
1868         /* Consider routes seen in other IA SRF packets */
1869 
1870         if (rh == NULL)
1871                 return;         /* no RIF; Event 3 */
1872 
1873         if ((rh->rt & 0x04) != 0)
1874                 return;         /* not SRF; Event 5 */
1875 
1876         gld_rif_ind(macinfo, rh, pktinfo->shost, snaphdr->s_lsap,
1877             snaphdr->d_lsap);        /* Event 4 */
1878 }
1879 
1880 /*
1881  * Send RQR: 802.2 9.6.3.4.2(9) RCC Receive Events 8-11
1882  *
1883  * The routing processing really doesn't belong here; it should be handled in
1884  * the LLC layer above.  If that were the case then RDE could just send down
1885  * an extra MA_UNITDATA_REQ with the info needed to construct the packet.  But
1886  * at the time we get control here, it's not a particularly good time to be
1887  * constructing packets and trying to send them.  Specifically, at this layer
1888  * we need to construct the full media packet, which means the below routine
1889  * knows that it is dealing with Token Ring media.  If this were instead done
1890  * via a proper MA_UNITDATA interface, the RDE stuff could all be completely
1891  * media independent.  But since TR is the only source routing medium we
1892  * support, this works even though it is not clean.
1893  *
1894  * We "know" that the only time we can get here is from the "interpret"
1895  * routine, and only when it was called at receive time.
1896  */
1897 static void
1898 gld_send_rqr(gld_mac_info_t *macinfo, uchar_t *shost, struct gld_ri *rh,
1899     struct rde_pdu *pdu, int pdulen)
1900 {
1901         mblk_t *nmp;
1902         int nlen;
1903         struct tr_mac_frm_nori *nmh;
1904         struct gld_ri *nrh;
1905         struct llc_snap_hdr *nsnaphdr;
1906         struct rde_pdu *npdu;
1907 
1908         /* We know and assume we're on the receive path */
1909         ASSERT(GLDM_LOCK_HELD(macinfo));
1910 
1911         if (pdulen < sizeof (struct rde_pdu))
1912                 return;         /* Bad incoming PDU */
1913 
1914         nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
1915             sizeof (struct rde_pdu);
1916 
1917         if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
1918                 return;
1919 
1920         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1921 
1922         nmp->b_rptr -= sizeof (struct rde_pdu);
1923         npdu = (struct rde_pdu *)(nmp->b_rptr);
1924         *npdu = *pdu;   /* copy orig/target macaddr/saps */
1925         npdu->rde_ver = 1;
1926         npdu->rde_ptype = RDE_RQR;
1927         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1928             npdu->rde_target_mac, macinfo->gldm_addrlen);
1929 
1930         nmp->b_rptr -= LLC_HDR1_LEN;
1931         nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
1932         nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
1933         nsnaphdr->control = CNTL_LLC_UI;
1934 
1935         if (rh == NULL || (rh->rt & 0x06) == 0x06 ||
1936             rh->len > sizeof (struct gld_ri)) {
1937                 /* no RIF (Event 8), or RIF type STE (Event 9): send ARE RQR */
1938                 nmp->b_rptr -= 2;
1939                 nrh = (struct gld_ri *)(nmp->b_rptr);
1940                 nrh->len = 2;
1941                 nrh->rt = RT_ARE;
1942                 nrh->dir = 0;
1943                 nrh->res = 0;
1944                 nrh->mtu = RT_MTU_MAX;
1945         } else {
1946                 /*
1947                  * RIF must be ARE (Event 10) or SRF (Event 11):
1948                  * send SRF (reverse) RQR
1949                  */
1950                 ASSERT(rh->len <= sizeof (struct gld_ri));
1951                 nmp->b_rptr -= rh->len;
1952                 nrh = (struct gld_ri *)(nmp->b_rptr);
1953                 bcopy(rh, nrh, rh->len);     /* copy incoming RIF */
1954                 nrh->rt = RT_SRF;            /* make it SRF */
1955                 nrh->dir ^= 1;                       /* reverse direction */
1956         }
1957 
1958         nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1959         nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
1960         nmh->tr_ac = 0x10;
1961         nmh->tr_fc = 0x40;
1962         mac_copy(shost, nmh->tr_dhost, macinfo->gldm_addrlen);
1963         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1964             nmh->tr_shost, macinfo->gldm_addrlen);
1965         nmh->tr_shost[0] |= 0x80;            /* indicate RIF present */
1966 
1967         /*
1968          * Packet assembled; send it.
1969          *
1970          * As noted before, this is not really a good time to be trying to
1971          * send out packets.  We have no obvious queue to use if the packet
1972          * can't be sent right away.  We pick one arbitrarily.
1973          */
1974         {
1975         gld_vlan_t *vlan;
1976         queue_t *q;
1977 
1978         if ((vlan = gld_find_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
1979                 /* oops, no vlan on the list for this macinfo! */
1980                 /* this should not happen */
1981                 freeb(nmp);
1982                 return;
1983         }
1984         q = vlan->gldv_str_next->gld_qptr;
1985 
1986         /*
1987          * Queue the packet and let gld_wsrv
1988          * handle it, thus preventing a panic
1989          * caused by v2 TR in promiscuous mode
1990          * where it attempts to get the mutex
1991          * in this thread while already holding
1992          * it.
1993          */
1994         (void) putbq(WR(q), nmp);
1995         qenable(WR(q));
1996         }
1997 }
1998 
1999 /*
2000  * This routine implements a modified subset of the 802.2 RDE RCC send actions:
2001  *   we implement RCC send events 5 to 10 (ISO 8802-2:1994 9.6.3.5);
2002  *   we omit special handling for the NULL SAP;
2003  *   events 11 to 12 are handled by gld_rde_pdu_req below;
2004  *   we require an immediate response to our GET_ROUTE_REQUEST.
2005  */
2006 static void
2007 gld_rcc_send(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
2008     struct gld_ri **rhp, uchar_t *llcpkt)
2009 {
2010         struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
2011 
2012         /*
2013          * Our caller has to take the mutex because: to avoid an extra bcopy
2014          * of the RIF on every transmit, we pass back a pointer to our sr
2015          * table entry via rhp.  He has to keep the mutex until he has a
2016          * chance to copy the RIF out into the outgoing packet, so that we
2017          * don't modify the entry while he's trying to copy it.  This is a
2018          * little ugly, but saves the extra bcopy.
2019          */
2020         ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2021 
2022         *rhp = (struct gld_ri *)NULL;   /* start off clean (no RIF) */
2023 
2024         if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled) {
2025                 /* RDE is disabled -- use NULL or STE always */
2026                 if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
2027                     rde_str_indicator_ste)
2028                         *rhp = &ri_ste_def; /* STE option */
2029                 return;
2030         }
2031 
2032         if (!(dhost[0] & 0x80)) {
2033                 /* individual address; Events 7 - 10 */
2034                 if ((snaphdr->control & 0xef) == 0xe3) {
2035                         /* TEST command, reset the route */
2036                         gld_reset_route(macinfo, q,
2037                             dhost, snaphdr->d_lsap, snaphdr->s_lsap);
2038                 }
2039                 gld_get_route(macinfo, q,
2040                     dhost, rhp, snaphdr->d_lsap, snaphdr->s_lsap);
2041         }
2042 
2043         if (*rhp == NULL) {
2044                 /*
2045                  * group address (Events 5 - 6),
2046                  * or no route available (Events 8 - 9):
2047                  * Need to send NSR or STE, as configured.
2048                  */
2049                 if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
2050                     rde_str_indicator_ste)
2051                         *rhp = &ri_ste_def; /* STE option */
2052         }
2053 }
2054 
2055 /*
2056  * RCC send events 11 - 12
2057  *
2058  * At present we only handle the RQC ptype.
2059  *
2060  * We "know" that the only time we can get here is from the "unitdata"
2061  * routine, called at wsrv time.
2062  *
2063  * If we ever implement the RS ptype (Event 13), this may no longer be true!
2064  */
2065 static void
2066 gld_rde_pdu_req(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
2067     struct gld_ri *rh, uchar_t dsap, uchar_t ssap, uchar_t ptype)
2068 {
2069         mblk_t *nmp;
2070         int nlen;
2071         struct tr_mac_frm_nori *nmh;
2072         struct gld_ri *nrh;
2073         struct llc_snap_hdr *nsnaphdr;
2074         struct rde_pdu *npdu;
2075         int srpresent = 0;
2076 
2077         /* if you change this to process other types, review all code below */
2078         ASSERT(ptype == RDE_RQC);
2079         ASSERT(rh == NULL);     /* RQC never uses SRF */
2080 
2081         nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
2082             sizeof (struct rde_pdu);
2083 
2084         if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
2085                 return;
2086 
2087         nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
2088 
2089         nmp->b_rptr -= sizeof (struct rde_pdu);
2090         npdu = (struct rde_pdu *)(nmp->b_rptr);
2091         npdu->rde_ver = 1;
2092         npdu->rde_ptype = ptype;
2093         mac_copy(dhost, &npdu->rde_target_mac, 6);
2094 
2095         /*
2096          * access the mac address without a mutex - take a risk -
2097          * to prevent mutex contention (BUG 4211361)
2098          */
2099         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
2100             &npdu->rde_orig_mac, 6);
2101         npdu->rde_target_sap = dsap;
2102         npdu->rde_orig_sap = ssap;
2103 
2104         nmp->b_rptr -= LLC_HDR1_LEN;
2105         nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
2106         nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
2107         nsnaphdr->control = CNTL_LLC_UI;
2108 
2109 #if 0   /* we don't need this for now */
2110         if (rh != NULL) {
2111                 /* send an SRF frame with specified RIF */
2112                 ASSERT(rh->len <= sizeof (struct gld_ri));
2113                 nmp->b_rptr -= rh->len;
2114                 nrh = (struct gld_ri *)(nmp->b_rptr);
2115                 bcopy(rh, nrh, rh->len);
2116                 ASSERT(nrh->rt == RT_SRF);
2117                 srpresent = 1;
2118         } else
2119 #endif
2120 
2121         /* Need to send NSR or STE, as configured.  */
2122         if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
2123                 /* send an STE frame */
2124                 nmp->b_rptr -= 2;
2125                 nrh = (struct gld_ri *)(nmp->b_rptr);
2126                 nrh->len = 2;
2127                 nrh->rt = RT_STE;
2128                 nrh->dir = 0;
2129                 nrh->res = 0;
2130                 nrh->mtu = RT_MTU_MAX;
2131                 srpresent = 1;
2132         } /* else send an NSR frame */
2133 
2134         nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
2135         nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
2136         nmh->tr_ac = 0x10;
2137         nmh->tr_fc = 0x40;
2138         mac_copy(dhost, nmh->tr_dhost, macinfo->gldm_addrlen);
2139         /*
2140          * access the mac address without a mutex - take a risk -
2141          * to prevent mutex contention  - BUG 4211361
2142          */
2143         mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
2144             nmh->tr_shost, macinfo->gldm_addrlen);
2145 
2146         if (srpresent)
2147                 nmh->tr_shost[0] |= 0x80;
2148         else
2149                 nmh->tr_shost[0] &= ~0x80;
2150 
2151         /*
2152          * Packet assembled; send it.
2153          *
2154          * Since we own the SR_MUTEX, we don't want to take the maclock
2155          * mutex (since they are acquired in the opposite order on the
2156          * receive path, so deadlock could occur).  We could rearrange
2157          * the code in gld_get_route() and drop the SR_MUTEX around the
2158          * call to gld_rde_pdu_req(), but that's kind of ugly.  Rather,
2159          * we just refrain from calling gld_start() from here, and
2160          * instead just queue the packet for wsrv to send next.  Besides,
2161          * it's more important to get the packet we're working on out
2162          * quickly than this RQC.
2163          */
2164         (void) putbq(WR(q), nmp);
2165         qenable(WR(q));
2166 }
2167 
2168 /*
2169  * Route Determination Component (RDC)
2170  *
2171  * We do not implement separate routes for each SAP, as specified by
2172  * ISO 8802-2; instead we implement only one route per remote mac address.
2173  */
2174 static void
2175 gld_get_route(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
2176     struct gld_ri **rhp, uchar_t dsap, uchar_t ssap)
2177 {
2178         struct srtab *sr;
2179         clock_t t = ddi_get_lbolt();
2180 
2181         ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2182 
2183         sr = gld_sr_lookup_entry(macinfo, dhost);
2184 
2185         if (sr == NULL) {
2186                 /*
2187                  * we have no entry -- never heard of this address:
2188                  * create an empty entry and initiate RQC
2189                  */
2190                 sr = gld_sr_create_entry(macinfo, dhost);
2191                 gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
2192                     dsap, ssap, RDE_RQC);
2193                 if (sr)
2194                         sr->sr_timer = t;
2195                 *rhp = NULL;            /* we have no route yet */
2196                 return;
2197         }
2198 
2199         /* we have an entry; see if we know a route yet */
2200 
2201         if (sr->sr_ri.len == 0) {
2202                 /* Have asked RQC, but no reply (yet) */
2203                 if (t - sr->sr_timer >
2204                     ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
2205                         /* RQR overdue, resend RQC */
2206                         gld_rde_pdu_req(macinfo, q, dhost,
2207                             (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
2208                         sr->sr_timer = t;
2209                 }
2210                 *rhp = NULL;            /* we have no route yet */
2211                 return;
2212         }
2213 
2214         /* we know a route, or it's local */
2215 
2216         /* if it might be stale, reset and get a new one */
2217         if (t - sr->sr_timer >
2218             ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
2219                 gld_rde_pdu_req(macinfo, q, dhost,
2220                     (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
2221                 sr->sr_ri.len = 0;
2222                 sr->sr_timer = t;
2223                 *rhp = NULL;            /* we have no route */
2224                 return;
2225         }
2226 
2227         if (sr->sr_ri.len == 2) {
2228                 /* the remote site is on our local ring -- no route needed */
2229                 *rhp = NULL;
2230                 return;
2231         }
2232 
2233         *rhp = &sr->sr_ri;       /* we have a route, return it */
2234 }
2235 
2236 /*
2237  * zap the specified entry and reinitiate RQC
2238  */
2239 static void
2240 gld_reset_route(gld_mac_info_t *macinfo, queue_t *q,
2241     uchar_t *dhost, uchar_t dsap, uchar_t ssap)
2242 {
2243         struct srtab *sr;
2244 
2245         ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2246 
2247         sr = gld_sr_create_entry(macinfo, dhost);
2248         gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
2249             dsap, ssap, RDE_RQC);
2250         if (sr == NULL)
2251                 return;
2252 
2253         sr->sr_ri.len = 0;
2254         sr->sr_timer = ddi_get_lbolt();
2255 }
2256 
2257 /*
2258  * This routine is called when an RDE PDU is received from our peer.
2259  * If it is an RS (Route Selected) PDU, we adopt the specified route.
2260  * If it is an RQR (reply to our previous RQC), we evaluate the
2261  * specified route in comparison with our current known route, if any,
2262  * and we keep the "better" of the two routes.
2263  */
2264 static void
2265 gld_rde_pdu_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, struct rde_pdu *pdu,
2266     int pdulen)
2267 {
2268         struct srtab *sr;
2269         uchar_t *otherhost;
2270 
2271         if (pdulen < sizeof (struct rde_pdu))
2272                 return;         /* Bad incoming PDU */
2273 
2274         if (pdu->rde_ptype == RDE_RQC)
2275                 return;                 /* ignore RQC */
2276 
2277         if (pdu->rde_ptype != RDE_RQR && pdu->rde_ptype != RDE_RS) {
2278 #ifdef GLD_DEBUG
2279                 if (gld_debug & GLDERRS)
2280                         cmn_err(CE_WARN, "gld: bogus RDE ptype 0x%x received",
2281                             pdu->rde_ptype);
2282 #endif
2283                 return;
2284         }
2285 
2286         if (rh == NULL) {
2287 #ifdef GLD_DEBUG
2288                 if (gld_debug & GLDERRS)
2289                         cmn_err(CE_WARN,
2290                             "gld: bogus NULL RIF, ptype 0x%x received",
2291                             pdu->rde_ptype);
2292 #endif
2293                 return;
2294         }
2295 
2296         ASSERT(rh->len >= 2);
2297         ASSERT(rh->len <= sizeof (struct gld_ri));
2298         ASSERT((rh->len & 1) == 0);
2299 
2300         if (pdu->rde_ptype == RDE_RQR) {
2301                 /* A reply to our RQC has his address as target mac */
2302                 otherhost = pdu->rde_target_mac;
2303         } else {
2304                 ASSERT(pdu->rde_ptype == RDE_RS);
2305                 /* An RS has his address as orig mac */
2306                 otherhost = pdu->rde_orig_mac;
2307         }
2308 
2309         mutex_enter(GLD_SR_MUTEX(macinfo));
2310 
2311         if ((sr = gld_sr_create_entry(macinfo, otherhost)) == NULL) {
2312                 mutex_exit(GLD_SR_MUTEX(macinfo));
2313                 return;         /* oh well, out of memory */
2314         }
2315 
2316         if (pdu->rde_ptype == RDE_RQR) {
2317                 /* see if new route is better than what we may already have */
2318                 if (sr->sr_ri.len != 0 &&
2319                     sr->sr_ri.len <= rh->len) {
2320                         mutex_exit(GLD_SR_MUTEX(macinfo));
2321                         return; /* we have one, and new one is no shorter */
2322                 }
2323         }
2324 
2325         /* adopt the new route */
2326         bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
2327         sr->sr_ri.rt = RT_SRF;       /* make it a clean SRF */
2328         sr->sr_ri.dir ^= 1;  /* reverse direction */
2329         sr->sr_timer = ddi_get_lbolt();
2330 
2331         mutex_exit(GLD_SR_MUTEX(macinfo));
2332 }
2333 
2334 /*
2335  * This routine is called when a packet with a RIF is received.  Our
2336  * policy is to adopt the route.
2337  */
2338 /* ARGSUSED3 */
2339 static void
2340 gld_rif_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, uchar_t *shost,
2341     uchar_t ssap, uchar_t dsap)
2342 {
2343         struct srtab *sr;
2344 
2345         ASSERT(rh != NULL);             /* ensure RIF */
2346         ASSERT((rh->rt & 0x04) == 0);    /* ensure SRF */
2347         ASSERT(rh->len >= 2);
2348         ASSERT(rh->len <= sizeof (struct gld_ri));
2349         ASSERT((rh->len & 1) == 0);
2350 
2351         mutex_enter(GLD_SR_MUTEX(macinfo));
2352 
2353         if ((sr = gld_sr_create_entry(macinfo, shost)) == NULL) {
2354                 mutex_exit(GLD_SR_MUTEX(macinfo));
2355                 return;         /* oh well, out of memory */
2356         }
2357 
2358         /* we have an entry; fill it in */
2359         bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
2360         sr->sr_ri.rt = RT_SRF;       /* make it a clean SRF */
2361         sr->sr_ri.dir ^= 1;  /* reverse direction */
2362         sr->sr_timer = ddi_get_lbolt();
2363 
2364         mutex_exit(GLD_SR_MUTEX(macinfo));
2365 }
2366 
2367 static struct srtab **
2368 gld_sr_hash(struct srtab **sr_hash_tbl, uchar_t *addr, int addr_length)
2369 {
2370         uint_t hashval = 0;
2371 
2372         while (--addr_length >= 0)
2373                 hashval ^= *addr++;
2374 
2375         return (&sr_hash_tbl[hashval % SR_HASH_SIZE]);
2376 }
2377 
2378 static struct srtab *
2379 gld_sr_lookup_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
2380 {
2381         struct srtab *sr;
2382 
2383         ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2384 
2385         for (sr = *gld_sr_hash(GLD_SR_HASH(macinfo), macaddr,
2386             macinfo->gldm_addrlen); sr; sr = sr->sr_next)
2387                 if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
2388                         return (sr);
2389 
2390         return ((struct srtab *)0);
2391 }
2392 
2393 static struct srtab *
2394 gld_sr_create_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
2395 {
2396         struct srtab *sr;
2397         struct srtab **srp;
2398 
2399         ASSERT(!(macaddr[0] & 0x80));       /* no group addresses here */
2400         ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2401 
2402         srp = gld_sr_hash(GLD_SR_HASH(macinfo), macaddr, macinfo->gldm_addrlen);
2403 
2404         for (sr = *srp; sr; sr = sr->sr_next)
2405                 if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
2406                         return (sr);
2407 
2408         if (!(sr = kmem_zalloc(sizeof (struct srtab), KM_NOSLEEP))) {
2409 #ifdef GLD_DEBUG
2410                 if (gld_debug & GLDERRS)
2411                         cmn_err(CE_WARN,
2412                             "gld: gld_sr_create_entry kmem_alloc failed");
2413 #endif
2414                 return ((struct srtab *)0);
2415         }
2416 
2417         bcopy((caddr_t)macaddr, (caddr_t)sr->sr_mac, macinfo->gldm_addrlen);
2418 
2419         sr->sr_next = *srp;
2420         *srp = sr;
2421         return (sr);
2422 }
2423 
2424 static void
2425 gld_sr_clear(gld_mac_info_t *macinfo)
2426 {
2427         int i;
2428         struct srtab **sr_hash_tbl = GLD_SR_HASH(macinfo);
2429         struct srtab **srp, *sr;
2430 
2431         /*
2432          * Walk through the table, deleting all entries.
2433          *
2434          * Only called from uninit, so don't need the mutex.
2435          */
2436         for (i = 0; i < SR_HASH_SIZE; i++) {
2437                 for (srp = &sr_hash_tbl[i]; (sr = *srp) != NULL; ) {
2438                         *srp = sr->sr_next;
2439                         kmem_free((char *)sr, sizeof (struct srtab));
2440                 }
2441         }
2442 }
2443 
2444 #ifdef  DEBUG
2445 void
2446 gld_sr_dump(gld_mac_info_t *macinfo)
2447 {
2448         int i, j;
2449         struct srtab **sr_hash_tbl;
2450         struct srtab *sr;
2451 
2452         sr_hash_tbl = GLD_SR_HASH(macinfo);
2453         if (sr_hash_tbl == NULL)
2454                 return;
2455 
2456         mutex_enter(GLD_SR_MUTEX(macinfo));
2457 
2458         /*
2459          * Walk through the table, printing all entries
2460          */
2461         cmn_err(CE_NOTE, "GLD Source Routing Table (0x%p):", (void *)macinfo);
2462         cmn_err(CE_CONT, "Addr len,rt,dir,mtu,res rng,brg0 rng,brg1...\n");
2463         for (i = 0; i < SR_HASH_SIZE; i++) {
2464                 for (sr = sr_hash_tbl[i]; sr; sr = sr->sr_next) {
2465                         cmn_err(CE_CONT,
2466                             "%x:%x:%x:%x:%x:%x %d,%x,%x,%x,%x ",
2467                             sr->sr_mac[0], sr->sr_mac[1], sr->sr_mac[2],
2468                             sr->sr_mac[3], sr->sr_mac[4], sr->sr_mac[5],
2469                             sr->sr_ri.len, sr->sr_ri.rt, sr->sr_ri.dir,
2470                             sr->sr_ri.mtu, sr->sr_ri.res);
2471                         if (sr->sr_ri.len)
2472                                 for (j = 0; j < (sr->sr_ri.len - 2) / 2; j++)
2473                                         cmn_err(CE_CONT, "%x ",
2474                                             REF_NET_USHORT(*(unsigned short *)
2475                                             &sr->sr_ri.rd[j]));
2476                         cmn_err(CE_CONT, "\n");
2477                 }
2478         }
2479 
2480         mutex_exit(GLD_SR_MUTEX(macinfo));
2481 }
2482 #endif