10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*931Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * IDN DLPI support (based on QE implementation). 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/debug.h> 340Sstevel@tonic-gate #include <sys/stropts.h> 350Sstevel@tonic-gate #include <sys/stream.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/cmn_err.h> 380Sstevel@tonic-gate #include <sys/errno.h> 390Sstevel@tonic-gate #ifdef xxx_trace 400Sstevel@tonic-gate #include <sys/vtrace.h> 410Sstevel@tonic-gate #endif /* xxx_trace */ 420Sstevel@tonic-gate #include <sys/kmem.h> 430Sstevel@tonic-gate #include <sys/ddi.h> 440Sstevel@tonic-gate #include <sys/sunddi.h> 450Sstevel@tonic-gate #include <sys/strsun.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/kstat.h> 480Sstevel@tonic-gate #include <sys/dlpi.h> 490Sstevel@tonic-gate #include <sys/time.h> 500Sstevel@tonic-gate #include <sys/cpuvar.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate #include <sys/idn.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate #ifdef IPV6 550Sstevel@tonic-gate #define IS_ETHERTYPE_IPV4(x) ((x) == ETHERTYPE_IP) 560Sstevel@tonic-gate #define IS_ETHERTYPE_IPV6(x) ((x) == ETHERTYPE_IPV6) 570Sstevel@tonic-gate #define IS_ETHERTYPE_IP(x) (IS_ETHERTYPE_IPV4(x) || IS_ETHERTYPE_IPV6(x)) 580Sstevel@tonic-gate #else 590Sstevel@tonic-gate #define IS_ETHERTYPE_IPV4(x) ((x) == ETHERTYPE_IP) 600Sstevel@tonic-gate #define IS_ETHERTYPE_IPV6(x) (0) 610Sstevel@tonic-gate #define IS_ETHERTYPE_IP IS_ETHERTYPE_IPV4 620Sstevel@tonic-gate #endif /* IPV6 */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate #ifdef IDN_TRACE 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * This stuff should go into <sys/vtrace.h> 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate #define TR_FAC_IDN 100 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * TR_FAC_IDN tags 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate #define TR_IDN_OPEN 0 730Sstevel@tonic-gate #define TR_IDN_CLOSE 1 740Sstevel@tonic-gate #define TR_IDN_WPUT_START 2 750Sstevel@tonic-gate #define TR_IDN_WPUT_END 3 760Sstevel@tonic-gate #define TR_IDN_WSRV_START 4 770Sstevel@tonic-gate #define TR_IDN_WSRV_END 5 780Sstevel@tonic-gate #define TR_IDN_START_START 6 790Sstevel@tonic-gate #define TR_IDN_START_END 7 800Sstevel@tonic-gate #define TR_IDN_INTR_START 8 810Sstevel@tonic-gate #define TR_IDN_INTR_END 9 820Sstevel@tonic-gate #define TR_IDN_READ_START 10 830Sstevel@tonic-gate #define TR_IDN_READ_END 11 840Sstevel@tonic-gate #define TR_IDN_SENDUP_START 12 850Sstevel@tonic-gate #define TR_IDN_SENDUP_END 13 860Sstevel@tonic-gate #define TR_IDN_ADDUDIND_START 14 870Sstevel@tonic-gate #define TR_IDN_ADDUDIND_END 15 880Sstevel@tonic-gate #define TR_IDN_GETBUF_START 16 890Sstevel@tonic-gate #define TR_IDN_GETBUF_END 17 900Sstevel@tonic-gate #define TR_IDN_FREEBUF_START 18 910Sstevel@tonic-gate #define TR_IDN_FREEBUF_END 19 920Sstevel@tonic-gate #define TR_IDN_PROTO_START 20 930Sstevel@tonic-gate #define TR_IDN_PROTO_END 21 940Sstevel@tonic-gate #define TR_IDN_INIT_START 22 950Sstevel@tonic-gate #define TR_IDN_INIT_END 23 960Sstevel@tonic-gate #define TR_IDN_PROTO_IN 24 970Sstevel@tonic-gate #define TR_IDN_PROTO_OUT 25 980Sstevel@tonic-gate 990Sstevel@tonic-gate #define IDNTRACE(fac, tag) (printf("idn.TRACE: ")) 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate #define TRACE_0(fac, tag, name) \ 1020Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1030Sstevel@tonic-gate printf(name); printf("\n"); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate #define TRACE_1(fac, tag, name, d1) \ 1060Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1070Sstevel@tonic-gate printf(name, (d1)); printf("\n"); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #define TRACE_2(fac, tag, name, d1, d2) \ 1100Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1110Sstevel@tonic-gate printf(name, (d1), (d2)); printf("\n"); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate #define TRACE_3(fac, tag, name, d1, d2, d3) \ 1140Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1150Sstevel@tonic-gate printf(name, (d1), (d2), (d3)); printf("\n"); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate #define TRACE_4(fac, tag, name, d1, d2, d3, d4) \ 1180Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1190Sstevel@tonic-gate printf(name, (d1), (d2), (d3), (d4)); printf("\n"); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate #define TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) \ 1220Sstevel@tonic-gate IDNTRACE((fac), (tag)); \ 1230Sstevel@tonic-gate printf(name, (d1), (d2), (d3), (d4), (d5)); printf("\n"); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate #else /* IDN_TRACE */ 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate #define TRACE_0(fac, tag, name) {} 1280Sstevel@tonic-gate #define TRACE_1(fac, tag, name, d1) {} 1290Sstevel@tonic-gate #define TRACE_2(fac, tag, name, d1, d2) {} 1300Sstevel@tonic-gate #define TRACE_3(fac, tag, name, d1, d2, d3) {} 1310Sstevel@tonic-gate #define TRACE_4(fac, tag, name, d1, d2, d3, d4) {} 1320Sstevel@tonic-gate #define TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) {} 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate #endif /* IDN_TRACE */ 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate #ifdef DEBUG 1370Sstevel@tonic-gate #define DLERRORACK(qq, mm, cc, ee, xx) \ 1380Sstevel@tonic-gate { \ 1390Sstevel@tonic-gate PR_DLPI("dlpi: ERRORACK: 0x%x(%s), err = 0x%x(%s)\n", \ 1400Sstevel@tonic-gate (uint_t)(cc), dlprim2str(cc), \ 1410Sstevel@tonic-gate (uint_t)(ee), dlerr2str((int)(ee))); \ 1420Sstevel@tonic-gate dlerrorack((qq), (mm), (cc), (ee), (xx)); \ 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate #define DLOKACK(qq, mm, cc) \ 1450Sstevel@tonic-gate { \ 1460Sstevel@tonic-gate PR_DLPI("dlpi: OKACK: 0x%x(%s)\n", (cc), dlprim2str(cc)); \ 1470Sstevel@tonic-gate dlokack((qq), (mm), (cc)); \ 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate #define DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \ 1500Sstevel@tonic-gate { \ 1510Sstevel@tonic-gate PR_DLPI("dlpi: BINDACK: eth=%x:%x:%x:%x:%x:%x, sap=0x%x, l=%d\n", \ 1520Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \ 1530Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \ 1540Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \ 1550Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \ 1560Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \ 1570Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \ 1580Sstevel@tonic-gate (uint_t)(ss), (int)(ll)); \ 1590Sstevel@tonic-gate dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy)); \ 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate #define DLPHYSADDRACK(qq, mm, aa, ll) \ 1620Sstevel@tonic-gate { \ 1630Sstevel@tonic-gate PR_DLPI("dlpi: PHYSACK: eth=%x:%x:%x:%x:%x:%x, l=%d\n", \ 1640Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \ 1650Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \ 1660Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \ 1670Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \ 1680Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \ 1690Sstevel@tonic-gate ((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \ 1700Sstevel@tonic-gate (ll)); \ 1710Sstevel@tonic-gate dlphysaddrack((qq), (mm), (aa), (ll)); \ 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static char *dlerrstr[] = { 1750Sstevel@tonic-gate "DL_BADSAP", 1760Sstevel@tonic-gate "DL_BADADDR", 1770Sstevel@tonic-gate "DL_ACCESS", 1780Sstevel@tonic-gate "DL_OUTSTATE", 1790Sstevel@tonic-gate "DL_SYSERR", 1800Sstevel@tonic-gate "DL_BADCORR", 1810Sstevel@tonic-gate "DL_BADDATA", 1820Sstevel@tonic-gate "DL_UNSUPPORTED", 1830Sstevel@tonic-gate "DL_BADPPA", 1840Sstevel@tonic-gate "DL_BADPRIM", 1850Sstevel@tonic-gate "DL_BADQOSPARAM", 1860Sstevel@tonic-gate "DL_BADQOSTYPE", 1870Sstevel@tonic-gate "DL_BADTOKEN", 1880Sstevel@tonic-gate "DL_BOUND", 1890Sstevel@tonic-gate "DL_INITFAILED", 1900Sstevel@tonic-gate "DL_NOADDR", 1910Sstevel@tonic-gate "DL_NOTINIT", 1920Sstevel@tonic-gate "DL_UNDELIVERABLE", 1930Sstevel@tonic-gate "DL_NOTSUPPORTED", 1940Sstevel@tonic-gate "DL_TOOMANY", 1950Sstevel@tonic-gate "DL_NOTENAB", 1960Sstevel@tonic-gate "DL_BUSY", 1970Sstevel@tonic-gate "DL_NOAUTO", 1980Sstevel@tonic-gate "DL_NOXIDAUTO", 1990Sstevel@tonic-gate "DL_NOTESTAUTO", 2000Sstevel@tonic-gate "DL_XIDAUTO", 2010Sstevel@tonic-gate "DL_TESTAUTO", 2020Sstevel@tonic-gate "DL_PENDING" 2030Sstevel@tonic-gate }; 2040Sstevel@tonic-gate static int dlerrnum = (sizeof (dlerrstr) / sizeof (char *)); 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate static char * 2070Sstevel@tonic-gate dlerr2str(int err) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate if ((err < 0) || (err >= dlerrnum)) 2100Sstevel@tonic-gate return ("unknown"); 2110Sstevel@tonic-gate else 2120Sstevel@tonic-gate return (dlerrstr[err]); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate static char * 2160Sstevel@tonic-gate dlprim2str(int prim) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate char *pstr; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate switch (prim) { 2210Sstevel@tonic-gate case DL_UNITDATA_REQ: pstr = "UNITDATA_REQ"; break; 2220Sstevel@tonic-gate case DL_ATTACH_REQ: pstr = "ATTACH_REQ"; break; 2230Sstevel@tonic-gate case DL_DETACH_REQ: pstr = "DETACH_REQ"; break; 2240Sstevel@tonic-gate case DL_BIND_REQ: pstr = "BIND_REQ"; break; 2250Sstevel@tonic-gate case DL_UNBIND_REQ: pstr = "UNBIND_REQ"; break; 2260Sstevel@tonic-gate case DL_INFO_REQ: pstr = "INFO_REQ"; break; 2270Sstevel@tonic-gate case DL_PROMISCON_REQ: pstr = "PROMISCON_REQ"; break; 2280Sstevel@tonic-gate case DL_PROMISCOFF_REQ: pstr = "PROMISCOFF_REQ"; break; 2290Sstevel@tonic-gate case DL_ENABMULTI_REQ: pstr = "ENABMULTI_REQ"; break; 2300Sstevel@tonic-gate case DL_DISABMULTI_REQ: pstr = "DISABMULTI_REQ"; break; 2310Sstevel@tonic-gate case DL_PHYS_ADDR_REQ: pstr = "PHYS_ADDR_REQ"; break; 2320Sstevel@tonic-gate case DL_SET_PHYS_ADDR_REQ: 2330Sstevel@tonic-gate pstr = "SET_PHYS_ADDR_REQ"; break; 2340Sstevel@tonic-gate default: pstr = "unsupported"; break; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate return (pstr); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate #else /* DEBUG */ 2390Sstevel@tonic-gate #define DLERRORACK(qq, mm, cc, ee, xx) \ 2400Sstevel@tonic-gate (dlerrorack((qq), (mm), (cc), (ee), (xx))) 2410Sstevel@tonic-gate #define DLOKACK(qq, mm, cc) \ 2420Sstevel@tonic-gate (dlokack((qq), (mm), (cc))) 2430Sstevel@tonic-gate #define DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \ 2440Sstevel@tonic-gate (dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy))) 2450Sstevel@tonic-gate #define DLPHYSADDRACK(qq, mm, aa, ll) \ 2460Sstevel@tonic-gate (dlphysaddrack((qq), (mm), (aa), (ll))) 2470Sstevel@tonic-gate #endif /* DEBUG */ 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate #define IDNDL_ADDR_IS_MULTICAST(ap) (((ap)->ether_addr_octet[0] & 01) == 1) 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * MIB II broadcast/multicast packets 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate #define IS_BROADCAST(ehp) \ 2540Sstevel@tonic-gate (ether_cmp(&(ehp)->ether_dhost, ðerbroadcastaddr) == 0) 2550Sstevel@tonic-gate #define IS_MULTICAST(ehp) \ 2560Sstevel@tonic-gate IDNDL_ADDR_IS_MULTICAST(&(ehp)->ether_dhost) 2570Sstevel@tonic-gate #define BUMP_InNUcast(sip, ehp) \ 2580Sstevel@tonic-gate if (IS_BROADCAST(ehp)) { \ 2590Sstevel@tonic-gate (sip)->si_kstat.si_brdcstrcv++; \ 2600Sstevel@tonic-gate } else if (IS_MULTICAST(ehp)) { \ 2610Sstevel@tonic-gate (sip)->si_kstat.si_multircv++; \ 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate #define BUMP_OutNUcast(sip, ehp) \ 2640Sstevel@tonic-gate if (IS_BROADCAST(ehp)) { \ 2650Sstevel@tonic-gate (sip)->si_kstat.si_brdcstxmt++; \ 2660Sstevel@tonic-gate } else if (IS_MULTICAST(ehp)) { \ 2670Sstevel@tonic-gate (sip)->si_kstat.si_multixmt++; \ 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * Function prototypes. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate static int idndl_ioc_hdr_info(queue_t *, mblk_t *, int *); 2740Sstevel@tonic-gate static void idndl_areq(queue_t *, mblk_t *); 2750Sstevel@tonic-gate static void idndl_dreq(queue_t *, mblk_t *); 2760Sstevel@tonic-gate static void idndl_breq(queue_t *, mblk_t *); 2770Sstevel@tonic-gate static void idndl_ubreq(queue_t *, mblk_t *); 2780Sstevel@tonic-gate static void idndl_ireq(queue_t *, mblk_t *); 2790Sstevel@tonic-gate static void idndl_ponreq(queue_t *, mblk_t *); 2800Sstevel@tonic-gate static void idndl_poffreq(queue_t *, mblk_t *); 2810Sstevel@tonic-gate static void idndl_emreq(queue_t *, mblk_t *); 2820Sstevel@tonic-gate static void idndl_dmreq(queue_t *, mblk_t *); 2830Sstevel@tonic-gate static void idndl_pareq(queue_t *, mblk_t *); 2840Sstevel@tonic-gate #ifdef notdef 2850Sstevel@tonic-gate static void idndl_spareq(queue_t *, mblk_t *); 2860Sstevel@tonic-gate #endif /* notdef */ 2870Sstevel@tonic-gate static void idndl_udreq(queue_t *, mblk_t *); 2880Sstevel@tonic-gate static void serror(dev_info_t *dip, int idnerr, char *fmt, ...); 2890Sstevel@tonic-gate static mblk_t *idndl_addudind(struct idn *, mblk_t *, struct ether_addr *, 2900Sstevel@tonic-gate struct ether_addr *, int, ulong_t); 2910Sstevel@tonic-gate static void idndl_setipq(struct idn *); 2920Sstevel@tonic-gate static int idndl_mcmatch(struct idnstr *, struct ether_addr *); 2930Sstevel@tonic-gate static int idndl_stat_kstat_update(kstat_t *ksp, int rw); 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate static int _idndl_ether2domain(struct ether_addr *eap); 2960Sstevel@tonic-gate static struct idn *_idndl_ether2sip(struct ether_addr *eap); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate #define IDNSAPMATCH(sap, type, flags) ((sap == type)? 1 : \ 3000Sstevel@tonic-gate ((flags & IDNSALLSAP)? 1 : \ 3010Sstevel@tonic-gate ((sap <= ETHERMTU) && sap && (type <= ETHERMTU))? 1 : 0)) 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Our DL_INFO_ACK template. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate static dl_info_ack_t idninfoack = { 3070Sstevel@tonic-gate DL_INFO_ACK, /* dl_primitive */ 3080Sstevel@tonic-gate 0, /* dl_max_sdu (see idndl_dlpi_init()) */ 3090Sstevel@tonic-gate 0, /* dl_min_sdu */ 3100Sstevel@tonic-gate IDNADDRL, /* dl_addr_length */ 3110Sstevel@tonic-gate DL_ETHER, /* DL_OTHER, */ /* dl_mac_type */ 3120Sstevel@tonic-gate 0, /* dl_reserved */ 3130Sstevel@tonic-gate 0, /* dl_current_state */ 3140Sstevel@tonic-gate -2, /* dl_sap_length */ 3150Sstevel@tonic-gate DL_CLDLS, /* DL_CODLS? */ /* dl_service_mode */ 3160Sstevel@tonic-gate 0, /* dl_qos_length */ 3170Sstevel@tonic-gate 0, /* dl_qos_offset */ 3180Sstevel@tonic-gate 0, /* dl_range_length */ 3190Sstevel@tonic-gate 0, /* dl_range_offset */ 3200Sstevel@tonic-gate DL_STYLE2, /* dl_provider_style */ 3210Sstevel@tonic-gate sizeof (dl_info_ack_t), /* dl_addr_offset */ 3220Sstevel@tonic-gate DL_VERSION_2, /* dl_version */ 3230Sstevel@tonic-gate ETHERADDRL, /* dl_brdcst_addr_length */ 3240Sstevel@tonic-gate sizeof (dl_info_ack_t) + IDNADDRL, /* dl_brdcst_addr_offset */ 3250Sstevel@tonic-gate 0 /* dl_growth */ 3260Sstevel@tonic-gate }; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * Ethernet broadcast address definition. 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = { 3320Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 3330Sstevel@tonic-gate }; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * -------------------------------------------------- 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate void 3390Sstevel@tonic-gate idndl_localetheraddr(struct idn *sip, struct ether_addr *eap) 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate int rv; 3420Sstevel@tonic-gate int instance; 3430Sstevel@tonic-gate procname_t proc = "idndl_localetheraddr"; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate ASSERT(sip && sip->si_dip && eap); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate instance = ddi_get_instance(sip->si_dip); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate PR_DLPI("%s: getting local etheraddr...\n", proc); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate rv = idndl_domain_etheraddr(idn.localid, instance, eap); 3520Sstevel@tonic-gate ASSERT(rv == 0); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate int 3560Sstevel@tonic-gate idndl_domain_etheraddr(int domid, int channel, struct ether_addr *eap) 3570Sstevel@tonic-gate { 3580Sstevel@tonic-gate uchar_t netid; 3590Sstevel@tonic-gate procname_t proc = "idndl_domain_etheraddr"; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate if (idn_domain[domid].dcpu == IDN_NIL_DCPU) 3620Sstevel@tonic-gate return (-1); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate netid = (uchar_t)idn_domain[domid].dnetid; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate PR_DLPI("%s: dnetid = 0x%x, channel = 0x%x\n", 3670Sstevel@tonic-gate proc, (uint_t)netid, channel); 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate #ifdef notdef 3700Sstevel@tonic-gate localetheraddr(NULL, eap); 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate PR_DLPI("%s: localetheraddr = %x:%x:%x:%x:%x:%x\n", 3730Sstevel@tonic-gate proc, eap->ether_addr_octet[0], eap->ether_addr_octet[1], 3740Sstevel@tonic-gate eap->ether_addr_octet[2], eap->ether_addr_octet[3], 3750Sstevel@tonic-gate eap->ether_addr_octet[4], eap->ether_addr_octet[5]): 3760Sstevel@tonic-gate #endif /* notdef */ 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_ZERO] = 0; 3790Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_COOKIE1] = IDNETHER_COOKIE1_VAL; 3800Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_COOKIE2] = IDNETHER_COOKIE2_VAL; 3810Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_NETID] = netid; 3820Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_CHANNEL] = (uchar_t)channel; 3830Sstevel@tonic-gate eap->ether_addr_octet[IDNETHER_RESERVED] = IDNETHER_RESERVED_VAL; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate PR_DLPI("%s: domain %d: etheraddr = %x:%x:%x:%x:%x:%x\n", 3860Sstevel@tonic-gate proc, domid, 3870Sstevel@tonic-gate eap->ether_addr_octet[0], eap->ether_addr_octet[1], 3880Sstevel@tonic-gate eap->ether_addr_octet[2], eap->ether_addr_octet[3], 3890Sstevel@tonic-gate eap->ether_addr_octet[4], eap->ether_addr_octet[5]); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate return (0); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate #ifdef DEBUG 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate static int 3980Sstevel@tonic-gate _idndl_ether2domain(struct ether_addr *eap) 3990Sstevel@tonic-gate { 4000Sstevel@tonic-gate uchar_t *eaop; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate eaop = eap->ether_addr_octet; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate ASSERT(IDNDL_ADDR_IS_MULTICAST(eap) || 4050Sstevel@tonic-gate ((eaop[IDNETHER_COOKIE1] == IDNETHER_COOKIE1_VAL) && 4060Sstevel@tonic-gate (eaop[IDNETHER_COOKIE2] == IDNETHER_COOKIE2_VAL)) || 4070Sstevel@tonic-gate ((eaop[IDNETHER_COOKIE1] == 0xff) && 4080Sstevel@tonic-gate (eaop[IDNETHER_COOKIE2] == 0xff))); 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Note that (IDN_NIL_DOMID) will be returned if ether address is 4110Sstevel@tonic-gate * a broadcast 0xff. 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate return (IDN_NETID2DOMID(eaop[IDNETHER_NETID])); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate static struct idn * 4190Sstevel@tonic-gate _idndl_ether2sip(struct ether_addr *eap) 4200Sstevel@tonic-gate { 4210Sstevel@tonic-gate int instance; 4220Sstevel@tonic-gate struct idn *sip; 4230Sstevel@tonic-gate uchar_t *eaop; 4240Sstevel@tonic-gate procname_t proc = "_idndl_ether2sip"; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate eaop = eap->ether_addr_octet; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate if (!IDNDL_ADDR_IS_MULTICAST(eap) && 4290Sstevel@tonic-gate (((eaop[IDNETHER_COOKIE1] != IDNETHER_COOKIE1_VAL) || 4300Sstevel@tonic-gate (eaop[IDNETHER_COOKIE2] != IDNETHER_COOKIE2_VAL)) && 4310Sstevel@tonic-gate ((eaop[IDNETHER_COOKIE1] != 0xff) || 4320Sstevel@tonic-gate (eaop[IDNETHER_COOKIE2] != 0xff)))) { 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate cmn_err(CE_WARN, 4350Sstevel@tonic-gate "IDN: 400: corrupted MAC header " 4360Sstevel@tonic-gate "(exp %x or 0xffff, act 0x%x)", 4370Sstevel@tonic-gate (IDNETHER_COOKIE1_VAL << 8) | 4380Sstevel@tonic-gate IDNETHER_COOKIE2_VAL, 4390Sstevel@tonic-gate (eaop[IDNETHER_COOKIE1] << 8) | 4400Sstevel@tonic-gate eaop[IDNETHER_COOKIE2]); 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate return (NULL); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (IDNDL_ADDR_IS_MULTICAST(eap)) { 4460Sstevel@tonic-gate PR_DLPI("%s: MULTICAST ADDR *** ERROR ***\n", proc); 4470Sstevel@tonic-gate sip = NULL; 4480Sstevel@tonic-gate } else if (eaop[IDNETHER_CHANNEL] == 0xff) { 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Received a broadcast. Need to manually 4510Sstevel@tonic-gate * find anybody the first running sip and use it. 4520Sstevel@tonic-gate * XXX - kind of kludgy - single threads broadcasts. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate PR_DLPI("%s: BROADCAST CHANNEL *** ERROR ***\n", proc); 4550Sstevel@tonic-gate sip = NULL; 4560Sstevel@tonic-gate } else { 4570Sstevel@tonic-gate instance = (int)eaop[IDNETHER_CHANNEL]; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate sip = IDN_INST2SIP(instance); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate return (sip); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate #endif /* DEBUG */ 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate void 4670Sstevel@tonic-gate idndl_dlpi_init() 4680Sstevel@tonic-gate { 4690Sstevel@tonic-gate procname_t proc = "idndl_dlpi_init"; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate PR_DLPI("%s: setting dl_max_sdu to %ld (0x%lx) bytes\n", 4720Sstevel@tonic-gate proc, IDN_MTU, IDN_MTU); 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * This field is dynamic because the user may 4750Sstevel@tonic-gate * want to dynamically set it _before_ an IDNnet 4760Sstevel@tonic-gate * has been established via ndd(1M). 4770Sstevel@tonic-gate */ 4780Sstevel@tonic-gate idninfoack.dl_max_sdu = IDN_MTU; 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate static int 4820Sstevel@tonic-gate idndl_stat_kstat_update(kstat_t *ksp, int rw) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate struct idn *sip; 4850Sstevel@tonic-gate struct idn_kstat_named *skp; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate sip = (struct idn *)ksp->ks_private; 4880Sstevel@tonic-gate skp = (struct idn_kstat_named *)ksp->ks_data; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate if (rw == KSTAT_WRITE) { 4910Sstevel@tonic-gate #if 0 4920Sstevel@tonic-gate bzero(&sg_kstat.gk_kstat, sizeof (sg_kstat.gk_kstat)); 4930Sstevel@tonic-gate #endif /* 0 */ 4940Sstevel@tonic-gate bzero(&sip->si_kstat, sizeof (sip->si_kstat)); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate sip->si_kstat.si_ipackets = skp->sk_ipackets.value.ul; 4970Sstevel@tonic-gate sip->si_kstat.si_ierrors = skp->sk_ierrors.value.ul; 4980Sstevel@tonic-gate sip->si_kstat.si_opackets = skp->sk_opackets.value.ul; 4990Sstevel@tonic-gate sip->si_kstat.si_oerrors = skp->sk_oerrors.value.ul; 5000Sstevel@tonic-gate sip->si_kstat.si_txcoll = skp->sk_txcoll.value.ul; 5010Sstevel@tonic-gate sip->si_kstat.si_rxcoll = skp->sk_rxcoll.value.ul; 5020Sstevel@tonic-gate sip->si_kstat.si_crc = skp->sk_crc.value.ul; 5030Sstevel@tonic-gate sip->si_kstat.si_buff = skp->sk_buff.value.ul; 5040Sstevel@tonic-gate sip->si_kstat.si_nolink = skp->sk_nolink.value.ul; 5050Sstevel@tonic-gate sip->si_kstat.si_linkdown = skp->sk_linkdown.value.ul; 5060Sstevel@tonic-gate sip->si_kstat.si_inits = skp->sk_inits.value.ul; 5070Sstevel@tonic-gate sip->si_kstat.si_nocanput = skp->sk_nocanput.value.ul; 5080Sstevel@tonic-gate sip->si_kstat.si_allocbfail = skp->sk_allocbfail.value.ul; 5090Sstevel@tonic-gate sip->si_kstat.si_notbufs = skp->sk_notbufs.value.ul; 5100Sstevel@tonic-gate sip->si_kstat.si_reclaim = skp->sk_reclaim.value.ul; 5110Sstevel@tonic-gate sip->si_kstat.si_smraddr = skp->sk_smraddr.value.ul; 5120Sstevel@tonic-gate sip->si_kstat.si_txmax = skp->sk_txmax.value.ul; 5130Sstevel@tonic-gate sip->si_kstat.si_txfull = skp->sk_txfull.value.ul; 5140Sstevel@tonic-gate sip->si_kstat.si_xdcall = skp->sk_xdcall.value.ul; 5150Sstevel@tonic-gate sip->si_kstat.si_sigsvr = skp->sk_sigsvr.value.ul; 5160Sstevel@tonic-gate sip->si_kstat.si_mboxcrc = skp->sk_mboxcrc.value.ul; 5170Sstevel@tonic-gate /* 5180Sstevel@tonic-gate * MIB II kstat variables 5190Sstevel@tonic-gate */ 5200Sstevel@tonic-gate sip->si_kstat.si_rcvbytes = skp->sk_rcvbytes.value.ul; 5210Sstevel@tonic-gate sip->si_kstat.si_xmtbytes = skp->sk_xmtbytes.value.ul; 5220Sstevel@tonic-gate sip->si_kstat.si_multircv = skp->sk_multircv.value.ul; 5230Sstevel@tonic-gate sip->si_kstat.si_multixmt = skp->sk_multixmt.value.ul; 5240Sstevel@tonic-gate sip->si_kstat.si_brdcstrcv = skp->sk_brdcstrcv.value.ul; 5250Sstevel@tonic-gate sip->si_kstat.si_brdcstxmt = skp->sk_brdcstxmt.value.ul; 5260Sstevel@tonic-gate sip->si_kstat.si_norcvbuf = skp->sk_norcvbuf.value.ul; 5270Sstevel@tonic-gate sip->si_kstat.si_noxmtbuf = skp->sk_noxmtbuf.value.ul; 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * PSARC 1997/198 : 64bit kstats 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate sip->si_kstat.si_ipackets64 = skp->sk_ipackets64.value.ull; 5320Sstevel@tonic-gate sip->si_kstat.si_opackets64 = skp->sk_opackets64.value.ull; 5330Sstevel@tonic-gate sip->si_kstat.si_rbytes64 = skp->sk_rbytes64.value.ull; 5340Sstevel@tonic-gate sip->si_kstat.si_obytes64 = skp->sk_obytes64.value.ull; 5350Sstevel@tonic-gate /* 5360Sstevel@tonic-gate * PSARC 1997/247 : RFC 1643 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate sip->si_kstat.si_fcs_errors = skp->sk_fcs_errors.value.ul; 5390Sstevel@tonic-gate sip->si_kstat.si_macxmt_errors = 5400Sstevel@tonic-gate skp->sk_macxmt_errors.value.ul; 5410Sstevel@tonic-gate sip->si_kstat.si_toolong_errors = 5420Sstevel@tonic-gate skp->sk_toolong_errors.value.ul; 5430Sstevel@tonic-gate sip->si_kstat.si_macrcv_errors = 5440Sstevel@tonic-gate skp->sk_macrcv_errors.value.ul; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate return (0); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate skp->sk_ipackets.value.ul = sip->si_kstat.si_ipackets; 5500Sstevel@tonic-gate skp->sk_ierrors.value.ul = sip->si_kstat.si_ierrors; 5510Sstevel@tonic-gate skp->sk_opackets.value.ul = sip->si_kstat.si_opackets; 5520Sstevel@tonic-gate skp->sk_oerrors.value.ul = sip->si_kstat.si_oerrors; 5530Sstevel@tonic-gate skp->sk_txcoll.value.ul = sip->si_kstat.si_txcoll; 5540Sstevel@tonic-gate skp->sk_rxcoll.value.ul = sip->si_kstat.si_rxcoll; 5550Sstevel@tonic-gate skp->sk_crc.value.ul = sip->si_kstat.si_crc; 5560Sstevel@tonic-gate skp->sk_buff.value.ul = sip->si_kstat.si_buff; 5570Sstevel@tonic-gate skp->sk_nolink.value.ul = sip->si_kstat.si_nolink; 5580Sstevel@tonic-gate skp->sk_linkdown.value.ul = sip->si_kstat.si_linkdown; 5590Sstevel@tonic-gate skp->sk_inits.value.ul = sip->si_kstat.si_inits; 5600Sstevel@tonic-gate skp->sk_nocanput.value.ul = sip->si_kstat.si_nocanput; 5610Sstevel@tonic-gate skp->sk_allocbfail.value.ul = sip->si_kstat.si_allocbfail; 5620Sstevel@tonic-gate skp->sk_notbufs.value.ul = sip->si_kstat.si_notbufs; 5630Sstevel@tonic-gate skp->sk_reclaim.value.ul = sip->si_kstat.si_reclaim; 5640Sstevel@tonic-gate skp->sk_smraddr.value.ul = sip->si_kstat.si_smraddr; 5650Sstevel@tonic-gate skp->sk_txfull.value.ul = sip->si_kstat.si_txfull; 5660Sstevel@tonic-gate skp->sk_txmax.value.ul = sip->si_kstat.si_txmax; 5670Sstevel@tonic-gate skp->sk_xdcall.value.ul = sip->si_kstat.si_xdcall; 5680Sstevel@tonic-gate skp->sk_sigsvr.value.ul = sip->si_kstat.si_sigsvr; 5690Sstevel@tonic-gate skp->sk_mboxcrc.value.ul = sip->si_kstat.si_mboxcrc; 5700Sstevel@tonic-gate /* 5710Sstevel@tonic-gate * MIB II kstat variables 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate skp->sk_rcvbytes.value.ul = sip->si_kstat.si_rcvbytes; 5740Sstevel@tonic-gate skp->sk_xmtbytes.value.ul = sip->si_kstat.si_xmtbytes; 5750Sstevel@tonic-gate skp->sk_multircv.value.ul = sip->si_kstat.si_multircv; 5760Sstevel@tonic-gate skp->sk_multixmt.value.ul = sip->si_kstat.si_multixmt; 5770Sstevel@tonic-gate skp->sk_brdcstrcv.value.ul = sip->si_kstat.si_brdcstrcv; 5780Sstevel@tonic-gate skp->sk_brdcstxmt.value.ul = sip->si_kstat.si_brdcstxmt; 5790Sstevel@tonic-gate skp->sk_norcvbuf.value.ul = sip->si_kstat.si_norcvbuf; 5800Sstevel@tonic-gate skp->sk_noxmtbuf.value.ul = sip->si_kstat.si_noxmtbuf; 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * PSARC 1997/198 : 64bit kstats 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate skp->sk_ipackets64.value.ull = sip->si_kstat.si_ipackets64; 5850Sstevel@tonic-gate skp->sk_opackets64.value.ull = sip->si_kstat.si_opackets64; 5860Sstevel@tonic-gate skp->sk_rbytes64.value.ull = sip->si_kstat.si_rbytes64; 5870Sstevel@tonic-gate skp->sk_obytes64.value.ull = sip->si_kstat.si_obytes64; 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * PSARC 1997/247 : RFC 1643 5900Sstevel@tonic-gate */ 5910Sstevel@tonic-gate skp->sk_fcs_errors.value.ul = sip->si_kstat.si_fcs_errors; 5920Sstevel@tonic-gate skp->sk_macxmt_errors.value.ul = sip->si_kstat.si_macxmt_errors; 5930Sstevel@tonic-gate skp->sk_toolong_errors.value.ul = sip->si_kstat.si_toolong_errors; 5940Sstevel@tonic-gate skp->sk_macrcv_errors.value.ul = sip->si_kstat.si_macrcv_errors; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate return (0); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate void 6000Sstevel@tonic-gate idndl_statinit(struct idn *sip) 6010Sstevel@tonic-gate { 6020Sstevel@tonic-gate struct kstat *ksp; 6030Sstevel@tonic-gate struct idn_kstat_named *skp; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate #ifdef kstat 6060Sstevel@tonic-gate if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip), 6070Sstevel@tonic-gate NULL, "net", KSTAT_TYPE_NAMED, 6080Sstevel@tonic-gate sizeof (struct idn_kstat_named) / sizeof (kstat_named_t), 6090Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT)) == NULL) { 6100Sstevel@tonic-gate #else 6110Sstevel@tonic-gate if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip), 6120Sstevel@tonic-gate NULL, "net", KSTAT_TYPE_NAMED, 6130Sstevel@tonic-gate sizeof (struct idn_kstat_named) / 6140Sstevel@tonic-gate sizeof (kstat_named_t), 0)) == NULL) { 6150Sstevel@tonic-gate #endif /* kstat */ 6160Sstevel@tonic-gate serror(sip->si_dip, 450, "kstat_create failed"); 6170Sstevel@tonic-gate return; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate sip->si_ksp = ksp; 6210Sstevel@tonic-gate skp = (struct idn_kstat_named *)(ksp->ks_data); 6220Sstevel@tonic-gate kstat_named_init(&skp->sk_ipackets, "ipackets", 6230Sstevel@tonic-gate KSTAT_DATA_ULONG); 6240Sstevel@tonic-gate kstat_named_init(&skp->sk_ierrors, "ierrors", 6250Sstevel@tonic-gate KSTAT_DATA_ULONG); 6260Sstevel@tonic-gate kstat_named_init(&skp->sk_opackets, "opackets", 6270Sstevel@tonic-gate KSTAT_DATA_ULONG); 6280Sstevel@tonic-gate kstat_named_init(&skp->sk_oerrors, "oerrors", 6290Sstevel@tonic-gate KSTAT_DATA_ULONG); 6300Sstevel@tonic-gate kstat_named_init(&skp->sk_txcoll, "collisions", 6310Sstevel@tonic-gate KSTAT_DATA_ULONG); 6320Sstevel@tonic-gate kstat_named_init(&skp->sk_rxcoll, "rx_collisions", 6330Sstevel@tonic-gate KSTAT_DATA_ULONG); 6340Sstevel@tonic-gate kstat_named_init(&skp->sk_crc, "crc", 6350Sstevel@tonic-gate KSTAT_DATA_ULONG); 6360Sstevel@tonic-gate kstat_named_init(&skp->sk_buff, "buff", 6370Sstevel@tonic-gate KSTAT_DATA_ULONG); 6380Sstevel@tonic-gate kstat_named_init(&skp->sk_nolink, "nolink", 6390Sstevel@tonic-gate KSTAT_DATA_ULONG); 6400Sstevel@tonic-gate kstat_named_init(&skp->sk_linkdown, "linkdown", 6410Sstevel@tonic-gate KSTAT_DATA_ULONG); 6420Sstevel@tonic-gate kstat_named_init(&skp->sk_inits, "inits", 6430Sstevel@tonic-gate KSTAT_DATA_ULONG); 6440Sstevel@tonic-gate kstat_named_init(&skp->sk_nocanput, "nocanput", 6450Sstevel@tonic-gate KSTAT_DATA_ULONG); 6460Sstevel@tonic-gate kstat_named_init(&skp->sk_allocbfail, "allocbfail", 6470Sstevel@tonic-gate KSTAT_DATA_ULONG); 6480Sstevel@tonic-gate kstat_named_init(&skp->sk_notbufs, "notbufs", 6490Sstevel@tonic-gate KSTAT_DATA_ULONG); 6500Sstevel@tonic-gate kstat_named_init(&skp->sk_reclaim, "reclaim", 6510Sstevel@tonic-gate KSTAT_DATA_ULONG); 6520Sstevel@tonic-gate kstat_named_init(&skp->sk_smraddr, "smraddr", 6530Sstevel@tonic-gate KSTAT_DATA_ULONG); 6540Sstevel@tonic-gate kstat_named_init(&skp->sk_txmax, "txmax", 6550Sstevel@tonic-gate KSTAT_DATA_ULONG); 6560Sstevel@tonic-gate kstat_named_init(&skp->sk_txfull, "txfull", 6570Sstevel@tonic-gate KSTAT_DATA_ULONG); 6580Sstevel@tonic-gate kstat_named_init(&skp->sk_xdcall, "xdcall", 6590Sstevel@tonic-gate KSTAT_DATA_ULONG); 6600Sstevel@tonic-gate kstat_named_init(&skp->sk_sigsvr, "sigsvr", 6610Sstevel@tonic-gate KSTAT_DATA_ULONG); 6620Sstevel@tonic-gate kstat_named_init(&skp->sk_mboxcrc, "mboxcrc", 6630Sstevel@tonic-gate KSTAT_DATA_ULONG); 6640Sstevel@tonic-gate /* 6650Sstevel@tonic-gate * MIB II kstat variables 6660Sstevel@tonic-gate */ 6670Sstevel@tonic-gate kstat_named_init(&skp->sk_rcvbytes, "rbytes", 6680Sstevel@tonic-gate KSTAT_DATA_ULONG); 6690Sstevel@tonic-gate kstat_named_init(&skp->sk_xmtbytes, "obytes", 6700Sstevel@tonic-gate KSTAT_DATA_ULONG); 6710Sstevel@tonic-gate kstat_named_init(&skp->sk_multircv, "multircv", 6720Sstevel@tonic-gate KSTAT_DATA_ULONG); 6730Sstevel@tonic-gate kstat_named_init(&skp->sk_multixmt, "multixmt", 6740Sstevel@tonic-gate KSTAT_DATA_ULONG); 6750Sstevel@tonic-gate kstat_named_init(&skp->sk_brdcstrcv, "brdcstrcv", 6760Sstevel@tonic-gate KSTAT_DATA_ULONG); 6770Sstevel@tonic-gate kstat_named_init(&skp->sk_brdcstxmt, "brdcstxmt", 6780Sstevel@tonic-gate KSTAT_DATA_ULONG); 6790Sstevel@tonic-gate kstat_named_init(&skp->sk_norcvbuf, "norcvbuf", 6800Sstevel@tonic-gate KSTAT_DATA_ULONG); 6810Sstevel@tonic-gate kstat_named_init(&skp->sk_noxmtbuf, "noxmtbuf", 6820Sstevel@tonic-gate KSTAT_DATA_ULONG); 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * PSARC 1997/198 : 64bit kstats 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate kstat_named_init(&skp->sk_ipackets64, "ipackets64", 6870Sstevel@tonic-gate KSTAT_DATA_ULONGLONG); 6880Sstevel@tonic-gate kstat_named_init(&skp->sk_opackets64, "opackets64", 6890Sstevel@tonic-gate KSTAT_DATA_ULONGLONG); 6900Sstevel@tonic-gate kstat_named_init(&skp->sk_rbytes64, "rbytes64", 6910Sstevel@tonic-gate KSTAT_DATA_ULONGLONG); 6920Sstevel@tonic-gate kstat_named_init(&skp->sk_obytes64, "obytes64", 6930Sstevel@tonic-gate KSTAT_DATA_ULONGLONG); 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * PSARC 1997/247 : RFC 1643 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate kstat_named_init(&skp->sk_fcs_errors, "fcs_errors", 6980Sstevel@tonic-gate KSTAT_DATA_ULONG); 6990Sstevel@tonic-gate kstat_named_init(&skp->sk_macxmt_errors, "macxmt_errors", 7000Sstevel@tonic-gate KSTAT_DATA_ULONG); 7010Sstevel@tonic-gate kstat_named_init(&skp->sk_toolong_errors, "toolong_errors", 7020Sstevel@tonic-gate KSTAT_DATA_ULONG); 7030Sstevel@tonic-gate kstat_named_init(&skp->sk_macrcv_errors, "macrcv_errors", 7040Sstevel@tonic-gate KSTAT_DATA_ULONG); 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate ksp->ks_update = idndl_stat_kstat_update; 7070Sstevel@tonic-gate ksp->ks_private = (void *)sip; 7080Sstevel@tonic-gate kstat_install(ksp); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate void 7120Sstevel@tonic-gate idndl_proto(queue_t *wq, mblk_t *mp) 7130Sstevel@tonic-gate { 7140Sstevel@tonic-gate union DL_primitives *dlp; 7150Sstevel@tonic-gate struct idnstr *stp; 7160Sstevel@tonic-gate t_uscalar_t prim; 7170Sstevel@tonic-gate procname_t proc = "idndl_proto"; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 7200Sstevel@tonic-gate if (MBLKL(mp) < sizeof (t_uscalar_t)) { 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * Gotta at least have enough room to hold 7230Sstevel@tonic-gate * the primitive! 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate DLERRORACK(wq, mp, -1, DL_BADPRIM, 0); 7260Sstevel@tonic-gate return; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 7290Sstevel@tonic-gate prim = dlp->dl_primitive; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_START, 7320Sstevel@tonic-gate "idndl_proto start: wq %p dlprim %X", wq, prim); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate #ifdef DEBUG 735*931Smathue PR_DLPI("%s: stp = 0x%p, wq = 0x%p, dlprim = 0x%x(%s)\n", 736*931Smathue proc, stp, wq, prim, dlprim2str(prim)); 7370Sstevel@tonic-gate #endif /* DEBUG */ 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate rw_enter(&stp->ss_rwlock, RW_WRITER); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate switch (prim) { 7420Sstevel@tonic-gate case DL_UNITDATA_REQ: 7430Sstevel@tonic-gate idndl_udreq(wq, mp); 7440Sstevel@tonic-gate break; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate case DL_ATTACH_REQ: 7470Sstevel@tonic-gate idndl_areq(wq, mp); 7480Sstevel@tonic-gate break; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate case DL_DETACH_REQ: 7510Sstevel@tonic-gate idndl_dreq(wq, mp); 7520Sstevel@tonic-gate break; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate case DL_BIND_REQ: 7550Sstevel@tonic-gate idndl_breq(wq, mp); 7560Sstevel@tonic-gate break; 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate case DL_UNBIND_REQ: 7590Sstevel@tonic-gate idndl_ubreq(wq, mp); 7600Sstevel@tonic-gate break; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate case DL_INFO_REQ: 7630Sstevel@tonic-gate idndl_ireq(wq, mp); 7640Sstevel@tonic-gate break; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate case DL_PROMISCON_REQ: 7670Sstevel@tonic-gate idndl_ponreq(wq, mp); 7680Sstevel@tonic-gate break; 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate case DL_PROMISCOFF_REQ: 7710Sstevel@tonic-gate idndl_poffreq(wq, mp); 7720Sstevel@tonic-gate break; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate case DL_ENABMULTI_REQ: 7750Sstevel@tonic-gate idndl_emreq(wq, mp); 7760Sstevel@tonic-gate break; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate case DL_DISABMULTI_REQ: 7790Sstevel@tonic-gate idndl_dmreq(wq, mp); 7800Sstevel@tonic-gate break; 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate case DL_PHYS_ADDR_REQ: 7830Sstevel@tonic-gate idndl_pareq(wq, mp); 7840Sstevel@tonic-gate break; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate #ifdef notdef 7870Sstevel@tonic-gate /* 7880Sstevel@tonic-gate * We cannot allow this in IDN-land because we 7890Sstevel@tonic-gate * rely on the ethernet (physical) address to determine 7900Sstevel@tonic-gate * where to target the message. Recall that unlike 7910Sstevel@tonic-gate * ethernet we simply cannot dump junk on the wire and 7920Sstevel@tonic-gate * expect it to automatically find its destination. 7930Sstevel@tonic-gate * In the IDN we need to target the destination. 7940Sstevel@tonic-gate * Note that if we used POINT-TO-POINT then we wouldn't 7950Sstevel@tonic-gate * have to worry about the physical address since each 7960Sstevel@tonic-gate * domain connection would have a separate queue. 7970Sstevel@tonic-gate * However, ptp then requires multiple interfaces at 7980Sstevel@tonic-gate * the appl level as opposed to a single one for all 7990Sstevel@tonic-gate * of idn. We opt for the simpler single interface (idn0). 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate case DL_SET_PHYS_ADDR_REQ: 8020Sstevel@tonic-gate idndl_spareq(wq, mp); 8030Sstevel@tonic-gate break; 8040Sstevel@tonic-gate #endif /* notdef */ 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate default: 8070Sstevel@tonic-gate DLERRORACK(wq, mp, prim, DL_UNSUPPORTED, 0); 8080Sstevel@tonic-gate break; 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_END, 8120Sstevel@tonic-gate "idnproto end: wq %p dlprim %X", wq, prim); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate rw_exit(&stp->ss_rwlock); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate int 8180Sstevel@tonic-gate idnioc_dlpi(queue_t *wq, mblk_t *mp, int *argsizep) 8190Sstevel@tonic-gate { 8200Sstevel@tonic-gate int rv = 0; 8210Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 8220Sstevel@tonic-gate struct idnstr *stp = (struct idnstr *)wq->q_ptr; 8230Sstevel@tonic-gate procname_t proc = "idnioc_dlpi"; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate *argsizep = 0; 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate switch (iocp->ioc_cmd) { 8280Sstevel@tonic-gate case DLIOCRAW: /* raw M_DATA mode */ 8290Sstevel@tonic-gate PR_DLPI("%s: cmd = DLIOCRAW\n", proc); 8300Sstevel@tonic-gate stp->ss_flags |= IDNSRAW; 8310Sstevel@tonic-gate break; 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate case DL_IOC_HDR_INFO: /* M_DATA "fastpath" info request */ 8340Sstevel@tonic-gate PR_DLPI("%s: cmd = DL_IOC_HDR_INFO\n", proc); 8350Sstevel@tonic-gate rv = idndl_ioc_hdr_info(wq, mp, argsizep); 8360Sstevel@tonic-gate break; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate default: 8390Sstevel@tonic-gate PR_DLPI("%s: invalid cmd 0x%x\n", proc, iocp->ioc_cmd); 8400Sstevel@tonic-gate rv = EINVAL; 8410Sstevel@tonic-gate break; 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate return (rv); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * M_DATA "fastpath" info request. 8480Sstevel@tonic-gate * Following the M_IOCTL mblk should come a DL_UNITDATA_REQ mblk. 8490Sstevel@tonic-gate * We ack with an M_IOCACK pointing to the original DL_UNITDATA_REQ mblk 8500Sstevel@tonic-gate * followed by an mblk containing the raw ethernet header corresponding 8510Sstevel@tonic-gate * to the destination address. Subsequently, we may receive M_DATA 8520Sstevel@tonic-gate * msgs which start with this header and may send up 8530Sstevel@tonic-gate * up M_DATA msgs with b_rptr pointing to a (ulong) group address 8540Sstevel@tonic-gate * indicator followed by the network-layer data (IP packet header). 8550Sstevel@tonic-gate * This is all selectable on a per-Stream basis. 8560Sstevel@tonic-gate */ 8570Sstevel@tonic-gate static int 8580Sstevel@tonic-gate idndl_ioc_hdr_info(queue_t *wq, mblk_t *mp, int *argsizep) 8590Sstevel@tonic-gate { 8600Sstevel@tonic-gate mblk_t *nmp; 8610Sstevel@tonic-gate struct idnstr *stp; 8620Sstevel@tonic-gate struct idndladdr *dlap; 8630Sstevel@tonic-gate dl_unitdata_req_t *dludp; 8640Sstevel@tonic-gate struct ether_header *headerp; 8650Sstevel@tonic-gate struct idn *sip; 8660Sstevel@tonic-gate int off, len; 8670Sstevel@tonic-gate int padding = 0; 8680Sstevel@tonic-gate int error; 8690Sstevel@tonic-gate procname_t proc = "idndl_ioc_hdr_info"; 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 8720Sstevel@tonic-gate sip = stp->ss_sip; 8730Sstevel@tonic-gate if (sip == NULL) { 8740Sstevel@tonic-gate PR_DLPI("%s: NULL sip (ret EINVAL)\n", proc); 8750Sstevel@tonic-gate return (EINVAL); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate error = miocpullup(mp, sizeof (dl_unitdata_req_t) + IDNADDRL); 8790Sstevel@tonic-gate if (error != 0) { 8800Sstevel@tonic-gate PR_DLPI("%s: sanity error (ret %d)\n", proc, error); 8810Sstevel@tonic-gate return (error); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate /* 8850Sstevel@tonic-gate * Sanity check the DL_UNITDATA_REQ destination address 8860Sstevel@tonic-gate * offset and length values. 8870Sstevel@tonic-gate */ 8880Sstevel@tonic-gate dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr; 8890Sstevel@tonic-gate off = dludp->dl_dest_addr_offset; 8900Sstevel@tonic-gate len = dludp->dl_dest_addr_length; 8910Sstevel@tonic-gate if (dludp->dl_primitive != DL_UNITDATA_REQ || 8920Sstevel@tonic-gate !MBLKIN(mp->b_cont, off, len) || len != IDNADDRL) { 8930Sstevel@tonic-gate PR_DLPI("%s: off(0x%x)/len(%d) error (ret EINVAL)\n", 8940Sstevel@tonic-gate proc, off, len); 8950Sstevel@tonic-gate return (EINVAL); 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate dlap = (struct idndladdr *)(mp->b_cont->b_rptr + off); 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate /* 9010Sstevel@tonic-gate * Allocate a new mblk to hold the ether header. 9020Sstevel@tonic-gate */ 9030Sstevel@tonic-gate nmp = allocb(sizeof (struct ether_header) + padding, BPRI_MED); 9040Sstevel@tonic-gate if (nmp == NULL) { 9050Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_allocbfail); 9060Sstevel@tonic-gate return (ENOMEM); 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate nmp->b_rptr += padding; 9090Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (struct ether_header); 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate /* 9120Sstevel@tonic-gate * Fill in the ether header. 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate headerp = (struct ether_header *)nmp->b_rptr; 9150Sstevel@tonic-gate ether_copy(&dlap->dl_phys, &headerp->ether_dhost); 9160Sstevel@tonic-gate ether_copy(&sip->si_ouraddr, &headerp->ether_shost); 9170Sstevel@tonic-gate headerp->ether_type = dlap->dl_sap; 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate /* 9200Sstevel@tonic-gate * Link new mblk in after the "request" mblks. 9210Sstevel@tonic-gate */ 9220Sstevel@tonic-gate linkb(mp, nmp); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate stp->ss_flags |= IDNSFAST; 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate /* 9270Sstevel@tonic-gate * XXX Don't bother calling idndl_setipq() here. 9280Sstevel@tonic-gate */ 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate if (argsizep) 9310Sstevel@tonic-gate *argsizep = msgsize(mp->b_cont); 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate return (0); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate static void 9370Sstevel@tonic-gate idndl_areq(queue_t *wq, mblk_t *mp) 9380Sstevel@tonic-gate { 9390Sstevel@tonic-gate struct idnstr *stp; 9400Sstevel@tonic-gate union DL_primitives *dlp; 9410Sstevel@tonic-gate struct idn *sip; 9420Sstevel@tonic-gate int ppa; 9430Sstevel@tonic-gate procname_t proc = "idndl_areq"; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 9460Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) { 9490Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0); 9500Sstevel@tonic-gate return; 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate if (stp->ss_state != DL_UNATTACHED) { 9540Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0); 9550Sstevel@tonic-gate return; 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate ppa = dlp->attach_req.dl_ppa; 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * Valid ppa? 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate if (ppa == -1 || qassociate(wq, ppa) != 0) { 9640Sstevel@tonic-gate PR_DLPI("%s: bad ppa %d\n", proc, ppa); 9650Sstevel@tonic-gate DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADPPA, 0); 9660Sstevel@tonic-gate return; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate mutex_enter(&idn.siplock); 9690Sstevel@tonic-gate for (sip = idn.sip; sip; sip = sip->si_nextp) { 9700Sstevel@tonic-gate if (ppa == ddi_get_instance(sip->si_dip)) 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate mutex_exit(&idn.siplock); 9740Sstevel@tonic-gate ASSERT(sip != NULL); /* qassociate() succeeded */ 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * Has device been initialized? Do so if necessary. 9780Sstevel@tonic-gate */ 9790Sstevel@tonic-gate if ((sip->si_flags & IDNRUNNING) == 0) { 9800Sstevel@tonic-gate if (idndl_init(sip)) { 9810Sstevel@tonic-gate DLERRORACK(wq, mp, dlp->dl_primitive, 9820Sstevel@tonic-gate DL_INITFAILED, 0); 9830Sstevel@tonic-gate (void) qassociate(wq, -1); 9840Sstevel@tonic-gate return; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /* 9890Sstevel@tonic-gate * Set link to device and update our state. 9900Sstevel@tonic-gate */ 9910Sstevel@tonic-gate stp->ss_sip = sip; 9920Sstevel@tonic-gate stp->ss_state = DL_UNBOUND; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate DLOKACK(wq, mp, DL_ATTACH_REQ); 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate static void 9980Sstevel@tonic-gate idndl_dreq(queue_t *wq, mblk_t *mp) 9990Sstevel@tonic-gate { 10000Sstevel@tonic-gate struct idnstr *stp; 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate if (MBLKL(mp) < DL_DETACH_REQ_SIZE) { 10050Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); 10060Sstevel@tonic-gate return; 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate if (stp->ss_state != DL_UNBOUND) { 10100Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0); 10110Sstevel@tonic-gate return; 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate idndl_dodetach(stp); 10150Sstevel@tonic-gate (void) qassociate(wq, -1); 10160Sstevel@tonic-gate DLOKACK(wq, mp, DL_DETACH_REQ); 10170Sstevel@tonic-gate } 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate /* 10200Sstevel@tonic-gate * Detach a Stream from an interface. 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate void 10230Sstevel@tonic-gate idndl_dodetach(struct idnstr *stp) 10240Sstevel@tonic-gate { 10250Sstevel@tonic-gate struct idnstr *tstp; 10260Sstevel@tonic-gate struct idn *sip; 10270Sstevel@tonic-gate int reinit = 0; 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate ASSERT(stp->ss_sip); 10300Sstevel@tonic-gate 10310Sstevel@tonic-gate sip = stp->ss_sip; 10320Sstevel@tonic-gate stp->ss_sip = NULL; 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate /* 10350Sstevel@tonic-gate * Disable promiscuous mode if on. 10360Sstevel@tonic-gate */ 10370Sstevel@tonic-gate if (stp->ss_flags & IDNSALLPHYS) { 10380Sstevel@tonic-gate stp->ss_flags &= ~IDNSALLPHYS; 10390Sstevel@tonic-gate reinit = 1; 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate /* 10430Sstevel@tonic-gate * Disable ALLMULTI mode if on. 10440Sstevel@tonic-gate */ 10450Sstevel@tonic-gate if (stp->ss_flags & IDNSALLMULTI) { 10460Sstevel@tonic-gate stp->ss_flags &= ~IDNSALLMULTI; 10470Sstevel@tonic-gate reinit = 1; 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate /* 10510Sstevel@tonic-gate * Disable any Multicast Addresses. 10520Sstevel@tonic-gate */ 10530Sstevel@tonic-gate stp->ss_mccount = 0; 10540Sstevel@tonic-gate if (stp->ss_mctab) { 10550Sstevel@tonic-gate kmem_free(stp->ss_mctab, IDNMCALLOC); 10560Sstevel@tonic-gate stp->ss_mctab = NULL; 10570Sstevel@tonic-gate reinit = 1; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * Detach from device structure. 10620Sstevel@tonic-gate * Uninit the device when no other streams are attached to it. 10630Sstevel@tonic-gate */ 10640Sstevel@tonic-gate rw_enter(&idn.struprwlock, RW_READER); 10650Sstevel@tonic-gate for (tstp = idn.strup; tstp; tstp = tstp->ss_nextp) 10660Sstevel@tonic-gate if (tstp->ss_sip == sip) 10670Sstevel@tonic-gate break; 10680Sstevel@tonic-gate rw_exit(&idn.struprwlock); 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate if (tstp == NULL) 10710Sstevel@tonic-gate idndl_uninit(sip); 10720Sstevel@tonic-gate else if (reinit) 10730Sstevel@tonic-gate (void) idndl_init(sip); 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate stp->ss_state = DL_UNATTACHED; 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate idndl_setipq(sip); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate static void 10810Sstevel@tonic-gate idndl_breq(queue_t *wq, mblk_t *mp) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate struct idnstr *stp; 10840Sstevel@tonic-gate union DL_primitives *dlp; 10850Sstevel@tonic-gate struct idn *sip; 10860Sstevel@tonic-gate struct idndladdr idnaddr; 10870Sstevel@tonic-gate t_uscalar_t sap; 10880Sstevel@tonic-gate int xidtest; 10890Sstevel@tonic-gate procname_t proc = "idndl_breq"; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate if (MBLKL(mp) < DL_BIND_REQ_SIZE) { 10940Sstevel@tonic-gate DLERRORACK(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); 10950Sstevel@tonic-gate return; 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate if (stp->ss_state != DL_UNBOUND) { 10990Sstevel@tonic-gate DLERRORACK(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0); 11000Sstevel@tonic-gate return; 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate if (dlp->bind_req.dl_service_mode != idninfoack.dl_service_mode) { 11060Sstevel@tonic-gate DLERRORACK(wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); 11070Sstevel@tonic-gate return; 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate sip = stp->ss_sip; 11110Sstevel@tonic-gate sap = dlp->bind_req.dl_sap; 11120Sstevel@tonic-gate xidtest = dlp->bind_req.dl_xidtest_flg; 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate ASSERT(sip); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate if (xidtest) { 11170Sstevel@tonic-gate DLERRORACK(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0); 11180Sstevel@tonic-gate return; 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate if (sap > ETHERTYPE_MAX) { 11220Sstevel@tonic-gate DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADSAP, 0); 11230Sstevel@tonic-gate return; 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate /* 11270Sstevel@tonic-gate * Save SAP value for this Stream and change state. 11280Sstevel@tonic-gate */ 11290Sstevel@tonic-gate stp->ss_sap = sap; 11300Sstevel@tonic-gate stp->ss_state = DL_IDLE; 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate idnaddr.dl_sap = sap; 11330Sstevel@tonic-gate ether_copy(&sip->si_ouraddr, &idnaddr.dl_phys); 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate if (IS_ETHERTYPE_IP(sap)) { 11360Sstevel@tonic-gate int channel; 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate channel = 11390Sstevel@tonic-gate (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; 11400Sstevel@tonic-gate PR_DLPI("%s: IP SAP, opening channel %d\n", proc, channel); 11410Sstevel@tonic-gate if (idn_open_channel(channel)) { 11420Sstevel@tonic-gate PR_DLPI("%s: FAILED TO OPEN CHANNEL %d\n", 11430Sstevel@tonic-gate proc, channel); 11440Sstevel@tonic-gate DLERRORACK(wq, mp, dlp->dl_primitive, DL_NOADDR, 0); 11450Sstevel@tonic-gate return; 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate DLBINDACK(wq, mp, sap, &idnaddr, IDNADDRL, 0, 0); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate idndl_setipq(sip); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate static void 11540Sstevel@tonic-gate idndl_ubreq(queue_t *wq, mblk_t *mp) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate struct idnstr *stp; 11570Sstevel@tonic-gate procname_t proc = "idndl_ubreq"; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) { 11620Sstevel@tonic-gate DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0); 11630Sstevel@tonic-gate return; 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate if (stp->ss_state != DL_IDLE) { 11670Sstevel@tonic-gate DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); 11680Sstevel@tonic-gate return; 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate stp->ss_state = DL_UNBOUND; 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate if (IS_ETHERTYPE_IP(stp->ss_sap)) { 11740Sstevel@tonic-gate struct idn *sip; 11750Sstevel@tonic-gate int channel; 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate sip = stp->ss_sip; 11780Sstevel@tonic-gate channel = 11790Sstevel@tonic-gate (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; 11800Sstevel@tonic-gate PR_DLPI("%s: IP SAP, unbinding channel %d\n", proc, channel); 11810Sstevel@tonic-gate /* 11820Sstevel@tonic-gate * We need to do an "soft" close since there's a 11830Sstevel@tonic-gate * potential that we've been called by one of the 11840Sstevel@tonic-gate * IDN data server/dispatcher threads! We'll deadlock 11850Sstevel@tonic-gate * if we attempt a "hard" close of the channel from here. 11860Sstevel@tonic-gate */ 11870Sstevel@tonic-gate idn_close_channel(channel, IDNCHAN_SOFT_CLOSE); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate stp->ss_sap = 0; 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate DLOKACK(wq, mp, DL_UNBIND_REQ); 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate idndl_setipq(stp->ss_sip); 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate static void 11980Sstevel@tonic-gate idndl_ireq(queue_t *wq, mblk_t *mp) 11990Sstevel@tonic-gate { 12000Sstevel@tonic-gate struct idnstr *stp; 12010Sstevel@tonic-gate dl_info_ack_t *dlip; 12020Sstevel@tonic-gate struct idndladdr *dlap; 12030Sstevel@tonic-gate struct ether_addr *ep; 12040Sstevel@tonic-gate int size; 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate if (MBLKL(mp) < DL_INFO_REQ_SIZE) { 12090Sstevel@tonic-gate DLERRORACK(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0); 12100Sstevel@tonic-gate return; 12110Sstevel@tonic-gate } 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate /* 12140Sstevel@tonic-gate * Exchange current msg for a DL_INFO_ACK. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate size = sizeof (dl_info_ack_t) + IDNADDRL + ETHERADDRL; 12170Sstevel@tonic-gate if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL) 12180Sstevel@tonic-gate return; 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate /* 12210Sstevel@tonic-gate * Fill in the DL_INFO_ACK fields and reply. 12220Sstevel@tonic-gate */ 12230Sstevel@tonic-gate dlip = (dl_info_ack_t *)mp->b_rptr; 12240Sstevel@tonic-gate ASSERT(idninfoack.dl_max_sdu); 12250Sstevel@tonic-gate *dlip = idninfoack; 12260Sstevel@tonic-gate dlip->dl_current_state = stp->ss_state; 12270Sstevel@tonic-gate dlap = (struct idndladdr *)(mp->b_rptr + dlip->dl_addr_offset); 12280Sstevel@tonic-gate dlap->dl_sap = stp->ss_sap; 12290Sstevel@tonic-gate if (stp->ss_sip) { 12300Sstevel@tonic-gate ether_copy(&stp->ss_sip->si_ouraddr, &dlap->dl_phys); 12310Sstevel@tonic-gate } else { 12320Sstevel@tonic-gate bzero(&dlap->dl_phys, ETHERADDRL); 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate ep = (struct ether_addr *)(mp->b_rptr + dlip->dl_brdcst_addr_offset); 12350Sstevel@tonic-gate ether_copy(ðerbroadcastaddr, ep); 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate qreply(wq, mp); 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate static void 12410Sstevel@tonic-gate idndl_ponreq(queue_t *wq, mblk_t *mp) 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate struct idnstr *stp; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) { 12480Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); 12490Sstevel@tonic-gate return; 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate 12520Sstevel@tonic-gate switch (((dl_promiscon_req_t *)mp->b_rptr)->dl_level) { 12530Sstevel@tonic-gate case DL_PROMISC_PHYS: 12540Sstevel@tonic-gate stp->ss_flags |= IDNSALLPHYS; 12550Sstevel@tonic-gate break; 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate case DL_PROMISC_SAP: 12580Sstevel@tonic-gate stp->ss_flags |= IDNSALLSAP; 12590Sstevel@tonic-gate break; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate case DL_PROMISC_MULTI: 12620Sstevel@tonic-gate stp->ss_flags |= IDNSALLMULTI; 12630Sstevel@tonic-gate break; 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate default: 12660Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0); 12670Sstevel@tonic-gate return; 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate if (stp->ss_sip) 12710Sstevel@tonic-gate (void) idndl_init(stp->ss_sip); 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate if (stp->ss_sip) 12740Sstevel@tonic-gate idndl_setipq(stp->ss_sip); 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate DLOKACK(wq, mp, DL_PROMISCON_REQ); 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate static void 12800Sstevel@tonic-gate idndl_poffreq(queue_t *wq, mblk_t *mp) 12810Sstevel@tonic-gate { 12820Sstevel@tonic-gate struct idnstr *stp; 12830Sstevel@tonic-gate int flag; 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) { 12880Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); 12890Sstevel@tonic-gate return; 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate switch (((dl_promiscoff_req_t *)mp->b_rptr)->dl_level) { 12930Sstevel@tonic-gate case DL_PROMISC_PHYS: 12940Sstevel@tonic-gate flag = IDNSALLPHYS; 12950Sstevel@tonic-gate break; 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate case DL_PROMISC_SAP: 12980Sstevel@tonic-gate flag = IDNSALLSAP; 12990Sstevel@tonic-gate break; 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate case DL_PROMISC_MULTI: 13020Sstevel@tonic-gate flag = IDNSALLMULTI; 13030Sstevel@tonic-gate break; 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate default: 13060Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0); 13070Sstevel@tonic-gate return; 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate if ((stp->ss_flags & flag) == 0) { 13110Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); 13120Sstevel@tonic-gate return; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate stp->ss_flags &= ~flag; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate if (stp->ss_sip) 13180Sstevel@tonic-gate (void) idndl_init(stp->ss_sip); 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate if (stp->ss_sip) 13210Sstevel@tonic-gate idndl_setipq(stp->ss_sip); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate DLOKACK(wq, mp, DL_PROMISCOFF_REQ); 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate static void 13270Sstevel@tonic-gate idndl_emreq(queue_t *wq, mblk_t *mp) 13280Sstevel@tonic-gate { 13290Sstevel@tonic-gate struct idnstr *stp; 13300Sstevel@tonic-gate union DL_primitives *dlp; 13310Sstevel@tonic-gate struct ether_addr *addrp; 13320Sstevel@tonic-gate int off; 13330Sstevel@tonic-gate int len; 13340Sstevel@tonic-gate int i; 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate if (MBLKL(mp) < DL_ENABMULTI_REQ_SIZE) { 13390Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); 13400Sstevel@tonic-gate return; 13410Sstevel@tonic-gate } 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate if (stp->ss_state == DL_UNATTACHED) { 13440Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); 13450Sstevel@tonic-gate return; 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 13490Sstevel@tonic-gate len = dlp->enabmulti_req.dl_addr_length; 13500Sstevel@tonic-gate off = dlp->enabmulti_req.dl_addr_offset; 13510Sstevel@tonic-gate addrp = (struct ether_addr *)(mp->b_rptr + off); 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate if ((len != ETHERADDRL) || 13540Sstevel@tonic-gate !MBLKIN(mp, off, len) || 13550Sstevel@tonic-gate !IDNDL_ADDR_IS_MULTICAST(addrp)) { 13560Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); 13570Sstevel@tonic-gate return; 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate if ((stp->ss_mccount + 1) >= IDNMAXMC) { 13610Sstevel@tonic-gate DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_TOOMANY, 0); 13620Sstevel@tonic-gate return; 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate /* 13660Sstevel@tonic-gate * Allocate table on first request. 13670Sstevel@tonic-gate */ 13680Sstevel@tonic-gate if (stp->ss_mctab == NULL) 13690Sstevel@tonic-gate stp->ss_mctab = kmem_alloc(IDNMCALLOC, KM_SLEEP); 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate /* 13720Sstevel@tonic-gate * Check to see if the address is already in the table. 13730Sstevel@tonic-gate * Bug 1209733: 13740Sstevel@tonic-gate * If present in the table, add the entry to the end of the table 13750Sstevel@tonic-gate * and return without initializing the hardware. 13760Sstevel@tonic-gate */ 13770Sstevel@tonic-gate for (i = 0; i < stp->ss_mccount; i++) { 13780Sstevel@tonic-gate if (ether_cmp(&stp->ss_mctab[i], addrp) == 0) { 13790Sstevel@tonic-gate stp->ss_mctab[stp->ss_mccount++] = *addrp; 13800Sstevel@tonic-gate DLOKACK(wq, mp, DL_ENABMULTI_REQ); 13810Sstevel@tonic-gate return; 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate stp->ss_mctab[stp->ss_mccount++] = *addrp; 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate (void) idndl_init(stp->ss_sip); 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate DLOKACK(wq, mp, DL_ENABMULTI_REQ); 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate static void 13930Sstevel@tonic-gate idndl_dmreq(queue_t *wq, mblk_t *mp) 13940Sstevel@tonic-gate { 13950Sstevel@tonic-gate struct idnstr *stp; 13960Sstevel@tonic-gate union DL_primitives *dlp; 13970Sstevel@tonic-gate struct ether_addr *addrp; 13980Sstevel@tonic-gate int off; 13990Sstevel@tonic-gate int len; 14000Sstevel@tonic-gate int i; 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate if (MBLKL(mp) < DL_DISABMULTI_REQ_SIZE) { 14050Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); 14060Sstevel@tonic-gate return; 14070Sstevel@tonic-gate } 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate if (stp->ss_state == DL_UNATTACHED) { 14100Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0); 14110Sstevel@tonic-gate return; 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 14150Sstevel@tonic-gate len = dlp->disabmulti_req.dl_addr_length; 14160Sstevel@tonic-gate off = dlp->disabmulti_req.dl_addr_offset; 14170Sstevel@tonic-gate addrp = (struct ether_addr *)(mp->b_rptr + off); 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate if ((len != ETHERADDRL) || !MBLKIN(mp, off, len)) { 14200Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); 14210Sstevel@tonic-gate return; 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate /* 14250Sstevel@tonic-gate * Find the address in the multicast table for this Stream 14260Sstevel@tonic-gate * and delete it by shifting all subsequent multicast 14270Sstevel@tonic-gate * table entries over one. 14280Sstevel@tonic-gate */ 14290Sstevel@tonic-gate for (i = 0; i < stp->ss_mccount; i++) 14300Sstevel@tonic-gate if (ether_cmp(addrp, &stp->ss_mctab[i]) == 0) { 14310Sstevel@tonic-gate bcopy(&stp->ss_mctab[i+1], 14320Sstevel@tonic-gate &stp->ss_mctab[i], 14330Sstevel@tonic-gate ((stp->ss_mccount - i) * 14340Sstevel@tonic-gate sizeof (struct ether_addr))); 14350Sstevel@tonic-gate stp->ss_mccount--; 14360Sstevel@tonic-gate (void) idndl_init(stp->ss_sip); 14370Sstevel@tonic-gate DLOKACK(wq, mp, DL_DISABMULTI_REQ); 14380Sstevel@tonic-gate return; 14390Sstevel@tonic-gate } 14400Sstevel@tonic-gate DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_NOTENAB, 0); 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate static void 14440Sstevel@tonic-gate idndl_pareq(queue_t *wq, mblk_t *mp) 14450Sstevel@tonic-gate { 14460Sstevel@tonic-gate struct idnstr *stp; 14470Sstevel@tonic-gate union DL_primitives *dlp; 14480Sstevel@tonic-gate int type; 14490Sstevel@tonic-gate struct idn *sip; 14500Sstevel@tonic-gate struct ether_addr addr; 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) { 14550Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); 14560Sstevel@tonic-gate return; 14570Sstevel@tonic-gate } 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 14600Sstevel@tonic-gate type = dlp->physaddr_req.dl_addr_type; 14610Sstevel@tonic-gate sip = stp->ss_sip; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (sip == NULL) { 14640Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 14650Sstevel@tonic-gate return; 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate switch (type) { 14690Sstevel@tonic-gate case DL_FACT_PHYS_ADDR: 14700Sstevel@tonic-gate idndl_localetheraddr(sip, &addr); 14710Sstevel@tonic-gate break; 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate case DL_CURR_PHYS_ADDR: 14740Sstevel@tonic-gate ether_copy(&sip->si_ouraddr, &addr); 14750Sstevel@tonic-gate break; 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate default: 14780Sstevel@tonic-gate DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_NOTSUPPORTED, 0); 14790Sstevel@tonic-gate return; 14800Sstevel@tonic-gate } 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate DLPHYSADDRACK(wq, mp, &addr, ETHERADDRL); 14830Sstevel@tonic-gate } 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate #ifdef notdef 14860Sstevel@tonic-gate static void 14870Sstevel@tonic-gate idndl_spareq(queue_t *wq, mblk_t *mp) 14880Sstevel@tonic-gate { 14890Sstevel@tonic-gate struct idnstr *stp; 14900Sstevel@tonic-gate union DL_primitives *dlp; 14910Sstevel@tonic-gate int off; 14920Sstevel@tonic-gate int len; 14930Sstevel@tonic-gate struct ether_addr *addrp; 14940Sstevel@tonic-gate struct idn *sip; 14950Sstevel@tonic-gate 14960Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate if (MBLKL(mp) < DL_SET_PHYS_ADDR_REQ_SIZE) { 14990Sstevel@tonic-gate DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); 15000Sstevel@tonic-gate return; 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 15040Sstevel@tonic-gate len = dlp->set_physaddr_req.dl_addr_length; 15050Sstevel@tonic-gate off = dlp->set_physaddr_req.dl_addr_offset; 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate if (!MBLKIN(mp, off, len)) { 15080Sstevel@tonic-gate DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); 15090Sstevel@tonic-gate return; 15100Sstevel@tonic-gate } 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate addrp = (struct ether_addr *)(mp->b_rptr + off); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate /* 15150Sstevel@tonic-gate * Error if length of address isn't right or the address 15160Sstevel@tonic-gate * specified is a multicast or broadcast address. 15170Sstevel@tonic-gate */ 15180Sstevel@tonic-gate if ((len != ETHERADDRL) || 15190Sstevel@tonic-gate IDNDL_ADDR_IS_MULTICAST(addrp) || 15200Sstevel@tonic-gate (ether_cmp(addrp, ðerbroadcastaddr) == 0)) { 15210Sstevel@tonic-gate DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0); 15220Sstevel@tonic-gate return; 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate /* 15260Sstevel@tonic-gate * Error if this stream is not attached to a device. 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate if ((sip = stp->ss_sip) == NULL) { 15290Sstevel@tonic-gate DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 15300Sstevel@tonic-gate return; 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate /* 15340Sstevel@tonic-gate * Set new interface local address and re-init device. 15350Sstevel@tonic-gate * This is destructive to any other streams attached 15360Sstevel@tonic-gate * to this device. 15370Sstevel@tonic-gate */ 15380Sstevel@tonic-gate ether_copy(addrp, &sip->si_ouraddr); 15390Sstevel@tonic-gate (void) idndl_init(stp->ss_sip); 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate DLOKACK(wq, mp, DL_SET_PHYS_ADDR_REQ); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate #endif /* notdef */ 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate static void 15460Sstevel@tonic-gate idndl_udreq(queue_t *wq, mblk_t *mp) 15470Sstevel@tonic-gate { 15480Sstevel@tonic-gate struct idnstr *stp; 15490Sstevel@tonic-gate register struct idn *sip; 15500Sstevel@tonic-gate register dl_unitdata_req_t *dludp; 15510Sstevel@tonic-gate mblk_t *nmp; 15520Sstevel@tonic-gate struct idndladdr *dlap; 15530Sstevel@tonic-gate struct ether_header *headerp; 15540Sstevel@tonic-gate t_uscalar_t off, len; 15550Sstevel@tonic-gate t_uscalar_t sap; 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 15580Sstevel@tonic-gate sip = stp->ss_sip; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate if (stp->ss_state != DL_IDLE) { 15610Sstevel@tonic-gate DLERRORACK(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); 15620Sstevel@tonic-gate return; 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate dludp = (dl_unitdata_req_t *)mp->b_rptr; 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate off = dludp->dl_dest_addr_offset; 15680Sstevel@tonic-gate len = dludp->dl_dest_addr_length; 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate /* 15710Sstevel@tonic-gate * Validate destination address format. 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate if (!MBLKIN(mp, off, len) || (len != IDNADDRL)) { 15740Sstevel@tonic-gate dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADADDR, 0); 15750Sstevel@tonic-gate return; 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * Error if no M_DATA follows. 15800Sstevel@tonic-gate */ 15810Sstevel@tonic-gate nmp = mp->b_cont; 15820Sstevel@tonic-gate if (nmp == NULL) { 15830Sstevel@tonic-gate dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADDATA, 0); 15840Sstevel@tonic-gate return; 15850Sstevel@tonic-gate } 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate dlap = (struct idndladdr *)(mp->b_rptr + off); 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate /* 15900Sstevel@tonic-gate * Create ethernet header by either prepending it onto the 15910Sstevel@tonic-gate * next mblk if potential, or reusing the M_PROTO block if not. 15920Sstevel@tonic-gate */ 15930Sstevel@tonic-gate if ((DB_REF(nmp) == 1) && 15940Sstevel@tonic-gate (MBLKHEAD(nmp) >= sizeof (struct ether_header)) && 15950Sstevel@tonic-gate (((ulong_t)nmp->b_rptr & 0x1) == 0)) { 15960Sstevel@tonic-gate nmp->b_rptr -= sizeof (struct ether_header); 15970Sstevel@tonic-gate headerp = (struct ether_header *)nmp->b_rptr; 15980Sstevel@tonic-gate ether_copy(&dlap->dl_phys, &headerp->ether_dhost); 15990Sstevel@tonic-gate ether_copy(&sip->si_ouraddr, &headerp->ether_shost); 16000Sstevel@tonic-gate sap = dlap->dl_sap; 16010Sstevel@tonic-gate freeb(mp); 16020Sstevel@tonic-gate mp = nmp; 16030Sstevel@tonic-gate } else { 16040Sstevel@tonic-gate DB_TYPE(mp) = M_DATA; 16050Sstevel@tonic-gate headerp = (struct ether_header *)mp->b_rptr; 16060Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct ether_header); 16070Sstevel@tonic-gate ether_copy(&dlap->dl_phys, &headerp->ether_dhost); 16080Sstevel@tonic-gate ether_copy(&sip->si_ouraddr, &headerp->ether_shost); 16090Sstevel@tonic-gate sap = dlap->dl_sap; 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate 16120Sstevel@tonic-gate /* 16130Sstevel@tonic-gate * For transmitting, the driver looks at the 16140Sstevel@tonic-gate * sap field of the DL_BIND_REQ being 0 in addition to the type 16150Sstevel@tonic-gate * field in the range [0-1500]. If either is true, then the driver 16160Sstevel@tonic-gate * computes the length of the message, not including initial M_PROTO 16170Sstevel@tonic-gate * mblk (message block), of all subsequent DL_UNITDATA_REQ messages and 16180Sstevel@tonic-gate * transmits 802.3 frames that have this value in the MAC frame header 16190Sstevel@tonic-gate * length field. 16200Sstevel@tonic-gate */ 16210Sstevel@tonic-gate if ((sap <= ETHERMTU) || (stp->ss_sap == 0)) 16220Sstevel@tonic-gate headerp->ether_type = (msgsize(mp) - 16230Sstevel@tonic-gate sizeof (struct ether_header)); 16240Sstevel@tonic-gate else 16250Sstevel@tonic-gate headerp->ether_type = sap; 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate /* 16280Sstevel@tonic-gate * The data transfer code requires only READ access (idn_wput_data). 16290Sstevel@tonic-gate */ 16300Sstevel@tonic-gate rw_downgrade(&stp->ss_rwlock); 16310Sstevel@tonic-gate (void) idndl_start(wq, mp, sip); 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate int 16350Sstevel@tonic-gate idndl_start(queue_t *wq, register mblk_t *mp, register struct idn *sip) 16360Sstevel@tonic-gate { 16370Sstevel@tonic-gate int rv = 0; 16380Sstevel@tonic-gate int flags; 16390Sstevel@tonic-gate int broadcast = 0; 16400Sstevel@tonic-gate int goagain = 0; 16410Sstevel@tonic-gate int goqueue = 0; 16420Sstevel@tonic-gate int msgcount; 16430Sstevel@tonic-gate char channel; 16440Sstevel@tonic-gate mblk_t *nmp = NULL; 16450Sstevel@tonic-gate int domid; 16460Sstevel@tonic-gate domainset_t domset; 16470Sstevel@tonic-gate idn_netaddr_t netaddr; 16480Sstevel@tonic-gate struct idnstr *stp; 16490Sstevel@tonic-gate struct ether_header *ehp; 16500Sstevel@tonic-gate procname_t proc = "idndl_start"; 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA); 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate stp = (struct idnstr *)wq->q_ptr; 16550Sstevel@tonic-gate ASSERT(sip == stp->ss_sip); 16560Sstevel@tonic-gate flags = sip->si_flags; 16570Sstevel@tonic-gate channel = (char)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate ASSERT(RW_READ_HELD(&stp->ss_rwlock)); 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate if ((flags & (IDNRUNNING|IDNPROMISC)) != IDNRUNNING) { 16620Sstevel@tonic-gate if (!(flags & IDNRUNNING)) 16630Sstevel@tonic-gate goto requeue; 16640Sstevel@tonic-gate } 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * Translate an IDN ethernet address into a domainid 16680Sstevel@tonic-gate * and idnaddr. 16690Sstevel@tonic-gate */ 16700Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 16710Sstevel@tonic-gate domid = IDNDL_ETHER2DOMAIN(&ehp->ether_dhost); 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate /* 16740Sstevel@tonic-gate * update MIB II statistics 16750Sstevel@tonic-gate */ 16760Sstevel@tonic-gate BUMP_OutNUcast(sip, ehp); 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate PR_DLPI("%s: ether %x:%x:%x:%x:%x:%x (domid = %d)\n", 16790Sstevel@tonic-gate proc, ehp->ether_dhost.ether_addr_octet[0], 16800Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[1], 16810Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[2], 16820Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[3], 16830Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[4], 16840Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[5], 16850Sstevel@tonic-gate domid); 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate netaddr.net.chan = channel; 16880Sstevel@tonic-gate PR_DLPI("%s: source channel = %d\n", proc, (int)channel); 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate if ((ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) || 16910Sstevel@tonic-gate IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost)) { 16920Sstevel@tonic-gate /* 16930Sstevel@tonic-gate * Caller wants to broadcast! 16940Sstevel@tonic-gate * XXX - Send to everybody but ourself??? 16950Sstevel@tonic-gate */ 16960Sstevel@tonic-gate PR_DLPI("%s: broadcast/multicast requested!!!\n", proc); 16970Sstevel@tonic-gate domset = ~DOMAINSET(idn.localid); 16980Sstevel@tonic-gate broadcast = 1; 16990Sstevel@tonic-gate netaddr.net.netid = IDN_BROADCAST_ALLNETID; 17000Sstevel@tonic-gate if ((flags & IDNPROMISC) && 17010Sstevel@tonic-gate ((nmp = copymsg(mp)) == NULL)) { 17020Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_allocbfail); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate } else if (domid != IDN_NIL_DOMID) { 17060Sstevel@tonic-gate domset = DOMAINSET(domid); 17070Sstevel@tonic-gate netaddr.net.netid = idn_domain[domid].dnetid; 17080Sstevel@tonic-gate if ((flags & IDNPROMISC) && 17090Sstevel@tonic-gate ((nmp = copymsg(mp)) == NULL)) { 17100Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_allocbfail); 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate } else { 17130Sstevel@tonic-gate #ifdef DEBUG 17140Sstevel@tonic-gate int netid; 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate netid = (int) 17170Sstevel@tonic-gate ehp->ether_dhost.ether_addr_octet[IDNETHER_NETID]; 17180Sstevel@tonic-gate PR_DLPI("%s: no domain found for netid 0x%x\n", 17190Sstevel@tonic-gate proc, netid); 17200Sstevel@tonic-gate #endif /* DEBUG */ 17210Sstevel@tonic-gate goto bad; 17220Sstevel@tonic-gate } 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate PR_DLPI("%s: target domainset = 0x%x\n", proc, domset); 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate if ((domset == 0) && (domid == IDN_NIL_DOMID)) { 17270Sstevel@tonic-gate PR_DLPI("%s: not connected to any domains!! Bailing\n", 17280Sstevel@tonic-gate proc); 17290Sstevel@tonic-gate goto bad; 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate /* 17320Sstevel@tonic-gate * XXX - Need to find a better way to handle broadcasting. 17330Sstevel@tonic-gate * Should be able to take advantage of the fact that 17340Sstevel@tonic-gate * we can broadcast XDC's (xdc_some). Need to use 17350Sstevel@tonic-gate * atomic counter (semaphore) instead of binary 17360Sstevel@tonic-gate * "owner" flag, or perhaps domain specific owner bytes. 17370Sstevel@tonic-gate * 17380Sstevel@tonic-gate * Transfer the data. 17390Sstevel@tonic-gate */ 17400Sstevel@tonic-gate msgcount = 0; 17410Sstevel@tonic-gate if (!broadcast) 17420Sstevel@tonic-gate goto noloop; 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate for (domid = 0; domid < MAX_DOMAINS; domid++) { 17450Sstevel@tonic-gate if (!DOMAIN_IN_SET(domset, domid)) 17460Sstevel@tonic-gate continue; 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate noloop: 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate if (idn_domain[domid].dcpu == IDN_NIL_DCPU) { 17510Sstevel@tonic-gate if (broadcast) 17520Sstevel@tonic-gate continue; 17530Sstevel@tonic-gate else 17540Sstevel@tonic-gate break; 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate rv = idn_send_data(domid, netaddr, wq, mp); 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate switch (rv) { 17600Sstevel@tonic-gate case IDNXMIT_LOOP: /* handled in loopback */ 17610Sstevel@tonic-gate msgcount++; 17620Sstevel@tonic-gate break; 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate case IDNXMIT_OKAY: /* handled, okay to free */ 17650Sstevel@tonic-gate msgcount++; 17660Sstevel@tonic-gate break; 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate case IDNXMIT_RETRY: 17690Sstevel@tonic-gate if (!broadcast) 17700Sstevel@tonic-gate goto tryagain; 17710Sstevel@tonic-gate goagain++; 17720Sstevel@tonic-gate break; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate case IDNXMIT_REQUEUE: 17750Sstevel@tonic-gate if (!broadcast) 17760Sstevel@tonic-gate goto requeue; 17770Sstevel@tonic-gate goqueue++; 17780Sstevel@tonic-gate break; 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate default: 17810Sstevel@tonic-gate if (!broadcast) 17820Sstevel@tonic-gate goto bad; 17830Sstevel@tonic-gate break; 17840Sstevel@tonic-gate } 17850Sstevel@tonic-gate if (!broadcast) 17860Sstevel@tonic-gate break; 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate if (msgcount == 0) 17900Sstevel@tonic-gate if (goqueue) 17910Sstevel@tonic-gate goto requeue; 17920Sstevel@tonic-gate else if (goagain) 17930Sstevel@tonic-gate goto tryagain; 17940Sstevel@tonic-gate else 17950Sstevel@tonic-gate goto bad; 17960Sstevel@tonic-gate 17970Sstevel@tonic-gate if ((flags & IDNPROMISC) && nmp) 17980Sstevel@tonic-gate idndl_sendup(sip, nmp, idndl_paccept); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate freemsg(mp); 18010Sstevel@tonic-gate 18020Sstevel@tonic-gate PR_DLPI("%s: successful transmit to domainset 0x%x.\n", 18030Sstevel@tonic-gate proc, domset); 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate return (0); 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate bad: 18080Sstevel@tonic-gate PR_DLPI("%s: bad transmission to domainset 0x%x, dropping msg.\n", 18090Sstevel@tonic-gate proc, domset); 18100Sstevel@tonic-gate if (nmp) 18110Sstevel@tonic-gate freemsg(nmp); 18120Sstevel@tonic-gate freemsg(mp); 18130Sstevel@tonic-gate qenable(wq); 18140Sstevel@tonic-gate return (1); 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate requeue: 18170Sstevel@tonic-gate PR_DLPI("%s: requeue for domainset 0x%x, no qenable\n", 18180Sstevel@tonic-gate proc, domset); 18190Sstevel@tonic-gate if (nmp) 18200Sstevel@tonic-gate freemsg(nmp); 18210Sstevel@tonic-gate if (putbq(wq, mp) == 0) 18220Sstevel@tonic-gate freemsg(mp); 18230Sstevel@tonic-gate return (1); 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate tryagain: 18260Sstevel@tonic-gate PR_DLPI("%s: try again to domainset 0x%x, putbq.\n", 18270Sstevel@tonic-gate proc, domset); 18280Sstevel@tonic-gate if (nmp) 18290Sstevel@tonic-gate freemsg(nmp); 18300Sstevel@tonic-gate if (putbq(wq, mp) == 0) 18310Sstevel@tonic-gate freemsg(mp); 18320Sstevel@tonic-gate qenable(wq); 18330Sstevel@tonic-gate return (1); 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate /* 18370Sstevel@tonic-gate * Called by: idnh_recv_data, idn_recv_mboxdata. 18380Sstevel@tonic-gate */ 18390Sstevel@tonic-gate void 18400Sstevel@tonic-gate idndl_read(struct idn *sip, mblk_t *mp) 18410Sstevel@tonic-gate { 18420Sstevel@tonic-gate struct ether_header *ehp; 18430Sstevel@tonic-gate queue_t *ip4q; 18440Sstevel@tonic-gate queue_t *ip6q; 18450Sstevel@tonic-gate int pktlen; 18460Sstevel@tonic-gate procname_t proc = "idndl_read"; 18470Sstevel@tonic-gate 1848*931Smathue PR_DLPI("%s: incoming msgsize = %lu, msgdsize = %lu\n", 18490Sstevel@tonic-gate proc, msgsize(mp), msgdsize(mp)); 18500Sstevel@tonic-gate 18510Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 18520Sstevel@tonic-gate if (sip == NULL) 18530Sstevel@tonic-gate sip = IDNDL_ETHER2SIP(&ehp->ether_dhost); 18540Sstevel@tonic-gate if (sip == NULL) { 18550Sstevel@tonic-gate /* 18560Sstevel@tonic-gate * If the sip is NULL, then I don't have a connection 18570Sstevel@tonic-gate * for this network. No point in sending the message 18580Sstevel@tonic-gate * up. 18590Sstevel@tonic-gate */ 18600Sstevel@tonic-gate PR_DLPI("%s: no plumbing to send message through.\n", 18610Sstevel@tonic-gate proc); 18620Sstevel@tonic-gate freemsg(mp); 18630Sstevel@tonic-gate return; 18640Sstevel@tonic-gate } 18650Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_ipackets); 18660Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_ipackets64); 18670Sstevel@tonic-gate /* 18680Sstevel@tonic-gate * update MIB II statistics 18690Sstevel@tonic-gate */ 18700Sstevel@tonic-gate pktlen = mp->b_wptr - mp->b_rptr; 18710Sstevel@tonic-gate BUMP_InNUcast(sip, ehp); 18720Sstevel@tonic-gate IDN_KSTAT_ADD(sip, si_rcvbytes, pktlen); 18730Sstevel@tonic-gate IDN_KSTAT_ADD(sip, si_rbytes64, (uint64_t)pktlen); 18740Sstevel@tonic-gate 18750Sstevel@tonic-gate ip4q = sip->si_ip4q; 18760Sstevel@tonic-gate ip6q = sip->si_ip6q; 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate if (IS_ETHERTYPE_IPV4(ehp->ether_type) && 18790Sstevel@tonic-gate !IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) && 18800Sstevel@tonic-gate ip4q && 18810Sstevel@tonic-gate canputnext(ip4q)) { 18820Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header); 18830Sstevel@tonic-gate (void) putnext(ip4q, mp); 18840Sstevel@tonic-gate /*LINTED*/ 18850Sstevel@tonic-gate } else if (IS_ETHERTYPE_IPV6(ehp->ether_type) && 18860Sstevel@tonic-gate !IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) && 18870Sstevel@tonic-gate ip6q && 18880Sstevel@tonic-gate canputnext(ip6q)) { 18890Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header); 18900Sstevel@tonic-gate (void) putnext(ip6q, mp); 18910Sstevel@tonic-gate } else { 18920Sstevel@tonic-gate /* 18930Sstevel@tonic-gate * Strip the PADs for 802.3 18940Sstevel@tonic-gate */ 18950Sstevel@tonic-gate pktlen = ehp->ether_type + sizeof (struct ether_header); 18960Sstevel@tonic-gate PR_DLPI("%s: stripping PADs for 802.3 (pktlen=%d)\n", 18970Sstevel@tonic-gate proc, pktlen); 18980Sstevel@tonic-gate if (pktlen < ETHERMIN) 18990Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + pktlen; 19000Sstevel@tonic-gate idndl_sendup(sip, mp, idndl_accept); 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate } 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate int 19050Sstevel@tonic-gate idndl_init(struct idn *sip) 19060Sstevel@tonic-gate { 19070Sstevel@tonic-gate struct idnstr *stp; 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate if (sip->si_flags & IDNSUSPENDED) 19100Sstevel@tonic-gate (void) ddi_dev_is_needed(sip->si_dip, 0, 1); 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate sip->si_flags = 0; 19130Sstevel@tonic-gate sip->si_wantw = 0; 19140Sstevel@tonic-gate 19150Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_inits); 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate rw_enter(&idn.struprwlock, RW_WRITER); 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate for (stp = idn.strup; stp; stp = stp->ss_nextp) { 19200Sstevel@tonic-gate if ((stp->ss_sip == sip) && (stp->ss_flags & IDNSALLPHYS)) { 19210Sstevel@tonic-gate sip->si_flags |= IDNPROMISC; 19220Sstevel@tonic-gate break; 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate } 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate sip->si_flags |= IDNRUNNING; 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate mutex_enter(&idn.sipwenlock); 19290Sstevel@tonic-gate idndl_wenable(sip); 19300Sstevel@tonic-gate mutex_exit(&idn.sipwenlock); 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate rw_exit(&idn.struprwlock); 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate return (!(sip->si_flags & IDNRUNNING)); 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate void 19380Sstevel@tonic-gate idndl_uninit(struct idn *sip) 19390Sstevel@tonic-gate { 19400Sstevel@tonic-gate int channel; 19410Sstevel@tonic-gate procname_t proc = "idndl_uninit"; 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate sip->si_flags &= ~IDNRUNNING; 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate channel = (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL]; 19460Sstevel@tonic-gate PR_DLPI("%s: IP SAP, uninit channel %d\n", proc, channel); 19470Sstevel@tonic-gate /* 19480Sstevel@tonic-gate * A uninit is a hard close of an interface. 19490Sstevel@tonic-gate */ 19500Sstevel@tonic-gate idn_close_channel(channel, IDNCHAN_HARD_CLOSE); 19510Sstevel@tonic-gate } 19520Sstevel@tonic-gate 19530Sstevel@tonic-gate /* 19540Sstevel@tonic-gate * Send packet upstream. 19550Sstevel@tonic-gate * Assume mp->b_rptr points to ether_header. 19560Sstevel@tonic-gate */ 19570Sstevel@tonic-gate void 19580Sstevel@tonic-gate idndl_sendup(struct idn *sip, mblk_t *mp, struct idnstr *(*acceptfunc)()) 19590Sstevel@tonic-gate { 19600Sstevel@tonic-gate int type; 19610Sstevel@tonic-gate struct ether_addr *dhostp, *shostp; 19620Sstevel@tonic-gate struct idnstr *stp, *nstp; 19630Sstevel@tonic-gate mblk_t *nmp; 19640Sstevel@tonic-gate ulong_t isgroupaddr; 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_START, "idnsendup start"); 19670Sstevel@tonic-gate 19680Sstevel@tonic-gate dhostp = &((struct ether_header *)mp->b_rptr)->ether_dhost; 19690Sstevel@tonic-gate shostp = &((struct ether_header *)mp->b_rptr)->ether_shost; 19700Sstevel@tonic-gate type = ((struct ether_header *)mp->b_rptr)->ether_type; 19710Sstevel@tonic-gate 19720Sstevel@tonic-gate isgroupaddr = IDNDL_ADDR_IS_MULTICAST(dhostp); 19730Sstevel@tonic-gate 19740Sstevel@tonic-gate /* 19750Sstevel@tonic-gate * While holding a reader lock on the linked list of streams structures, 19760Sstevel@tonic-gate * attempt to match the address criteria for each stream 19770Sstevel@tonic-gate * and pass up the raw M_DATA ("fastpath") or a DL_UNITDATA_IND. 19780Sstevel@tonic-gate */ 19790Sstevel@tonic-gate 19800Sstevel@tonic-gate rw_enter(&idn.struprwlock, RW_READER); 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate if ((stp = (*acceptfunc)(idn.strup, sip, type, dhostp)) == NULL) { 19830Sstevel@tonic-gate rw_exit(&idn.struprwlock); 19840Sstevel@tonic-gate freemsg(mp); 19850Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end"); 19860Sstevel@tonic-gate return; 19870Sstevel@tonic-gate } 19880Sstevel@tonic-gate 19890Sstevel@tonic-gate /* 19900Sstevel@tonic-gate * Loop on matching open streams until (*acceptfunc)() returns NULL. 19910Sstevel@tonic-gate */ 19920Sstevel@tonic-gate for (; nstp = (*acceptfunc)(stp->ss_nextp, sip, type, dhostp); 19930Sstevel@tonic-gate stp = nstp) { 19940Sstevel@tonic-gate 19950Sstevel@tonic-gate if (canputnext(stp->ss_rq) == 0) { 19960Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_nocanput); 19970Sstevel@tonic-gate continue; 19980Sstevel@tonic-gate } 19990Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL) 20000Sstevel@tonic-gate nmp = copymsg(mp); 20010Sstevel@tonic-gate if (nmp) { 20020Sstevel@tonic-gate if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) { 20030Sstevel@tonic-gate nmp->b_rptr += sizeof (struct ether_header); 20040Sstevel@tonic-gate (void) putnext(stp->ss_rq, nmp); 20050Sstevel@tonic-gate } else if (stp->ss_flags & IDNSRAW) { 20060Sstevel@tonic-gate (void) putnext(stp->ss_rq, nmp); 20070Sstevel@tonic-gate } else if ((nmp = idndl_addudind(sip, nmp, shostp, 20080Sstevel@tonic-gate dhostp, type, isgroupaddr))) { 20090Sstevel@tonic-gate (void) putnext(stp->ss_rq, nmp); 20100Sstevel@tonic-gate } 20110Sstevel@tonic-gate } else { 20120Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_allocbfail); 20130Sstevel@tonic-gate } 20140Sstevel@tonic-gate } 20150Sstevel@tonic-gate 20160Sstevel@tonic-gate 20170Sstevel@tonic-gate /* 20180Sstevel@tonic-gate * Do the last one. 20190Sstevel@tonic-gate */ 20200Sstevel@tonic-gate if (canputnext(stp->ss_rq)) { 20210Sstevel@tonic-gate if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) { 20220Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header); 20230Sstevel@tonic-gate (void) putnext(stp->ss_rq, mp); 20240Sstevel@tonic-gate } else if (stp->ss_flags & IDNSRAW) { 20250Sstevel@tonic-gate (void) putnext(stp->ss_rq, mp); 20260Sstevel@tonic-gate } else if ((mp = idndl_addudind(sip, mp, shostp, dhostp, 20270Sstevel@tonic-gate type, isgroupaddr))) { 20280Sstevel@tonic-gate (void) putnext(stp->ss_rq, mp); 20290Sstevel@tonic-gate } 20300Sstevel@tonic-gate } else { 20310Sstevel@tonic-gate freemsg(mp); 20320Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_nocanput); 20330Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_norcvbuf); /* MIB II */ 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate rw_exit(&idn.struprwlock); 20370Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end"); 20380Sstevel@tonic-gate } 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate /* 20410Sstevel@tonic-gate * Test upstream destination sap and address match. 20420Sstevel@tonic-gate */ 20430Sstevel@tonic-gate struct idnstr * 20440Sstevel@tonic-gate idndl_accept(register struct idnstr *stp, register struct idn *sip, 20450Sstevel@tonic-gate int type, struct ether_addr *addrp) 20460Sstevel@tonic-gate { 20470Sstevel@tonic-gate t_uscalar_t sap; 20480Sstevel@tonic-gate uint_t flags; 20490Sstevel@tonic-gate 20500Sstevel@tonic-gate for (; stp; stp = stp->ss_nextp) { 20510Sstevel@tonic-gate sap = stp->ss_sap; 20520Sstevel@tonic-gate flags = stp->ss_flags; 20530Sstevel@tonic-gate 20540Sstevel@tonic-gate if ((stp->ss_sip == sip) && IDNSAPMATCH(sap, type, flags)) 20550Sstevel@tonic-gate if ((ether_cmp(addrp, &sip->si_ouraddr) == 0) || 20560Sstevel@tonic-gate (ether_cmp(addrp, ðerbroadcastaddr) == 0) || 20570Sstevel@tonic-gate (flags & IDNSALLPHYS) || 20580Sstevel@tonic-gate idndl_mcmatch(stp, addrp)) 20590Sstevel@tonic-gate return (stp); 20600Sstevel@tonic-gate } 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate return (NULL); 20630Sstevel@tonic-gate } 20640Sstevel@tonic-gate 20650Sstevel@tonic-gate /* 20660Sstevel@tonic-gate * Test upstream destination sap and address match for IDNSALLPHYS only. 20670Sstevel@tonic-gate */ 20680Sstevel@tonic-gate /* ARGSUSED3 */ 20690Sstevel@tonic-gate struct idnstr * 20700Sstevel@tonic-gate idndl_paccept(register struct idnstr *stp, register struct idn *sip, 20710Sstevel@tonic-gate int type, struct ether_addr *addrp) 20720Sstevel@tonic-gate { 20730Sstevel@tonic-gate t_uscalar_t sap; 20740Sstevel@tonic-gate uint_t flags; 20750Sstevel@tonic-gate 20760Sstevel@tonic-gate for (; stp; stp = stp->ss_nextp) { 20770Sstevel@tonic-gate sap = stp->ss_sap; 20780Sstevel@tonic-gate flags = stp->ss_flags; 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate if ((stp->ss_sip == sip) && 20810Sstevel@tonic-gate IDNSAPMATCH(sap, type, flags) && 20820Sstevel@tonic-gate (flags & IDNSALLPHYS)) 20830Sstevel@tonic-gate return (stp); 20840Sstevel@tonic-gate } 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate return (NULL); 20870Sstevel@tonic-gate } 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate /* 20900Sstevel@tonic-gate * Set or clear the device ipq pointer. 20910Sstevel@tonic-gate * Assumes IPv4 and IPv6 are IDNSFAST. 20920Sstevel@tonic-gate */ 20930Sstevel@tonic-gate static void 20940Sstevel@tonic-gate idndl_setipq(struct idn *sip) 20950Sstevel@tonic-gate { 20960Sstevel@tonic-gate struct idnstr *stp; 20970Sstevel@tonic-gate int ok4 = 1; 20980Sstevel@tonic-gate int ok6 = 1; 20990Sstevel@tonic-gate queue_t *ip4q = NULL; 21000Sstevel@tonic-gate queue_t *ip6q = NULL; 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate rw_enter(&idn.struprwlock, RW_READER); 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate for (stp = idn.strup; stp; stp = stp->ss_nextp) { 21050Sstevel@tonic-gate if (stp->ss_sip == sip) { 21060Sstevel@tonic-gate if (stp->ss_flags & (IDNSALLPHYS|IDNSALLSAP)) { 21070Sstevel@tonic-gate ok4 = 0; 21080Sstevel@tonic-gate ok6 = 0; 21090Sstevel@tonic-gate break; 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate if (IS_ETHERTYPE_IPV4(stp->ss_sap)) { 21120Sstevel@tonic-gate if (ip4q == NULL) 21130Sstevel@tonic-gate ip4q = stp->ss_rq; 21140Sstevel@tonic-gate else 21150Sstevel@tonic-gate ok4 = 0; 21160Sstevel@tonic-gate /*LINTED*/ 21170Sstevel@tonic-gate } else if (IS_ETHERTYPE_IPV6(stp->ss_sap)) { 21180Sstevel@tonic-gate if (ip6q == NULL) 21190Sstevel@tonic-gate ip6q = stp->ss_rq; 21200Sstevel@tonic-gate else 21210Sstevel@tonic-gate ok6 = 0; 21220Sstevel@tonic-gate } 21230Sstevel@tonic-gate } 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate 21260Sstevel@tonic-gate rw_exit(&idn.struprwlock); 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate if (ok4) 21290Sstevel@tonic-gate sip->si_ip4q = ip4q; 21300Sstevel@tonic-gate else 21310Sstevel@tonic-gate sip->si_ip4q = NULL; 21320Sstevel@tonic-gate if (ok6) 21330Sstevel@tonic-gate sip->si_ip6q = ip6q; 21340Sstevel@tonic-gate else 21350Sstevel@tonic-gate sip->si_ip6q = NULL; 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate /* 21390Sstevel@tonic-gate * Prefix msg with a DL_UNITDATA_IND mblk and return the new msg. 21400Sstevel@tonic-gate */ 21410Sstevel@tonic-gate static mblk_t * 21420Sstevel@tonic-gate idndl_addudind(struct idn *sip, mblk_t *mp, 21430Sstevel@tonic-gate struct ether_addr *shostp, struct ether_addr *dhostp, 21440Sstevel@tonic-gate int type, ulong_t isgroupaddr) 21450Sstevel@tonic-gate { 21460Sstevel@tonic-gate dl_unitdata_ind_t *dludindp; 21470Sstevel@tonic-gate struct idndladdr *dlap; 21480Sstevel@tonic-gate mblk_t *nmp; 21490Sstevel@tonic-gate int size; 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_START, "idndl_addudind start"); 21520Sstevel@tonic-gate 21530Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header); 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate /* 21560Sstevel@tonic-gate * Allocate an M_PROTO mblk for the DL_UNITDATA_IND. 21570Sstevel@tonic-gate */ 21580Sstevel@tonic-gate size = sizeof (dl_unitdata_ind_t) + IDNADDRL + IDNADDRL; 21590Sstevel@tonic-gate nmp = allocb(IDNROUNDUP(IDNHEADROOM + size, sizeof (double)), BPRI_LO); 21600Sstevel@tonic-gate if (nmp == NULL) { 21610Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_allocbfail); 21620Sstevel@tonic-gate IDN_KSTAT_INC(sip, si_ierrors); 21630Sstevel@tonic-gate if (idn_debug) 21640Sstevel@tonic-gate serror(sip->si_dip, 451, "allocb failed"); 21650Sstevel@tonic-gate freemsg(mp); 21660Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end"); 21670Sstevel@tonic-gate return (NULL); 21680Sstevel@tonic-gate } 21690Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO; 21700Sstevel@tonic-gate nmp->b_wptr = nmp->b_datap->db_lim; 21710Sstevel@tonic-gate nmp->b_rptr = nmp->b_wptr - size; 21720Sstevel@tonic-gate 21730Sstevel@tonic-gate /* 21740Sstevel@tonic-gate * Construct a DL_UNITDATA_IND primitive. 21750Sstevel@tonic-gate */ 21760Sstevel@tonic-gate dludindp = (dl_unitdata_ind_t *)nmp->b_rptr; 21770Sstevel@tonic-gate dludindp->dl_primitive = DL_UNITDATA_IND; 21780Sstevel@tonic-gate dludindp->dl_dest_addr_length = IDNADDRL; 21790Sstevel@tonic-gate dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t); 21800Sstevel@tonic-gate dludindp->dl_src_addr_length = IDNADDRL; 21810Sstevel@tonic-gate dludindp->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + IDNADDRL; 21820Sstevel@tonic-gate dludindp->dl_group_address = isgroupaddr; 21830Sstevel@tonic-gate 21840Sstevel@tonic-gate dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t)); 21850Sstevel@tonic-gate ether_copy(dhostp, &dlap->dl_phys); 21860Sstevel@tonic-gate dlap->dl_sap = (ushort_t)type; 21870Sstevel@tonic-gate 21880Sstevel@tonic-gate dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t) 21890Sstevel@tonic-gate + IDNADDRL); 21900Sstevel@tonic-gate ether_copy(shostp, &dlap->dl_phys); 21910Sstevel@tonic-gate dlap->dl_sap = (ushort_t)type; 21920Sstevel@tonic-gate 21930Sstevel@tonic-gate /* 21940Sstevel@tonic-gate * Link the M_PROTO and M_DATA together. 21950Sstevel@tonic-gate */ 21960Sstevel@tonic-gate nmp->b_cont = mp; 21970Sstevel@tonic-gate TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end"); 21980Sstevel@tonic-gate return (nmp); 21990Sstevel@tonic-gate } 22000Sstevel@tonic-gate 22010Sstevel@tonic-gate /* 22020Sstevel@tonic-gate * Return TRUE if the given multicast address is one 22030Sstevel@tonic-gate * of those that this particular Stream is interested in. 22040Sstevel@tonic-gate */ 22050Sstevel@tonic-gate static int 22060Sstevel@tonic-gate idndl_mcmatch(register struct idnstr *stp, register struct ether_addr *addrp) 22070Sstevel@tonic-gate { 22080Sstevel@tonic-gate register struct ether_addr *mctab; 22090Sstevel@tonic-gate register int mccount; 22100Sstevel@tonic-gate register int i; 22110Sstevel@tonic-gate 22120Sstevel@tonic-gate /* 22130Sstevel@tonic-gate * Return FALSE if not a multicast address. 22140Sstevel@tonic-gate */ 22150Sstevel@tonic-gate if (!IDNDL_ADDR_IS_MULTICAST(addrp)) 22160Sstevel@tonic-gate return (0); 22170Sstevel@tonic-gate 22180Sstevel@tonic-gate /* 22190Sstevel@tonic-gate * Check if all multicasts have been enabled for this Stream 22200Sstevel@tonic-gate */ 22210Sstevel@tonic-gate if (stp->ss_flags & IDNSALLMULTI) 22220Sstevel@tonic-gate return (1); 22230Sstevel@tonic-gate 22240Sstevel@tonic-gate /* 22250Sstevel@tonic-gate * Return FALSE if no multicast addresses enabled for this Stream. 22260Sstevel@tonic-gate */ 22270Sstevel@tonic-gate if (stp->ss_mccount == 0) 22280Sstevel@tonic-gate return (0); 22290Sstevel@tonic-gate 22300Sstevel@tonic-gate /* 22310Sstevel@tonic-gate * Otherwise, find it in the table. 22320Sstevel@tonic-gate */ 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate mccount = stp->ss_mccount; 22350Sstevel@tonic-gate mctab = stp->ss_mctab; 22360Sstevel@tonic-gate 22370Sstevel@tonic-gate for (i = 0; i < mccount; i++) 22380Sstevel@tonic-gate if (!ether_cmp(addrp, &mctab[i])) 22390Sstevel@tonic-gate return (1); 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate return (0); 22420Sstevel@tonic-gate } 22430Sstevel@tonic-gate 22440Sstevel@tonic-gate /* 22450Sstevel@tonic-gate * Start xmit on any msgs previously enqueued on any write queues. 22460Sstevel@tonic-gate * If the caller passes NULL, then we need to check all 22470Sstevel@tonic-gate * our interfaces. 22480Sstevel@tonic-gate */ 22490Sstevel@tonic-gate void 22500Sstevel@tonic-gate idndl_wenable(struct idn *sip) 22510Sstevel@tonic-gate { 22520Sstevel@tonic-gate struct idnstr *stp; 22530Sstevel@tonic-gate queue_t *wq; 22540Sstevel@tonic-gate 22550Sstevel@tonic-gate /* 22560Sstevel@tonic-gate * Order of wantw accesses is important. 22570Sstevel@tonic-gate */ 22580Sstevel@tonic-gate ASSERT((sip == NULL) ? RW_LOCK_HELD(&idn.struprwlock) : 1); 22590Sstevel@tonic-gate ASSERT(MUTEX_HELD(&idn.sipwenlock)); 22600Sstevel@tonic-gate 22610Sstevel@tonic-gate do { 22620Sstevel@tonic-gate if (sip) 22630Sstevel@tonic-gate sip->si_wantw = 0; 22640Sstevel@tonic-gate for (stp = idn.strup; stp; stp = stp->ss_nextp) { 22650Sstevel@tonic-gate if ((!sip || (stp->ss_sip == sip)) && 22660Sstevel@tonic-gate stp->ss_rq && ((wq = WR(stp->ss_rq))->q_first)) 22670Sstevel@tonic-gate qenable(wq); 22680Sstevel@tonic-gate } 22690Sstevel@tonic-gate } while (sip && sip->si_wantw); 22700Sstevel@tonic-gate } 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate /*VARARGS*/ 22730Sstevel@tonic-gate static void 22740Sstevel@tonic-gate serror(dev_info_t *dip, int idnerr, char *fmt, ...) 22750Sstevel@tonic-gate { 22760Sstevel@tonic-gate static long last; 22770Sstevel@tonic-gate static char *lastfmt; 22780Sstevel@tonic-gate char msg_buffer[255]; 22790Sstevel@tonic-gate va_list ap; 22800Sstevel@tonic-gate time_t now; 22810Sstevel@tonic-gate 22820Sstevel@tonic-gate /* 22830Sstevel@tonic-gate * Don't print same error message too often. 22840Sstevel@tonic-gate */ 22850Sstevel@tonic-gate now = gethrestime_sec(); 22860Sstevel@tonic-gate if ((last == (now & ~1)) && (lastfmt == fmt)) 22870Sstevel@tonic-gate return; 22880Sstevel@tonic-gate 22890Sstevel@tonic-gate last = now & ~1; 22900Sstevel@tonic-gate lastfmt = fmt; 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate va_start(ap, fmt); 22930Sstevel@tonic-gate (void) vsprintf(msg_buffer, fmt, ap); 22940Sstevel@tonic-gate cmn_err(CE_CONT, "IDN: %d: %s%d: %s\n", 22950Sstevel@tonic-gate idnerr, ddi_get_name(dip), 22960Sstevel@tonic-gate ddi_get_instance(dip), msg_buffer); 22970Sstevel@tonic-gate va_end(ap); 22980Sstevel@tonic-gate } 2299