xref: /titanic_50/usr/src/uts/sun4u/starfire/io/idn_dlpi.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*07d06da5SSurya Prakki  * Common Development and Distribution License (the "License").
6*07d06da5SSurya Prakki  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * IDN DLPI support (based on QE implementation).
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/debug.h>
317c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/stream.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate #ifdef xxx_trace
377c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
387c478bd9Sstevel@tonic-gate #endif /* xxx_trace */
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
457c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
467c478bd9Sstevel@tonic-gate #include <sys/time.h>
477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sys/idn.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #ifdef	IPV6
527c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IPV4(x)	((x) == ETHERTYPE_IP)
537c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IPV6(x)	((x) == ETHERTYPE_IPV6)
547c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IP(x)	(IS_ETHERTYPE_IPV4(x) || IS_ETHERTYPE_IPV6(x))
557c478bd9Sstevel@tonic-gate #else
567c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IPV4(x)	((x) == ETHERTYPE_IP)
577c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IPV6(x)	(0)
587c478bd9Sstevel@tonic-gate #define	IS_ETHERTYPE_IP		IS_ETHERTYPE_IPV4
597c478bd9Sstevel@tonic-gate #endif /* IPV6 */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #ifdef IDN_TRACE
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * This stuff should go into <sys/vtrace.h>
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate #define	TR_FAC_IDN		100
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * TR_FAC_IDN tags
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate #define	TR_IDN_OPEN		0
707c478bd9Sstevel@tonic-gate #define	TR_IDN_CLOSE		1
717c478bd9Sstevel@tonic-gate #define	TR_IDN_WPUT_START	2
727c478bd9Sstevel@tonic-gate #define	TR_IDN_WPUT_END		3
737c478bd9Sstevel@tonic-gate #define	TR_IDN_WSRV_START	4
747c478bd9Sstevel@tonic-gate #define	TR_IDN_WSRV_END		5
757c478bd9Sstevel@tonic-gate #define	TR_IDN_START_START	6
767c478bd9Sstevel@tonic-gate #define	TR_IDN_START_END	7
777c478bd9Sstevel@tonic-gate #define	TR_IDN_INTR_START	8
787c478bd9Sstevel@tonic-gate #define	TR_IDN_INTR_END		9
797c478bd9Sstevel@tonic-gate #define	TR_IDN_READ_START	10
807c478bd9Sstevel@tonic-gate #define	TR_IDN_READ_END		11
817c478bd9Sstevel@tonic-gate #define	TR_IDN_SENDUP_START	12
827c478bd9Sstevel@tonic-gate #define	TR_IDN_SENDUP_END	13
837c478bd9Sstevel@tonic-gate #define	TR_IDN_ADDUDIND_START	14
847c478bd9Sstevel@tonic-gate #define	TR_IDN_ADDUDIND_END	15
857c478bd9Sstevel@tonic-gate #define	TR_IDN_GETBUF_START	16
867c478bd9Sstevel@tonic-gate #define	TR_IDN_GETBUF_END	17
877c478bd9Sstevel@tonic-gate #define	TR_IDN_FREEBUF_START	18
887c478bd9Sstevel@tonic-gate #define	TR_IDN_FREEBUF_END	19
897c478bd9Sstevel@tonic-gate #define	TR_IDN_PROTO_START	20
907c478bd9Sstevel@tonic-gate #define	TR_IDN_PROTO_END	21
917c478bd9Sstevel@tonic-gate #define	TR_IDN_INIT_START	22
927c478bd9Sstevel@tonic-gate #define	TR_IDN_INIT_END		23
937c478bd9Sstevel@tonic-gate #define	TR_IDN_PROTO_IN		24
947c478bd9Sstevel@tonic-gate #define	TR_IDN_PROTO_OUT	25
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #define	IDNTRACE(fac, tag)	(printf("idn.TRACE: "))
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	TRACE_0(fac, tag, name) \
997c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1007c478bd9Sstevel@tonic-gate 	printf(name); printf("\n");
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #define	TRACE_1(fac, tag, name, d1) \
1037c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1047c478bd9Sstevel@tonic-gate 	printf(name, (d1)); printf("\n");
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #define	TRACE_2(fac, tag, name, d1, d2) \
1077c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1087c478bd9Sstevel@tonic-gate 	printf(name, (d1), (d2)); printf("\n");
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #define	TRACE_3(fac, tag, name, d1, d2, d3) \
1117c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1127c478bd9Sstevel@tonic-gate 	printf(name, (d1), (d2), (d3)); printf("\n");
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #define	TRACE_4(fac, tag, name, d1, d2, d3, d4) \
1157c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1167c478bd9Sstevel@tonic-gate 	printf(name, (d1), (d2), (d3), (d4)); printf("\n");
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate #define	TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) \
1197c478bd9Sstevel@tonic-gate 	IDNTRACE((fac), (tag)); \
1207c478bd9Sstevel@tonic-gate 	printf(name, (d1), (d2), (d3), (d4), (d5)); printf("\n");
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #else /* IDN_TRACE */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #define	TRACE_0(fac, tag, name) 			{}
1257c478bd9Sstevel@tonic-gate #define	TRACE_1(fac, tag, name, d1) 			{}
1267c478bd9Sstevel@tonic-gate #define	TRACE_2(fac, tag, name, d1, d2) 		{}
1277c478bd9Sstevel@tonic-gate #define	TRACE_3(fac, tag, name, d1, d2, d3) 		{}
1287c478bd9Sstevel@tonic-gate #define	TRACE_4(fac, tag, name, d1, d2, d3, d4) 	{}
1297c478bd9Sstevel@tonic-gate #define	TRACE_5(fac, tag, name, d1, d2, d3, d4, d5) 	{}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate #endif /* IDN_TRACE */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate #ifdef DEBUG
1347c478bd9Sstevel@tonic-gate #define	DLERRORACK(qq, mm, cc, ee, xx) \
1357c478bd9Sstevel@tonic-gate { \
1367c478bd9Sstevel@tonic-gate 	PR_DLPI("dlpi: ERRORACK: 0x%x(%s), err = 0x%x(%s)\n", \
1377c478bd9Sstevel@tonic-gate 		(uint_t)(cc), dlprim2str(cc), \
1387c478bd9Sstevel@tonic-gate 		(uint_t)(ee), dlerr2str((int)(ee))); \
1397c478bd9Sstevel@tonic-gate 	dlerrorack((qq), (mm), (cc), (ee), (xx)); \
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate #define	DLOKACK(qq, mm, cc) \
1427c478bd9Sstevel@tonic-gate { \
1437c478bd9Sstevel@tonic-gate 	PR_DLPI("dlpi: OKACK: 0x%x(%s)\n", (cc), dlprim2str(cc)); \
1447c478bd9Sstevel@tonic-gate 	dlokack((qq), (mm), (cc)); \
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate #define	DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \
1477c478bd9Sstevel@tonic-gate { \
1487c478bd9Sstevel@tonic-gate 	PR_DLPI("dlpi: BINDACK: eth=%x:%x:%x:%x:%x:%x, sap=0x%x, l=%d\n", \
1497c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \
1507c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \
1517c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \
1527c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \
1537c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \
1547c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \
1557c478bd9Sstevel@tonic-gate 		(uint_t)(ss), (int)(ll)); \
1567c478bd9Sstevel@tonic-gate 	dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy)); \
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate #define	DLPHYSADDRACK(qq, mm, aa, ll) \
1597c478bd9Sstevel@tonic-gate { \
1607c478bd9Sstevel@tonic-gate 	PR_DLPI("dlpi: PHYSACK: eth=%x:%x:%x:%x:%x:%x, l=%d\n", \
1617c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[0], \
1627c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[1], \
1637c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[2], \
1647c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[3], \
1657c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[4], \
1667c478bd9Sstevel@tonic-gate 		((struct idndladdr *)(aa))->dl_phys.ether_addr_octet[5], \
1677c478bd9Sstevel@tonic-gate 		(ll)); \
1687c478bd9Sstevel@tonic-gate 	dlphysaddrack((qq), (mm), (aa), (ll)); \
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate static char *dlerrstr[] = {
1727c478bd9Sstevel@tonic-gate 	"DL_BADSAP",
1737c478bd9Sstevel@tonic-gate 	"DL_BADADDR",
1747c478bd9Sstevel@tonic-gate 	"DL_ACCESS",
1757c478bd9Sstevel@tonic-gate 	"DL_OUTSTATE",
1767c478bd9Sstevel@tonic-gate 	"DL_SYSERR",
1777c478bd9Sstevel@tonic-gate 	"DL_BADCORR",
1787c478bd9Sstevel@tonic-gate 	"DL_BADDATA",
1797c478bd9Sstevel@tonic-gate 	"DL_UNSUPPORTED",
1807c478bd9Sstevel@tonic-gate 	"DL_BADPPA",
1817c478bd9Sstevel@tonic-gate 	"DL_BADPRIM",
1827c478bd9Sstevel@tonic-gate 	"DL_BADQOSPARAM",
1837c478bd9Sstevel@tonic-gate 	"DL_BADQOSTYPE",
1847c478bd9Sstevel@tonic-gate 	"DL_BADTOKEN",
1857c478bd9Sstevel@tonic-gate 	"DL_BOUND",
1867c478bd9Sstevel@tonic-gate 	"DL_INITFAILED",
1877c478bd9Sstevel@tonic-gate 	"DL_NOADDR",
1887c478bd9Sstevel@tonic-gate 	"DL_NOTINIT",
1897c478bd9Sstevel@tonic-gate 	"DL_UNDELIVERABLE",
1907c478bd9Sstevel@tonic-gate 	"DL_NOTSUPPORTED",
1917c478bd9Sstevel@tonic-gate 	"DL_TOOMANY",
1927c478bd9Sstevel@tonic-gate 	"DL_NOTENAB",
1937c478bd9Sstevel@tonic-gate 	"DL_BUSY",
1947c478bd9Sstevel@tonic-gate 	"DL_NOAUTO",
1957c478bd9Sstevel@tonic-gate 	"DL_NOXIDAUTO",
1967c478bd9Sstevel@tonic-gate 	"DL_NOTESTAUTO",
1977c478bd9Sstevel@tonic-gate 	"DL_XIDAUTO",
1987c478bd9Sstevel@tonic-gate 	"DL_TESTAUTO",
1997c478bd9Sstevel@tonic-gate 	"DL_PENDING"
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate static int dlerrnum = (sizeof (dlerrstr) / sizeof (char *));
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate static char *
dlerr2str(int err)2047c478bd9Sstevel@tonic-gate dlerr2str(int err)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	if ((err < 0) || (err >= dlerrnum))
2077c478bd9Sstevel@tonic-gate 		return ("unknown");
2087c478bd9Sstevel@tonic-gate 	else
2097c478bd9Sstevel@tonic-gate 		return (dlerrstr[err]);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate static char *
dlprim2str(int prim)2137c478bd9Sstevel@tonic-gate dlprim2str(int prim)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	char	*pstr;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	switch (prim) {
2187c478bd9Sstevel@tonic-gate 	case DL_UNITDATA_REQ:	pstr = "UNITDATA_REQ";		break;
2197c478bd9Sstevel@tonic-gate 	case DL_ATTACH_REQ:	pstr = "ATTACH_REQ";		break;
2207c478bd9Sstevel@tonic-gate 	case DL_DETACH_REQ:	pstr = "DETACH_REQ";		break;
2217c478bd9Sstevel@tonic-gate 	case DL_BIND_REQ:	pstr = "BIND_REQ";		break;
2227c478bd9Sstevel@tonic-gate 	case DL_UNBIND_REQ:	pstr = "UNBIND_REQ";		break;
2237c478bd9Sstevel@tonic-gate 	case DL_INFO_REQ:	pstr = "INFO_REQ";		break;
2247c478bd9Sstevel@tonic-gate 	case DL_PROMISCON_REQ:	pstr = "PROMISCON_REQ";		break;
2257c478bd9Sstevel@tonic-gate 	case DL_PROMISCOFF_REQ:	pstr = "PROMISCOFF_REQ";	break;
2267c478bd9Sstevel@tonic-gate 	case DL_ENABMULTI_REQ:	pstr = "ENABMULTI_REQ";		break;
2277c478bd9Sstevel@tonic-gate 	case DL_DISABMULTI_REQ:	pstr = "DISABMULTI_REQ";	break;
2287c478bd9Sstevel@tonic-gate 	case DL_PHYS_ADDR_REQ:	pstr = "PHYS_ADDR_REQ";		break;
2297c478bd9Sstevel@tonic-gate 	case DL_SET_PHYS_ADDR_REQ:
2307c478bd9Sstevel@tonic-gate 				pstr = "SET_PHYS_ADDR_REQ";	break;
2317c478bd9Sstevel@tonic-gate 	default:		pstr = "unsupported";		break;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	return (pstr);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate #else /* DEBUG */
2367c478bd9Sstevel@tonic-gate #define	DLERRORACK(qq, mm, cc, ee, xx) \
2377c478bd9Sstevel@tonic-gate 			(dlerrorack((qq), (mm), (cc), (ee), (xx)))
2387c478bd9Sstevel@tonic-gate #define	DLOKACK(qq, mm, cc) \
2397c478bd9Sstevel@tonic-gate 			(dlokack((qq), (mm), (cc)))
2407c478bd9Sstevel@tonic-gate #define	DLBINDACK(qq, mm, ss, aa, ll, xx, yy) \
2417c478bd9Sstevel@tonic-gate 			(dlbindack((qq), (mm), (ss), (aa), (ll), (xx), (yy)))
2427c478bd9Sstevel@tonic-gate #define	DLPHYSADDRACK(qq, mm, aa, ll) \
2437c478bd9Sstevel@tonic-gate 			(dlphysaddrack((qq), (mm), (aa), (ll)))
2447c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate #define	IDNDL_ADDR_IS_MULTICAST(ap)	(((ap)->ether_addr_octet[0] & 01) == 1)
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate  * MIB II broadcast/multicast packets
2497c478bd9Sstevel@tonic-gate  */
2507c478bd9Sstevel@tonic-gate #define	IS_BROADCAST(ehp) \
2517c478bd9Sstevel@tonic-gate 		(ether_cmp(&(ehp)->ether_dhost, &etherbroadcastaddr) == 0)
2527c478bd9Sstevel@tonic-gate #define	IS_MULTICAST(ehp) \
2537c478bd9Sstevel@tonic-gate 		IDNDL_ADDR_IS_MULTICAST(&(ehp)->ether_dhost)
2547c478bd9Sstevel@tonic-gate #define	BUMP_InNUcast(sip, ehp)					\
2557c478bd9Sstevel@tonic-gate 		if (IS_BROADCAST(ehp)) {			\
2567c478bd9Sstevel@tonic-gate 			(sip)->si_kstat.si_brdcstrcv++;		\
2577c478bd9Sstevel@tonic-gate 		} else if (IS_MULTICAST(ehp)) {			\
2587c478bd9Sstevel@tonic-gate 			(sip)->si_kstat.si_multircv++;		\
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate #define	BUMP_OutNUcast(sip, ehp)				\
2617c478bd9Sstevel@tonic-gate 		if (IS_BROADCAST(ehp)) {			\
2627c478bd9Sstevel@tonic-gate 			(sip)->si_kstat.si_brdcstxmt++;		\
2637c478bd9Sstevel@tonic-gate 		} else if (IS_MULTICAST(ehp)) {			\
2647c478bd9Sstevel@tonic-gate 			(sip)->si_kstat.si_multixmt++;		\
2657c478bd9Sstevel@tonic-gate 		}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate  * Function prototypes.
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate static int	idndl_ioc_hdr_info(queue_t *, mblk_t *, int *);
2717c478bd9Sstevel@tonic-gate static void	idndl_areq(queue_t *, mblk_t *);
2727c478bd9Sstevel@tonic-gate static void	idndl_dreq(queue_t *, mblk_t *);
2737c478bd9Sstevel@tonic-gate static void	idndl_breq(queue_t *, mblk_t *);
2747c478bd9Sstevel@tonic-gate static void	idndl_ubreq(queue_t *, mblk_t *);
2757c478bd9Sstevel@tonic-gate static void	idndl_ireq(queue_t *, mblk_t *);
2767c478bd9Sstevel@tonic-gate static void	idndl_ponreq(queue_t *, mblk_t *);
2777c478bd9Sstevel@tonic-gate static void	idndl_poffreq(queue_t *, mblk_t *);
2787c478bd9Sstevel@tonic-gate static void	idndl_emreq(queue_t *, mblk_t *);
2797c478bd9Sstevel@tonic-gate static void	idndl_dmreq(queue_t *, mblk_t *);
2807c478bd9Sstevel@tonic-gate static void	idndl_pareq(queue_t *, mblk_t *);
2817c478bd9Sstevel@tonic-gate #ifdef notdef
2827c478bd9Sstevel@tonic-gate static void	idndl_spareq(queue_t *, mblk_t *);
2837c478bd9Sstevel@tonic-gate #endif /* notdef */
2847c478bd9Sstevel@tonic-gate static void	idndl_udreq(queue_t *, mblk_t *);
2857c478bd9Sstevel@tonic-gate static void	serror(dev_info_t *dip, int idnerr, char *fmt, ...);
2867c478bd9Sstevel@tonic-gate static mblk_t	*idndl_addudind(struct idn *, mblk_t *, struct ether_addr *,
2877c478bd9Sstevel@tonic-gate 				struct ether_addr *, int, ulong_t);
2887c478bd9Sstevel@tonic-gate static void	idndl_setipq(struct idn *);
2897c478bd9Sstevel@tonic-gate static int	idndl_mcmatch(struct idnstr *, struct ether_addr *);
2907c478bd9Sstevel@tonic-gate static int	idndl_stat_kstat_update(kstat_t *ksp, int rw);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate static int		_idndl_ether2domain(struct ether_addr *eap);
2937c478bd9Sstevel@tonic-gate static struct idn	*_idndl_ether2sip(struct ether_addr *eap);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate #define	IDNSAPMATCH(sap, type, flags) ((sap == type)? 1 : \
2977c478bd9Sstevel@tonic-gate 	((flags & IDNSALLSAP)? 1 : \
2987c478bd9Sstevel@tonic-gate 	((sap <= ETHERMTU) && sap && (type <= ETHERMTU))? 1 : 0))
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  * Our DL_INFO_ACK template.
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate static	dl_info_ack_t idninfoack = {
3047c478bd9Sstevel@tonic-gate 	DL_INFO_ACK,			/* dl_primitive */
3057c478bd9Sstevel@tonic-gate 	0,				/* dl_max_sdu (see idndl_dlpi_init()) */
3067c478bd9Sstevel@tonic-gate 	0,				/* dl_min_sdu */
3077c478bd9Sstevel@tonic-gate 	IDNADDRL,			/* dl_addr_length */
3087c478bd9Sstevel@tonic-gate 	DL_ETHER, /* DL_OTHER, */	/* dl_mac_type */
3097c478bd9Sstevel@tonic-gate 	0,				/* dl_reserved */
3107c478bd9Sstevel@tonic-gate 	0,				/* dl_current_state */
3117c478bd9Sstevel@tonic-gate 	-2,				/* dl_sap_length */
3127c478bd9Sstevel@tonic-gate 	DL_CLDLS, /* DL_CODLS? */	/* dl_service_mode */
3137c478bd9Sstevel@tonic-gate 	0,				/* dl_qos_length */
3147c478bd9Sstevel@tonic-gate 	0,				/* dl_qos_offset */
3157c478bd9Sstevel@tonic-gate 	0,				/* dl_range_length */
3167c478bd9Sstevel@tonic-gate 	0,				/* dl_range_offset */
3177c478bd9Sstevel@tonic-gate 	DL_STYLE2,			/* dl_provider_style */
3187c478bd9Sstevel@tonic-gate 	sizeof (dl_info_ack_t),		/* dl_addr_offset */
3197c478bd9Sstevel@tonic-gate 	DL_VERSION_2,			/* dl_version */
3207c478bd9Sstevel@tonic-gate 	ETHERADDRL,			/* dl_brdcst_addr_length */
3217c478bd9Sstevel@tonic-gate 	sizeof (dl_info_ack_t) + IDNADDRL,	/* dl_brdcst_addr_offset */
3227c478bd9Sstevel@tonic-gate 	0				/* dl_growth */
3237c478bd9Sstevel@tonic-gate };
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * Ethernet broadcast address definition.
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate static struct ether_addr	etherbroadcastaddr = {
3297c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
3307c478bd9Sstevel@tonic-gate };
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  * --------------------------------------------------
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate void
idndl_localetheraddr(struct idn * sip,struct ether_addr * eap)3367c478bd9Sstevel@tonic-gate idndl_localetheraddr(struct idn *sip, struct ether_addr *eap)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	int		rv;
3397c478bd9Sstevel@tonic-gate 	int		instance;
3407c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_localetheraddr";
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	ASSERT(sip && sip->si_dip && eap);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(sip->si_dip);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: getting local etheraddr...\n", proc);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	rv = idndl_domain_etheraddr(idn.localid, instance, eap);
3497c478bd9Sstevel@tonic-gate 	ASSERT(rv == 0);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate int
idndl_domain_etheraddr(int domid,int channel,struct ether_addr * eap)3537c478bd9Sstevel@tonic-gate idndl_domain_etheraddr(int domid, int channel, struct ether_addr *eap)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate 	uchar_t		netid;
3567c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_domain_etheraddr";
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	if (idn_domain[domid].dcpu == IDN_NIL_DCPU)
3597c478bd9Sstevel@tonic-gate 		return (-1);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	netid = (uchar_t)idn_domain[domid].dnetid;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: dnetid = 0x%x, channel = 0x%x\n",
3647c478bd9Sstevel@tonic-gate 		proc, (uint_t)netid, channel);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate #ifdef notdef
3677c478bd9Sstevel@tonic-gate 	localetheraddr(NULL, eap);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: localetheraddr = %x:%x:%x:%x:%x:%x\n",
3707c478bd9Sstevel@tonic-gate 		proc, eap->ether_addr_octet[0], eap->ether_addr_octet[1],
3717c478bd9Sstevel@tonic-gate 		eap->ether_addr_octet[2], eap->ether_addr_octet[3],
3727c478bd9Sstevel@tonic-gate 		eap->ether_addr_octet[4], eap->ether_addr_octet[5]):
3737c478bd9Sstevel@tonic-gate #endif /* notdef */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_ZERO] = 0;
3767c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_COOKIE1] = IDNETHER_COOKIE1_VAL;
3777c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_COOKIE2] = IDNETHER_COOKIE2_VAL;
3787c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_NETID] = netid;
3797c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_CHANNEL] = (uchar_t)channel;
3807c478bd9Sstevel@tonic-gate 	eap->ether_addr_octet[IDNETHER_RESERVED] = IDNETHER_RESERVED_VAL;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: domain %d: etheraddr = %x:%x:%x:%x:%x:%x\n",
3837c478bd9Sstevel@tonic-gate 		proc, domid,
3847c478bd9Sstevel@tonic-gate 		eap->ether_addr_octet[0], eap->ether_addr_octet[1],
3857c478bd9Sstevel@tonic-gate 		eap->ether_addr_octet[2], eap->ether_addr_octet[3],
3867c478bd9Sstevel@tonic-gate 		eap->ether_addr_octet[4], eap->ether_addr_octet[5]);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	return (0);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate #ifdef DEBUG
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  */
3947c478bd9Sstevel@tonic-gate static int
_idndl_ether2domain(struct ether_addr * eap)3957c478bd9Sstevel@tonic-gate _idndl_ether2domain(struct ether_addr *eap)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	uchar_t	*eaop;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	eaop = eap->ether_addr_octet;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	ASSERT(IDNDL_ADDR_IS_MULTICAST(eap) ||
4027c478bd9Sstevel@tonic-gate 		((eaop[IDNETHER_COOKIE1] == IDNETHER_COOKIE1_VAL) &&
4037c478bd9Sstevel@tonic-gate 		    (eaop[IDNETHER_COOKIE2] == IDNETHER_COOKIE2_VAL)) ||
4047c478bd9Sstevel@tonic-gate 		((eaop[IDNETHER_COOKIE1] == 0xff) &&
4057c478bd9Sstevel@tonic-gate 		    (eaop[IDNETHER_COOKIE2] == 0xff)));
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * Note that (IDN_NIL_DOMID) will be returned if ether address is
4087c478bd9Sstevel@tonic-gate 	 * a broadcast 0xff.
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	return (IDN_NETID2DOMID(eaop[IDNETHER_NETID]));
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static struct idn *
_idndl_ether2sip(struct ether_addr * eap)4167c478bd9Sstevel@tonic-gate _idndl_ether2sip(struct ether_addr *eap)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	int		instance;
4197c478bd9Sstevel@tonic-gate 	struct idn	*sip;
4207c478bd9Sstevel@tonic-gate 	uchar_t		*eaop;
4217c478bd9Sstevel@tonic-gate 	procname_t	proc = "_idndl_ether2sip";
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	eaop = eap->ether_addr_octet;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (!IDNDL_ADDR_IS_MULTICAST(eap) &&
4267c478bd9Sstevel@tonic-gate 	    (((eaop[IDNETHER_COOKIE1] != IDNETHER_COOKIE1_VAL) ||
4277c478bd9Sstevel@tonic-gate 	    (eaop[IDNETHER_COOKIE2] != IDNETHER_COOKIE2_VAL)) &&
4287c478bd9Sstevel@tonic-gate 	    ((eaop[IDNETHER_COOKIE1] != 0xff) ||
4297c478bd9Sstevel@tonic-gate 		(eaop[IDNETHER_COOKIE2] != 0xff)))) {
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
4327c478bd9Sstevel@tonic-gate 			"IDN: 400: corrupted MAC header "
4337c478bd9Sstevel@tonic-gate 			"(exp %x or 0xffff, act 0x%x)",
4347c478bd9Sstevel@tonic-gate 			(IDNETHER_COOKIE1_VAL << 8) |
4357c478bd9Sstevel@tonic-gate 				IDNETHER_COOKIE2_VAL,
4367c478bd9Sstevel@tonic-gate 			(eaop[IDNETHER_COOKIE1] << 8) |
4377c478bd9Sstevel@tonic-gate 				eaop[IDNETHER_COOKIE2]);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		return (NULL);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (IDNDL_ADDR_IS_MULTICAST(eap)) {
4437c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: MULTICAST ADDR *** ERROR ***\n", proc);
4447c478bd9Sstevel@tonic-gate 		sip = NULL;
4457c478bd9Sstevel@tonic-gate 	} else if (eaop[IDNETHER_CHANNEL] == 0xff) {
4467c478bd9Sstevel@tonic-gate 		/*
4477c478bd9Sstevel@tonic-gate 		 * Received a broadcast.  Need to manually
4487c478bd9Sstevel@tonic-gate 		 * find anybody the first running sip and use it.
4497c478bd9Sstevel@tonic-gate 		 * XXX - kind of kludgy - single threads broadcasts.
4507c478bd9Sstevel@tonic-gate 		 */
4517c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: BROADCAST CHANNEL *** ERROR ***\n", proc);
4527c478bd9Sstevel@tonic-gate 		sip = NULL;
4537c478bd9Sstevel@tonic-gate 	} else {
4547c478bd9Sstevel@tonic-gate 		instance = (int)eaop[IDNETHER_CHANNEL];
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		sip = IDN_INST2SIP(instance);
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	return (sip);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate void
idndl_dlpi_init()4647c478bd9Sstevel@tonic-gate idndl_dlpi_init()
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_dlpi_init";
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: setting dl_max_sdu to %ld (0x%lx) bytes\n",
4697c478bd9Sstevel@tonic-gate 		proc, IDN_MTU, IDN_MTU);
4707c478bd9Sstevel@tonic-gate 	/*
4717c478bd9Sstevel@tonic-gate 	 * This field is dynamic because the user may
4727c478bd9Sstevel@tonic-gate 	 * want to dynamically set it _before_ an IDNnet
4737c478bd9Sstevel@tonic-gate 	 * has been established via ndd(1M).
4747c478bd9Sstevel@tonic-gate 	 */
4757c478bd9Sstevel@tonic-gate 	idninfoack.dl_max_sdu = IDN_MTU;
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate static int
idndl_stat_kstat_update(kstat_t * ksp,int rw)4797c478bd9Sstevel@tonic-gate idndl_stat_kstat_update(kstat_t *ksp, int rw)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	struct idn	*sip;
4827c478bd9Sstevel@tonic-gate 	struct idn_kstat_named	*skp;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	sip = (struct idn *)ksp->ks_private;
4857c478bd9Sstevel@tonic-gate 	skp = (struct idn_kstat_named *)ksp->ks_data;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
4887c478bd9Sstevel@tonic-gate #if 0
4897c478bd9Sstevel@tonic-gate 		bzero(&sg_kstat.gk_kstat, sizeof (sg_kstat.gk_kstat));
4907c478bd9Sstevel@tonic-gate #endif /* 0 */
4917c478bd9Sstevel@tonic-gate 		bzero(&sip->si_kstat, sizeof (sip->si_kstat));
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_ipackets 	= skp->sk_ipackets.value.ul;
4947c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_ierrors	= skp->sk_ierrors.value.ul;
4957c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_opackets 	= skp->sk_opackets.value.ul;
4967c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_oerrors	= skp->sk_oerrors.value.ul;
4977c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_txcoll		= skp->sk_txcoll.value.ul;
4987c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_rxcoll		= skp->sk_rxcoll.value.ul;
4997c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_crc		= skp->sk_crc.value.ul;
5007c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_buff		= skp->sk_buff.value.ul;
5017c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_nolink		= skp->sk_nolink.value.ul;
5027c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_linkdown	= skp->sk_linkdown.value.ul;
5037c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_inits		= skp->sk_inits.value.ul;
5047c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_nocanput	= skp->sk_nocanput.value.ul;
5057c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_allocbfail	= skp->sk_allocbfail.value.ul;
5067c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_notbufs	= skp->sk_notbufs.value.ul;
5077c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_reclaim	= skp->sk_reclaim.value.ul;
5087c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_smraddr	= skp->sk_smraddr.value.ul;
5097c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_txmax		= skp->sk_txmax.value.ul;
5107c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_txfull		= skp->sk_txfull.value.ul;
5117c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_xdcall		= skp->sk_xdcall.value.ul;
5127c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_sigsvr		= skp->sk_sigsvr.value.ul;
5137c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_mboxcrc	= skp->sk_mboxcrc.value.ul;
5147c478bd9Sstevel@tonic-gate 		/*
5157c478bd9Sstevel@tonic-gate 		 * MIB II kstat variables
5167c478bd9Sstevel@tonic-gate 		 */
5177c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_rcvbytes	= skp->sk_rcvbytes.value.ul;
5187c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_xmtbytes	= skp->sk_xmtbytes.value.ul;
5197c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_multircv	= skp->sk_multircv.value.ul;
5207c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_multixmt	= skp->sk_multixmt.value.ul;
5217c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_brdcstrcv	= skp->sk_brdcstrcv.value.ul;
5227c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_brdcstxmt	= skp->sk_brdcstxmt.value.ul;
5237c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_norcvbuf	= skp->sk_norcvbuf.value.ul;
5247c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_noxmtbuf	= skp->sk_noxmtbuf.value.ul;
5257c478bd9Sstevel@tonic-gate 		/*
5267c478bd9Sstevel@tonic-gate 		 * PSARC 1997/198 : 64bit kstats
5277c478bd9Sstevel@tonic-gate 		 */
5287c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_ipackets64	= skp->sk_ipackets64.value.ull;
5297c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_opackets64	= skp->sk_opackets64.value.ull;
5307c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_rbytes64	= skp->sk_rbytes64.value.ull;
5317c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_obytes64	= skp->sk_obytes64.value.ull;
5327c478bd9Sstevel@tonic-gate 		/*
5337c478bd9Sstevel@tonic-gate 		 * PSARC 1997/247 : RFC 1643
5347c478bd9Sstevel@tonic-gate 		 */
5357c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_fcs_errors	= skp->sk_fcs_errors.value.ul;
5367c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_macxmt_errors	=
5377c478bd9Sstevel@tonic-gate 						skp->sk_macxmt_errors.value.ul;
5387c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_toolong_errors	=
5397c478bd9Sstevel@tonic-gate 						skp->sk_toolong_errors.value.ul;
5407c478bd9Sstevel@tonic-gate 		sip->si_kstat.si_macrcv_errors	=
5417c478bd9Sstevel@tonic-gate 						skp->sk_macrcv_errors.value.ul;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		return (0);
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	skp->sk_ipackets.value.ul 	= sip->si_kstat.si_ipackets;
5477c478bd9Sstevel@tonic-gate 	skp->sk_ierrors.value.ul	= sip->si_kstat.si_ierrors;
5487c478bd9Sstevel@tonic-gate 	skp->sk_opackets.value.ul	= sip->si_kstat.si_opackets;
5497c478bd9Sstevel@tonic-gate 	skp->sk_oerrors.value.ul	= sip->si_kstat.si_oerrors;
5507c478bd9Sstevel@tonic-gate 	skp->sk_txcoll.value.ul		= sip->si_kstat.si_txcoll;
5517c478bd9Sstevel@tonic-gate 	skp->sk_rxcoll.value.ul		= sip->si_kstat.si_rxcoll;
5527c478bd9Sstevel@tonic-gate 	skp->sk_crc.value.ul		= sip->si_kstat.si_crc;
5537c478bd9Sstevel@tonic-gate 	skp->sk_buff.value.ul		= sip->si_kstat.si_buff;
5547c478bd9Sstevel@tonic-gate 	skp->sk_nolink.value.ul		= sip->si_kstat.si_nolink;
5557c478bd9Sstevel@tonic-gate 	skp->sk_linkdown.value.ul	= sip->si_kstat.si_linkdown;
5567c478bd9Sstevel@tonic-gate 	skp->sk_inits.value.ul		= sip->si_kstat.si_inits;
5577c478bd9Sstevel@tonic-gate 	skp->sk_nocanput.value.ul	= sip->si_kstat.si_nocanput;
5587c478bd9Sstevel@tonic-gate 	skp->sk_allocbfail.value.ul	= sip->si_kstat.si_allocbfail;
5597c478bd9Sstevel@tonic-gate 	skp->sk_notbufs.value.ul	= sip->si_kstat.si_notbufs;
5607c478bd9Sstevel@tonic-gate 	skp->sk_reclaim.value.ul	= sip->si_kstat.si_reclaim;
5617c478bd9Sstevel@tonic-gate 	skp->sk_smraddr.value.ul	= sip->si_kstat.si_smraddr;
5627c478bd9Sstevel@tonic-gate 	skp->sk_txfull.value.ul		= sip->si_kstat.si_txfull;
5637c478bd9Sstevel@tonic-gate 	skp->sk_txmax.value.ul		= sip->si_kstat.si_txmax;
5647c478bd9Sstevel@tonic-gate 	skp->sk_xdcall.value.ul		= sip->si_kstat.si_xdcall;
5657c478bd9Sstevel@tonic-gate 	skp->sk_sigsvr.value.ul		= sip->si_kstat.si_sigsvr;
5667c478bd9Sstevel@tonic-gate 	skp->sk_mboxcrc.value.ul	= sip->si_kstat.si_mboxcrc;
5677c478bd9Sstevel@tonic-gate 	/*
5687c478bd9Sstevel@tonic-gate 	 * MIB II kstat variables
5697c478bd9Sstevel@tonic-gate 	 */
5707c478bd9Sstevel@tonic-gate 	skp->sk_rcvbytes.value.ul	= sip->si_kstat.si_rcvbytes;
5717c478bd9Sstevel@tonic-gate 	skp->sk_xmtbytes.value.ul	= sip->si_kstat.si_xmtbytes;
5727c478bd9Sstevel@tonic-gate 	skp->sk_multircv.value.ul	= sip->si_kstat.si_multircv;
5737c478bd9Sstevel@tonic-gate 	skp->sk_multixmt.value.ul	= sip->si_kstat.si_multixmt;
5747c478bd9Sstevel@tonic-gate 	skp->sk_brdcstrcv.value.ul	= sip->si_kstat.si_brdcstrcv;
5757c478bd9Sstevel@tonic-gate 	skp->sk_brdcstxmt.value.ul	= sip->si_kstat.si_brdcstxmt;
5767c478bd9Sstevel@tonic-gate 	skp->sk_norcvbuf.value.ul	= sip->si_kstat.si_norcvbuf;
5777c478bd9Sstevel@tonic-gate 	skp->sk_noxmtbuf.value.ul	= sip->si_kstat.si_noxmtbuf;
5787c478bd9Sstevel@tonic-gate 	/*
5797c478bd9Sstevel@tonic-gate 	 * PSARC 1997/198 : 64bit kstats
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	skp->sk_ipackets64.value.ull	= sip->si_kstat.si_ipackets64;
5827c478bd9Sstevel@tonic-gate 	skp->sk_opackets64.value.ull	= sip->si_kstat.si_opackets64;
5837c478bd9Sstevel@tonic-gate 	skp->sk_rbytes64.value.ull	= sip->si_kstat.si_rbytes64;
5847c478bd9Sstevel@tonic-gate 	skp->sk_obytes64.value.ull	= sip->si_kstat.si_obytes64;
5857c478bd9Sstevel@tonic-gate 	/*
5867c478bd9Sstevel@tonic-gate 	 * PSARC 1997/247 : RFC 1643
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	skp->sk_fcs_errors.value.ul	= sip->si_kstat.si_fcs_errors;
5897c478bd9Sstevel@tonic-gate 	skp->sk_macxmt_errors.value.ul	= sip->si_kstat.si_macxmt_errors;
5907c478bd9Sstevel@tonic-gate 	skp->sk_toolong_errors.value.ul	= sip->si_kstat.si_toolong_errors;
5917c478bd9Sstevel@tonic-gate 	skp->sk_macrcv_errors.value.ul	= sip->si_kstat.si_macrcv_errors;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	return (0);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate void
idndl_statinit(struct idn * sip)5977c478bd9Sstevel@tonic-gate idndl_statinit(struct idn *sip)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	struct	kstat		*ksp;
6007c478bd9Sstevel@tonic-gate 	struct	idn_kstat_named	*skp;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate #ifdef	kstat
6037c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip),
6047c478bd9Sstevel@tonic-gate 		NULL, "net", KSTAT_TYPE_NAMED,
6057c478bd9Sstevel@tonic-gate 		sizeof (struct idn_kstat_named) / sizeof (kstat_named_t),
6067c478bd9Sstevel@tonic-gate 		KSTAT_FLAG_PERSISTENT)) == NULL) {
6077c478bd9Sstevel@tonic-gate #else
6087c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(IDNNAME, ddi_get_instance(sip->si_dip),
6097c478bd9Sstevel@tonic-gate 		NULL, "net", KSTAT_TYPE_NAMED,
6107c478bd9Sstevel@tonic-gate 		sizeof (struct idn_kstat_named) /
6117c478bd9Sstevel@tonic-gate 		sizeof (kstat_named_t), 0)) == NULL) {
6127c478bd9Sstevel@tonic-gate #endif	/* kstat */
6137c478bd9Sstevel@tonic-gate 		serror(sip->si_dip, 450, "kstat_create failed");
6147c478bd9Sstevel@tonic-gate 		return;
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	sip->si_ksp = ksp;
6187c478bd9Sstevel@tonic-gate 	skp = (struct idn_kstat_named *)(ksp->ks_data);
6197c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_ipackets,		"ipackets",
6207c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6217c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_ierrors,		"ierrors",
6227c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6237c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_opackets,		"opackets",
6247c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6257c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_oerrors,		"oerrors",
6267c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6277c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_txcoll,		"collisions",
6287c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6297c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_rxcoll,		"rx_collisions",
6307c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6317c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_crc,			"crc",
6327c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6337c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_buff,			"buff",
6347c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6357c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_nolink,		"nolink",
6367c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6377c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_linkdown,		"linkdown",
6387c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6397c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_inits,		"inits",
6407c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6417c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_nocanput,		"nocanput",
6427c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6437c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_allocbfail,		"allocbfail",
6447c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6457c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_notbufs,		"notbufs",
6467c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6477c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_reclaim,		"reclaim",
6487c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6497c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_smraddr,		"smraddr",
6507c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6517c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_txmax,		"txmax",
6527c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6537c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_txfull,		"txfull",
6547c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6557c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_xdcall,		"xdcall",
6567c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6577c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_sigsvr,		"sigsvr",
6587c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6597c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_mboxcrc,		"mboxcrc",
6607c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6617c478bd9Sstevel@tonic-gate 	/*
6627c478bd9Sstevel@tonic-gate 	 * MIB II kstat variables
6637c478bd9Sstevel@tonic-gate 	 */
6647c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_rcvbytes,		"rbytes",
6657c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6667c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_xmtbytes,		"obytes",
6677c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6687c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_multircv,		"multircv",
6697c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6707c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_multixmt,		"multixmt",
6717c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6727c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_brdcstrcv,		"brdcstrcv",
6737c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6747c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_brdcstxmt,		"brdcstxmt",
6757c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6767c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_norcvbuf,		"norcvbuf",
6777c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6787c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_noxmtbuf,		"noxmtbuf",
6797c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6807c478bd9Sstevel@tonic-gate 	/*
6817c478bd9Sstevel@tonic-gate 	 * PSARC 1997/198 : 64bit kstats
6827c478bd9Sstevel@tonic-gate 	 */
6837c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_ipackets64,		"ipackets64",
6847c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONGLONG);
6857c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_opackets64,		"opackets64",
6867c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONGLONG);
6877c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_rbytes64,		"rbytes64",
6887c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONGLONG);
6897c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_obytes64,		"obytes64",
6907c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONGLONG);
6917c478bd9Sstevel@tonic-gate 	/*
6927c478bd9Sstevel@tonic-gate 	 * PSARC 1997/247 : RFC 1643
6937c478bd9Sstevel@tonic-gate 	 */
6947c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_fcs_errors,		"fcs_errors",
6957c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6967c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_macxmt_errors,	"macxmt_errors",
6977c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
6987c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_toolong_errors,	"toolong_errors",
6997c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
7007c478bd9Sstevel@tonic-gate 	kstat_named_init(&skp->sk_macrcv_errors,	"macrcv_errors",
7017c478bd9Sstevel@tonic-gate 		KSTAT_DATA_ULONG);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	ksp->ks_update = idndl_stat_kstat_update;
7047c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)sip;
7057c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate void
7097c478bd9Sstevel@tonic-gate idndl_proto(queue_t *wq, mblk_t *mp)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
7127c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
7137c478bd9Sstevel@tonic-gate 	t_uscalar_t		prim;
7147c478bd9Sstevel@tonic-gate 	procname_t		proc = "idndl_proto";
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
7177c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (t_uscalar_t)) {
7187c478bd9Sstevel@tonic-gate 		/*
7197c478bd9Sstevel@tonic-gate 		 * Gotta at least have enough room to hold
7207c478bd9Sstevel@tonic-gate 		 * the primitive!
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, -1, DL_BADPRIM, 0);
7237c478bd9Sstevel@tonic-gate 		return;
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
7267c478bd9Sstevel@tonic-gate 	prim = dlp->dl_primitive;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_START,
7297c478bd9Sstevel@tonic-gate 		"idndl_proto start:  wq %p dlprim %X", wq, prim);
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate #ifdef DEBUG
732bf30efa4Smathue 	PR_DLPI("%s: stp = 0x%p, wq = 0x%p, dlprim = 0x%x(%s)\n",
733*07d06da5SSurya Prakki 		proc, (void *)stp, (void *)wq, prim, dlprim2str(prim));
7347c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	rw_enter(&stp->ss_rwlock, RW_WRITER);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	switch (prim) {
7397c478bd9Sstevel@tonic-gate 	case DL_UNITDATA_REQ:
7407c478bd9Sstevel@tonic-gate 		idndl_udreq(wq, mp);
7417c478bd9Sstevel@tonic-gate 		break;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	case DL_ATTACH_REQ:
7447c478bd9Sstevel@tonic-gate 		idndl_areq(wq, mp);
7457c478bd9Sstevel@tonic-gate 		break;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	case DL_DETACH_REQ:
7487c478bd9Sstevel@tonic-gate 		idndl_dreq(wq, mp);
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	case DL_BIND_REQ:
7527c478bd9Sstevel@tonic-gate 		idndl_breq(wq, mp);
7537c478bd9Sstevel@tonic-gate 		break;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	case DL_UNBIND_REQ:
7567c478bd9Sstevel@tonic-gate 		idndl_ubreq(wq, mp);
7577c478bd9Sstevel@tonic-gate 		break;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	case DL_INFO_REQ:
7607c478bd9Sstevel@tonic-gate 		idndl_ireq(wq, mp);
7617c478bd9Sstevel@tonic-gate 		break;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	case DL_PROMISCON_REQ:
7647c478bd9Sstevel@tonic-gate 		idndl_ponreq(wq, mp);
7657c478bd9Sstevel@tonic-gate 		break;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	case DL_PROMISCOFF_REQ:
7687c478bd9Sstevel@tonic-gate 		idndl_poffreq(wq, mp);
7697c478bd9Sstevel@tonic-gate 		break;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	case DL_ENABMULTI_REQ:
7727c478bd9Sstevel@tonic-gate 		idndl_emreq(wq, mp);
7737c478bd9Sstevel@tonic-gate 		break;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	case DL_DISABMULTI_REQ:
7767c478bd9Sstevel@tonic-gate 		idndl_dmreq(wq, mp);
7777c478bd9Sstevel@tonic-gate 		break;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	case DL_PHYS_ADDR_REQ:
7807c478bd9Sstevel@tonic-gate 		idndl_pareq(wq, mp);
7817c478bd9Sstevel@tonic-gate 		break;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate #ifdef notdef
7847c478bd9Sstevel@tonic-gate 	/*
7857c478bd9Sstevel@tonic-gate 	 * We cannot allow this in IDN-land because we
7867c478bd9Sstevel@tonic-gate 	 * rely on the ethernet (physical) address to determine
7877c478bd9Sstevel@tonic-gate 	 * where to target the message.  Recall that unlike
7887c478bd9Sstevel@tonic-gate 	 * ethernet we simply cannot dump junk on the wire and
7897c478bd9Sstevel@tonic-gate 	 * expect it to automatically find its destination.
7907c478bd9Sstevel@tonic-gate 	 * In the IDN we need to target the destination.
7917c478bd9Sstevel@tonic-gate 	 * Note that if we used POINT-TO-POINT then we wouldn't
7927c478bd9Sstevel@tonic-gate 	 * have to worry about the physical address since each
7937c478bd9Sstevel@tonic-gate 	 * domain connection would have a separate queue.
7947c478bd9Sstevel@tonic-gate 	 * However, ptp then requires multiple interfaces at
7957c478bd9Sstevel@tonic-gate 	 * the appl level as opposed to a single one for all
7967c478bd9Sstevel@tonic-gate 	 * of idn.  We opt for the simpler single interface (idn0).
7977c478bd9Sstevel@tonic-gate 	 */
7987c478bd9Sstevel@tonic-gate 	case DL_SET_PHYS_ADDR_REQ:
7997c478bd9Sstevel@tonic-gate 		idndl_spareq(wq, mp);
8007c478bd9Sstevel@tonic-gate 		break;
8017c478bd9Sstevel@tonic-gate #endif /* notdef */
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	default:
8047c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, prim, DL_UNSUPPORTED, 0);
8057c478bd9Sstevel@tonic-gate 		break;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_IDN, TR_IDN_PROTO_END,
8097c478bd9Sstevel@tonic-gate 		"idnproto end:  wq %p dlprim %X", wq, prim);
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	rw_exit(&stp->ss_rwlock);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate int
8157c478bd9Sstevel@tonic-gate idnioc_dlpi(queue_t *wq, mblk_t *mp, int *argsizep)
8167c478bd9Sstevel@tonic-gate {
8177c478bd9Sstevel@tonic-gate 	int	rv = 0;
8187c478bd9Sstevel@tonic-gate 	struct	iocblk	*iocp = (struct iocblk *)mp->b_rptr;
8197c478bd9Sstevel@tonic-gate 	struct	idnstr	*stp  = (struct idnstr *)wq->q_ptr;
8207c478bd9Sstevel@tonic-gate 	procname_t	proc = "idnioc_dlpi";
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	*argsizep = 0;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
8257c478bd9Sstevel@tonic-gate 	case DLIOCRAW:			/* raw M_DATA mode */
8267c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: cmd = DLIOCRAW\n", proc);
8277c478bd9Sstevel@tonic-gate 		stp->ss_flags |= IDNSRAW;
8287c478bd9Sstevel@tonic-gate 		break;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	case DL_IOC_HDR_INFO:		/* M_DATA "fastpath" info request */
8317c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: cmd = DL_IOC_HDR_INFO\n", proc);
8327c478bd9Sstevel@tonic-gate 		rv = idndl_ioc_hdr_info(wq, mp, argsizep);
8337c478bd9Sstevel@tonic-gate 		break;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	default:
8367c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: invalid cmd 0x%x\n", proc, iocp->ioc_cmd);
8377c478bd9Sstevel@tonic-gate 		rv = EINVAL;
8387c478bd9Sstevel@tonic-gate 		break;
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 	return (rv);
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate  * M_DATA "fastpath" info request.
8457c478bd9Sstevel@tonic-gate  * Following the M_IOCTL mblk should come a DL_UNITDATA_REQ mblk.
8467c478bd9Sstevel@tonic-gate  * We ack with an M_IOCACK pointing to the original DL_UNITDATA_REQ mblk
8477c478bd9Sstevel@tonic-gate  * followed by an mblk containing the raw ethernet header corresponding
8487c478bd9Sstevel@tonic-gate  * to the destination address.  Subsequently, we may receive M_DATA
8497c478bd9Sstevel@tonic-gate  * msgs which start with this header and may send up
8507c478bd9Sstevel@tonic-gate  * up M_DATA msgs with b_rptr pointing to a (ulong) group address
8517c478bd9Sstevel@tonic-gate  * indicator followed by the network-layer data (IP packet header).
8527c478bd9Sstevel@tonic-gate  * This is all selectable on a per-Stream basis.
8537c478bd9Sstevel@tonic-gate  */
8547c478bd9Sstevel@tonic-gate static int
8557c478bd9Sstevel@tonic-gate idndl_ioc_hdr_info(queue_t *wq, mblk_t *mp, int *argsizep)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	mblk_t			*nmp;
8587c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
8597c478bd9Sstevel@tonic-gate 	struct idndladdr	*dlap;
8607c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t	*dludp;
8617c478bd9Sstevel@tonic-gate 	struct ether_header	*headerp;
8627c478bd9Sstevel@tonic-gate 	struct idn		*sip;
8637c478bd9Sstevel@tonic-gate 	int	off, len;
8647c478bd9Sstevel@tonic-gate 	int	padding = 0;
8657c478bd9Sstevel@tonic-gate 	int	error;
8667c478bd9Sstevel@tonic-gate 	procname_t		proc = "idndl_ioc_hdr_info";
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
8697c478bd9Sstevel@tonic-gate 	sip = stp->ss_sip;
8707c478bd9Sstevel@tonic-gate 	if (sip == NULL) {
8717c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: NULL sip (ret EINVAL)\n", proc);
8727c478bd9Sstevel@tonic-gate 		return (EINVAL);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	error = miocpullup(mp, sizeof (dl_unitdata_req_t) + IDNADDRL);
8767c478bd9Sstevel@tonic-gate 	if (error != 0) {
8777c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: sanity error (ret %d)\n", proc, error);
8787c478bd9Sstevel@tonic-gate 		return (error);
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	/*
8827c478bd9Sstevel@tonic-gate 	 * Sanity check the DL_UNITDATA_REQ destination address
8837c478bd9Sstevel@tonic-gate 	 * offset and length values.
8847c478bd9Sstevel@tonic-gate 	 */
8857c478bd9Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
8867c478bd9Sstevel@tonic-gate 	off = dludp->dl_dest_addr_offset;
8877c478bd9Sstevel@tonic-gate 	len = dludp->dl_dest_addr_length;
8887c478bd9Sstevel@tonic-gate 	if (dludp->dl_primitive != DL_UNITDATA_REQ ||
8897c478bd9Sstevel@tonic-gate 	    !MBLKIN(mp->b_cont, off, len) || len != IDNADDRL) {
8907c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: off(0x%x)/len(%d) error (ret EINVAL)\n",
8917c478bd9Sstevel@tonic-gate 		    proc, off, len);
8927c478bd9Sstevel@tonic-gate 		return (EINVAL);
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	dlap = (struct idndladdr *)(mp->b_cont->b_rptr + off);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Allocate a new mblk to hold the ether header.
8997c478bd9Sstevel@tonic-gate 	 */
9007c478bd9Sstevel@tonic-gate 	nmp = allocb(sizeof (struct ether_header) + padding, BPRI_MED);
9017c478bd9Sstevel@tonic-gate 	if (nmp == NULL) {
9027c478bd9Sstevel@tonic-gate 		IDN_KSTAT_INC(sip, si_allocbfail);
9037c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 	nmp->b_rptr += padding;
9067c478bd9Sstevel@tonic-gate 	nmp->b_wptr = nmp->b_rptr + sizeof (struct ether_header);
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * Fill in the ether header.
9107c478bd9Sstevel@tonic-gate 	 */
9117c478bd9Sstevel@tonic-gate 	headerp = (struct ether_header *)nmp->b_rptr;
9127c478bd9Sstevel@tonic-gate 	ether_copy(&dlap->dl_phys, &headerp->ether_dhost);
9137c478bd9Sstevel@tonic-gate 	ether_copy(&sip->si_ouraddr, &headerp->ether_shost);
9147c478bd9Sstevel@tonic-gate 	headerp->ether_type = dlap->dl_sap;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/*
9177c478bd9Sstevel@tonic-gate 	 * Link new mblk in after the "request" mblks.
9187c478bd9Sstevel@tonic-gate 	 */
9197c478bd9Sstevel@tonic-gate 	linkb(mp, nmp);
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	stp->ss_flags |= IDNSFAST;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	/*
9247c478bd9Sstevel@tonic-gate 	 * XXX Don't bother calling idndl_setipq() here.
9257c478bd9Sstevel@tonic-gate 	 */
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (argsizep)
9287c478bd9Sstevel@tonic-gate 		*argsizep = msgsize(mp->b_cont);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	return (0);
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate static void
9347c478bd9Sstevel@tonic-gate idndl_areq(queue_t *wq, mblk_t *mp)
9357c478bd9Sstevel@tonic-gate {
9367c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
9377c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
9387c478bd9Sstevel@tonic-gate 	struct idn		*sip;
9397c478bd9Sstevel@tonic-gate 	int	ppa;
9407c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_areq";
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
9437c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) {
9467c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0);
9477c478bd9Sstevel@tonic-gate 		return;
9487c478bd9Sstevel@tonic-gate 	}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	if (stp->ss_state != DL_UNATTACHED) {
9517c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0);
9527c478bd9Sstevel@tonic-gate 		return;
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	ppa = dlp->attach_req.dl_ppa;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	/*
9587c478bd9Sstevel@tonic-gate 	 * Valid ppa?
9597c478bd9Sstevel@tonic-gate 	 */
9607c478bd9Sstevel@tonic-gate 	if (ppa == -1 || qassociate(wq, ppa) != 0) {
9617c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: bad ppa %d\n", proc, ppa);
9627c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADPPA, 0);
9637c478bd9Sstevel@tonic-gate 		return;
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 	mutex_enter(&idn.siplock);
9667c478bd9Sstevel@tonic-gate 	for (sip = idn.sip; sip; sip = sip->si_nextp) {
9677c478bd9Sstevel@tonic-gate 		if (ppa == ddi_get_instance(sip->si_dip))
9687c478bd9Sstevel@tonic-gate 			break;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 	mutex_exit(&idn.siplock);
9717c478bd9Sstevel@tonic-gate 	ASSERT(sip != NULL);	/* qassociate() succeeded */
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	/*
9747c478bd9Sstevel@tonic-gate 	 * Has device been initialized?  Do so if necessary.
9757c478bd9Sstevel@tonic-gate 	 */
9767c478bd9Sstevel@tonic-gate 	if ((sip->si_flags & IDNRUNNING) == 0) {
9777c478bd9Sstevel@tonic-gate 		if (idndl_init(sip)) {
9787c478bd9Sstevel@tonic-gate 			DLERRORACK(wq, mp, dlp->dl_primitive,
9797c478bd9Sstevel@tonic-gate 					DL_INITFAILED, 0);
9807c478bd9Sstevel@tonic-gate 			(void) qassociate(wq, -1);
9817c478bd9Sstevel@tonic-gate 			return;
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/*
9867c478bd9Sstevel@tonic-gate 	 * Set link to device and update our state.
9877c478bd9Sstevel@tonic-gate 	 */
9887c478bd9Sstevel@tonic-gate 	stp->ss_sip = sip;
9897c478bd9Sstevel@tonic-gate 	stp->ss_state = DL_UNBOUND;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_ATTACH_REQ);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate static void
9957c478bd9Sstevel@tonic-gate idndl_dreq(queue_t *wq, mblk_t *mp)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_DETACH_REQ_SIZE) {
10027c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0);
10037c478bd9Sstevel@tonic-gate 		return;
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if (stp->ss_state != DL_UNBOUND) {
10077c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0);
10087c478bd9Sstevel@tonic-gate 		return;
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	idndl_dodetach(stp);
10127c478bd9Sstevel@tonic-gate 	(void) qassociate(wq, -1);
10137c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_DETACH_REQ);
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate /*
10177c478bd9Sstevel@tonic-gate  * Detach a Stream from an interface.
10187c478bd9Sstevel@tonic-gate  */
10197c478bd9Sstevel@tonic-gate void
10207c478bd9Sstevel@tonic-gate idndl_dodetach(struct idnstr *stp)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate 	struct idnstr	*tstp;
10237c478bd9Sstevel@tonic-gate 	struct idn	*sip;
10247c478bd9Sstevel@tonic-gate 	int		reinit = 0;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	ASSERT(stp->ss_sip);
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	sip = stp->ss_sip;
10297c478bd9Sstevel@tonic-gate 	stp->ss_sip = NULL;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	/*
10327c478bd9Sstevel@tonic-gate 	 * Disable promiscuous mode if on.
10337c478bd9Sstevel@tonic-gate 	 */
10347c478bd9Sstevel@tonic-gate 	if (stp->ss_flags & IDNSALLPHYS) {
10357c478bd9Sstevel@tonic-gate 		stp->ss_flags &= ~IDNSALLPHYS;
10367c478bd9Sstevel@tonic-gate 		reinit = 1;
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/*
10407c478bd9Sstevel@tonic-gate 	 * Disable ALLMULTI mode if on.
10417c478bd9Sstevel@tonic-gate 	 */
10427c478bd9Sstevel@tonic-gate 	if (stp->ss_flags & IDNSALLMULTI) {
10437c478bd9Sstevel@tonic-gate 		stp->ss_flags &= ~IDNSALLMULTI;
10447c478bd9Sstevel@tonic-gate 		reinit = 1;
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	/*
10487c478bd9Sstevel@tonic-gate 	 * Disable any Multicast Addresses.
10497c478bd9Sstevel@tonic-gate 	 */
10507c478bd9Sstevel@tonic-gate 	stp->ss_mccount = 0;
10517c478bd9Sstevel@tonic-gate 	if (stp->ss_mctab) {
10527c478bd9Sstevel@tonic-gate 		kmem_free(stp->ss_mctab, IDNMCALLOC);
10537c478bd9Sstevel@tonic-gate 		stp->ss_mctab = NULL;
10547c478bd9Sstevel@tonic-gate 		reinit = 1;
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	/*
10587c478bd9Sstevel@tonic-gate 	 * Detach from device structure.
10597c478bd9Sstevel@tonic-gate 	 * Uninit the device when no other streams are attached to it.
10607c478bd9Sstevel@tonic-gate 	 */
10617c478bd9Sstevel@tonic-gate 	rw_enter(&idn.struprwlock, RW_READER);
10627c478bd9Sstevel@tonic-gate 	for (tstp = idn.strup; tstp; tstp = tstp->ss_nextp)
10637c478bd9Sstevel@tonic-gate 		if (tstp->ss_sip == sip)
10647c478bd9Sstevel@tonic-gate 			break;
10657c478bd9Sstevel@tonic-gate 	rw_exit(&idn.struprwlock);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	if (tstp == NULL)
10687c478bd9Sstevel@tonic-gate 		idndl_uninit(sip);
10697c478bd9Sstevel@tonic-gate 	else if (reinit)
10707c478bd9Sstevel@tonic-gate 		(void) idndl_init(sip);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	stp->ss_state = DL_UNATTACHED;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	idndl_setipq(sip);
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate static void
10787c478bd9Sstevel@tonic-gate idndl_breq(queue_t *wq, mblk_t *mp)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
10817c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
10827c478bd9Sstevel@tonic-gate 	struct idn		*sip;
10837c478bd9Sstevel@tonic-gate 	struct idndladdr	idnaddr;
10847c478bd9Sstevel@tonic-gate 	t_uscalar_t		sap;
10857c478bd9Sstevel@tonic-gate 	int		xidtest;
10867c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_breq";
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
10917c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0);
10927c478bd9Sstevel@tonic-gate 		return;
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	if (stp->ss_state != DL_UNBOUND) {
10967c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
10977c478bd9Sstevel@tonic-gate 		return;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	if (dlp->bind_req.dl_service_mode != idninfoack.dl_service_mode) {
11037c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
11047c478bd9Sstevel@tonic-gate 		return;
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	sip = stp->ss_sip;
11087c478bd9Sstevel@tonic-gate 	sap = dlp->bind_req.dl_sap;
11097c478bd9Sstevel@tonic-gate 	xidtest = dlp->bind_req.dl_xidtest_flg;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	ASSERT(sip);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	if (xidtest) {
11147c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0);
11157c478bd9Sstevel@tonic-gate 		return;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (sap > ETHERTYPE_MAX) {
11197c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, dlp->dl_primitive, DL_BADSAP, 0);
11207c478bd9Sstevel@tonic-gate 		return;
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/*
11247c478bd9Sstevel@tonic-gate 	 * Save SAP value for this Stream and change state.
11257c478bd9Sstevel@tonic-gate 	 */
11267c478bd9Sstevel@tonic-gate 	stp->ss_sap = sap;
11277c478bd9Sstevel@tonic-gate 	stp->ss_state = DL_IDLE;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	idnaddr.dl_sap = sap;
11307c478bd9Sstevel@tonic-gate 	ether_copy(&sip->si_ouraddr, &idnaddr.dl_phys);
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	if (IS_ETHERTYPE_IP(sap)) {
11337c478bd9Sstevel@tonic-gate 		int	channel;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 		channel =
11367c478bd9Sstevel@tonic-gate 			(int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL];
11377c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: IP SAP, opening channel %d\n", proc, channel);
11387c478bd9Sstevel@tonic-gate 		if (idn_open_channel(channel)) {
11397c478bd9Sstevel@tonic-gate 			PR_DLPI("%s: FAILED TO OPEN CHANNEL %d\n",
11407c478bd9Sstevel@tonic-gate 				proc, channel);
11417c478bd9Sstevel@tonic-gate 			DLERRORACK(wq, mp, dlp->dl_primitive, DL_NOADDR, 0);
11427c478bd9Sstevel@tonic-gate 			return;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 	DLBINDACK(wq, mp, sap, &idnaddr, IDNADDRL, 0, 0);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	idndl_setipq(sip);
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate static void
11517c478bd9Sstevel@tonic-gate idndl_ubreq(queue_t *wq, mblk_t *mp)
11527c478bd9Sstevel@tonic-gate {
11537c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
11547c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_ubreq";
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
11597c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0);
11607c478bd9Sstevel@tonic-gate 		return;
11617c478bd9Sstevel@tonic-gate 	}
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	if (stp->ss_state != DL_IDLE) {
11647c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
11657c478bd9Sstevel@tonic-gate 		return;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	stp->ss_state = DL_UNBOUND;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	if (IS_ETHERTYPE_IP(stp->ss_sap)) {
11717c478bd9Sstevel@tonic-gate 		struct idn	*sip;
11727c478bd9Sstevel@tonic-gate 		int		channel;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		sip = stp->ss_sip;
11757c478bd9Sstevel@tonic-gate 		channel =
11767c478bd9Sstevel@tonic-gate 			(int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL];
11777c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: IP SAP, unbinding channel %d\n", proc, channel);
11787c478bd9Sstevel@tonic-gate 		/*
11797c478bd9Sstevel@tonic-gate 		 * We need to do an "soft" close since there's a
11807c478bd9Sstevel@tonic-gate 		 * potential that we've been called by one of the
11817c478bd9Sstevel@tonic-gate 		 * IDN data server/dispatcher threads!  We'll deadlock
11827c478bd9Sstevel@tonic-gate 		 * if we attempt a "hard" close of the channel from here.
11837c478bd9Sstevel@tonic-gate 		 */
11847c478bd9Sstevel@tonic-gate 		idn_close_channel(channel, IDNCHAN_SOFT_CLOSE);
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	stp->ss_sap = 0;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_UNBIND_REQ);
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	idndl_setipq(stp->ss_sip);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate static void
11957c478bd9Sstevel@tonic-gate idndl_ireq(queue_t *wq, mblk_t *mp)
11967c478bd9Sstevel@tonic-gate {
11977c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
11987c478bd9Sstevel@tonic-gate 	dl_info_ack_t		*dlip;
11997c478bd9Sstevel@tonic-gate 	struct idndladdr	*dlap;
12007c478bd9Sstevel@tonic-gate 	struct ether_addr	*ep;
12017c478bd9Sstevel@tonic-gate 	int	size;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_INFO_REQ_SIZE) {
12067c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0);
12077c478bd9Sstevel@tonic-gate 		return;
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	/*
12117c478bd9Sstevel@tonic-gate 	 * Exchange current msg for a DL_INFO_ACK.
12127c478bd9Sstevel@tonic-gate 	 */
12137c478bd9Sstevel@tonic-gate 	size = sizeof (dl_info_ack_t) + IDNADDRL + ETHERADDRL;
12147c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL)
12157c478bd9Sstevel@tonic-gate 		return;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	/*
12187c478bd9Sstevel@tonic-gate 	 * Fill in the DL_INFO_ACK fields and reply.
12197c478bd9Sstevel@tonic-gate 	 */
12207c478bd9Sstevel@tonic-gate 	dlip = (dl_info_ack_t *)mp->b_rptr;
12217c478bd9Sstevel@tonic-gate 	ASSERT(idninfoack.dl_max_sdu);
12227c478bd9Sstevel@tonic-gate 	*dlip = idninfoack;
12237c478bd9Sstevel@tonic-gate 	dlip->dl_current_state = stp->ss_state;
12247c478bd9Sstevel@tonic-gate 	dlap = (struct idndladdr *)(mp->b_rptr + dlip->dl_addr_offset);
12257c478bd9Sstevel@tonic-gate 	dlap->dl_sap = stp->ss_sap;
12267c478bd9Sstevel@tonic-gate 	if (stp->ss_sip) {
12277c478bd9Sstevel@tonic-gate 		ether_copy(&stp->ss_sip->si_ouraddr, &dlap->dl_phys);
12287c478bd9Sstevel@tonic-gate 	} else {
12297c478bd9Sstevel@tonic-gate 		bzero(&dlap->dl_phys, ETHERADDRL);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 	ep = (struct ether_addr *)(mp->b_rptr + dlip->dl_brdcst_addr_offset);
12327c478bd9Sstevel@tonic-gate 	ether_copy(&etherbroadcastaddr, ep);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate static void
12387c478bd9Sstevel@tonic-gate idndl_ponreq(queue_t *wq, mblk_t *mp)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) {
12457c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
12467c478bd9Sstevel@tonic-gate 		return;
12477c478bd9Sstevel@tonic-gate 	}
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	switch (((dl_promiscon_req_t *)mp->b_rptr)->dl_level) {
12507c478bd9Sstevel@tonic-gate 	case DL_PROMISC_PHYS:
12517c478bd9Sstevel@tonic-gate 		stp->ss_flags |= IDNSALLPHYS;
12527c478bd9Sstevel@tonic-gate 		break;
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	case DL_PROMISC_SAP:
12557c478bd9Sstevel@tonic-gate 		stp->ss_flags |= IDNSALLSAP;
12567c478bd9Sstevel@tonic-gate 		break;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	case DL_PROMISC_MULTI:
12597c478bd9Sstevel@tonic-gate 		stp->ss_flags |= IDNSALLMULTI;
12607c478bd9Sstevel@tonic-gate 		break;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	default:
12637c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0);
12647c478bd9Sstevel@tonic-gate 		return;
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (stp->ss_sip)
12687c478bd9Sstevel@tonic-gate 		(void) idndl_init(stp->ss_sip);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	if (stp->ss_sip)
12717c478bd9Sstevel@tonic-gate 		idndl_setipq(stp->ss_sip);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_PROMISCON_REQ);
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate static void
12777c478bd9Sstevel@tonic-gate idndl_poffreq(queue_t *wq, mblk_t *mp)
12787c478bd9Sstevel@tonic-gate {
12797c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
12807c478bd9Sstevel@tonic-gate 	int		flag;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) {
12857c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
12867c478bd9Sstevel@tonic-gate 		return;
12877c478bd9Sstevel@tonic-gate 	}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	switch (((dl_promiscoff_req_t *)mp->b_rptr)->dl_level) {
12907c478bd9Sstevel@tonic-gate 	case DL_PROMISC_PHYS:
12917c478bd9Sstevel@tonic-gate 		flag = IDNSALLPHYS;
12927c478bd9Sstevel@tonic-gate 		break;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	case DL_PROMISC_SAP:
12957c478bd9Sstevel@tonic-gate 		flag = IDNSALLSAP;
12967c478bd9Sstevel@tonic-gate 		break;
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	case DL_PROMISC_MULTI:
12997c478bd9Sstevel@tonic-gate 		flag = IDNSALLMULTI;
13007c478bd9Sstevel@tonic-gate 		break;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	default:
13037c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0);
13047c478bd9Sstevel@tonic-gate 		return;
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	if ((stp->ss_flags & flag) == 0) {
13087c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
13097c478bd9Sstevel@tonic-gate 		return;
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	stp->ss_flags &= ~flag;
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	if (stp->ss_sip)
13157c478bd9Sstevel@tonic-gate 		(void) idndl_init(stp->ss_sip);
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	if (stp->ss_sip)
13187c478bd9Sstevel@tonic-gate 		idndl_setipq(stp->ss_sip);
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_PROMISCOFF_REQ);
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate static void
13247c478bd9Sstevel@tonic-gate idndl_emreq(queue_t *wq, mblk_t *mp)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
13277c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
13287c478bd9Sstevel@tonic-gate 	struct ether_addr	*addrp;
13297c478bd9Sstevel@tonic-gate 	int	off;
13307c478bd9Sstevel@tonic-gate 	int	len;
13317c478bd9Sstevel@tonic-gate 	int	i;
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_ENABMULTI_REQ_SIZE) {
13367c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0);
13377c478bd9Sstevel@tonic-gate 		return;
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (stp->ss_state == DL_UNATTACHED) {
13417c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0);
13427c478bd9Sstevel@tonic-gate 		return;
13437c478bd9Sstevel@tonic-gate 	}
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
13467c478bd9Sstevel@tonic-gate 	len = dlp->enabmulti_req.dl_addr_length;
13477c478bd9Sstevel@tonic-gate 	off = dlp->enabmulti_req.dl_addr_offset;
13487c478bd9Sstevel@tonic-gate 	addrp = (struct ether_addr *)(mp->b_rptr + off);
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	if ((len != ETHERADDRL) ||
13517c478bd9Sstevel@tonic-gate 		!MBLKIN(mp, off, len) ||
13527c478bd9Sstevel@tonic-gate 		!IDNDL_ADDR_IS_MULTICAST(addrp)) {
13537c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
13547c478bd9Sstevel@tonic-gate 		return;
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	if ((stp->ss_mccount + 1) >= IDNMAXMC) {
13587c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_ENABMULTI_REQ, DL_TOOMANY, 0);
13597c478bd9Sstevel@tonic-gate 		return;
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	/*
13637c478bd9Sstevel@tonic-gate 	 * Allocate table on first request.
13647c478bd9Sstevel@tonic-gate 	 */
13657c478bd9Sstevel@tonic-gate 	if (stp->ss_mctab == NULL)
13667c478bd9Sstevel@tonic-gate 		stp->ss_mctab = kmem_alloc(IDNMCALLOC, KM_SLEEP);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	/*
13697c478bd9Sstevel@tonic-gate 	 * Check to see if the address is already in the table.
13707c478bd9Sstevel@tonic-gate 	 * Bug 1209733:
13717c478bd9Sstevel@tonic-gate 	 * If present in the table, add the entry to the end of the table
13727c478bd9Sstevel@tonic-gate 	 * and return without initializing the hardware.
13737c478bd9Sstevel@tonic-gate 	 */
13747c478bd9Sstevel@tonic-gate 	for (i = 0; i < stp->ss_mccount; i++) {
13757c478bd9Sstevel@tonic-gate 		if (ether_cmp(&stp->ss_mctab[i], addrp) == 0) {
13767c478bd9Sstevel@tonic-gate 			stp->ss_mctab[stp->ss_mccount++] = *addrp;
13777c478bd9Sstevel@tonic-gate 			DLOKACK(wq, mp, DL_ENABMULTI_REQ);
13787c478bd9Sstevel@tonic-gate 			return;
13797c478bd9Sstevel@tonic-gate 		}
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	stp->ss_mctab[stp->ss_mccount++] = *addrp;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	(void) idndl_init(stp->ss_sip);
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_ENABMULTI_REQ);
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate static void
13907c478bd9Sstevel@tonic-gate idndl_dmreq(queue_t *wq, mblk_t *mp)
13917c478bd9Sstevel@tonic-gate {
13927c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
13937c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
13947c478bd9Sstevel@tonic-gate 	struct ether_addr	*addrp;
13957c478bd9Sstevel@tonic-gate 	int	off;
13967c478bd9Sstevel@tonic-gate 	int	len;
13977c478bd9Sstevel@tonic-gate 	int	i;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_DISABMULTI_REQ_SIZE) {
14027c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0);
14037c478bd9Sstevel@tonic-gate 		return;
14047c478bd9Sstevel@tonic-gate 	}
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	if (stp->ss_state == DL_UNATTACHED) {
14077c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0);
14087c478bd9Sstevel@tonic-gate 		return;
14097c478bd9Sstevel@tonic-gate 	}
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
14127c478bd9Sstevel@tonic-gate 	len = dlp->disabmulti_req.dl_addr_length;
14137c478bd9Sstevel@tonic-gate 	off = dlp->disabmulti_req.dl_addr_offset;
14147c478bd9Sstevel@tonic-gate 	addrp = (struct ether_addr *)(mp->b_rptr + off);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if ((len != ETHERADDRL) || !MBLKIN(mp, off, len)) {
14177c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
14187c478bd9Sstevel@tonic-gate 		return;
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	/*
14227c478bd9Sstevel@tonic-gate 	 * Find the address in the multicast table for this Stream
14237c478bd9Sstevel@tonic-gate 	 * and delete it by shifting all subsequent multicast
14247c478bd9Sstevel@tonic-gate 	 * table entries over one.
14257c478bd9Sstevel@tonic-gate 	 */
14267c478bd9Sstevel@tonic-gate 	for (i = 0; i < stp->ss_mccount; i++)
14277c478bd9Sstevel@tonic-gate 		if (ether_cmp(addrp, &stp->ss_mctab[i]) == 0) {
14287c478bd9Sstevel@tonic-gate 			bcopy(&stp->ss_mctab[i+1],
14297c478bd9Sstevel@tonic-gate 				&stp->ss_mctab[i],
14307c478bd9Sstevel@tonic-gate 				((stp->ss_mccount - i) *
14317c478bd9Sstevel@tonic-gate 				sizeof (struct ether_addr)));
14327c478bd9Sstevel@tonic-gate 			stp->ss_mccount--;
14337c478bd9Sstevel@tonic-gate 			(void) idndl_init(stp->ss_sip);
14347c478bd9Sstevel@tonic-gate 			DLOKACK(wq, mp, DL_DISABMULTI_REQ);
14357c478bd9Sstevel@tonic-gate 			return;
14367c478bd9Sstevel@tonic-gate 		}
14377c478bd9Sstevel@tonic-gate 	DLERRORACK(wq, mp, DL_DISABMULTI_REQ, DL_NOTENAB, 0);
14387c478bd9Sstevel@tonic-gate }
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate static void
14417c478bd9Sstevel@tonic-gate idndl_pareq(queue_t *wq, mblk_t *mp)
14427c478bd9Sstevel@tonic-gate {
14437c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
14447c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
14457c478bd9Sstevel@tonic-gate 	int			type;
14467c478bd9Sstevel@tonic-gate 	struct idn		*sip;
14477c478bd9Sstevel@tonic-gate 	struct ether_addr	addr;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) {
14527c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
14537c478bd9Sstevel@tonic-gate 		return;
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	dlp  = (union DL_primitives *)mp->b_rptr;
14577c478bd9Sstevel@tonic-gate 	type = dlp->physaddr_req.dl_addr_type;
14587c478bd9Sstevel@tonic-gate 	sip  = stp->ss_sip;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	if (sip == NULL) {
14617c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
14627c478bd9Sstevel@tonic-gate 		return;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	switch (type) {
14667c478bd9Sstevel@tonic-gate 	case DL_FACT_PHYS_ADDR:
14677c478bd9Sstevel@tonic-gate 		idndl_localetheraddr(sip, &addr);
14687c478bd9Sstevel@tonic-gate 		break;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	case DL_CURR_PHYS_ADDR:
14717c478bd9Sstevel@tonic-gate 		ether_copy(&sip->si_ouraddr, &addr);
14727c478bd9Sstevel@tonic-gate 		break;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	default:
14757c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_PHYS_ADDR_REQ, DL_NOTSUPPORTED, 0);
14767c478bd9Sstevel@tonic-gate 		return;
14777c478bd9Sstevel@tonic-gate 	}
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	DLPHYSADDRACK(wq, mp, &addr, ETHERADDRL);
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate #ifdef notdef
14837c478bd9Sstevel@tonic-gate static void
14847c478bd9Sstevel@tonic-gate idndl_spareq(queue_t *wq, mblk_t *mp)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	struct idnstr		*stp;
14877c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
14887c478bd9Sstevel@tonic-gate 	int	off;
14897c478bd9Sstevel@tonic-gate 	int	len;
14907c478bd9Sstevel@tonic-gate 	struct ether_addr	*addrp;
14917c478bd9Sstevel@tonic-gate 	struct idn		*sip;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < DL_SET_PHYS_ADDR_REQ_SIZE) {
14967c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0);
14977c478bd9Sstevel@tonic-gate 		return;
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
15017c478bd9Sstevel@tonic-gate 	len = dlp->set_physaddr_req.dl_addr_length;
15027c478bd9Sstevel@tonic-gate 	off = dlp->set_physaddr_req.dl_addr_offset;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len)) {
15057c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0);
15067c478bd9Sstevel@tonic-gate 		return;
15077c478bd9Sstevel@tonic-gate 	}
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	addrp = (struct ether_addr *)(mp->b_rptr + off);
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	/*
15127c478bd9Sstevel@tonic-gate 	 * Error if length of address isn't right or the address
15137c478bd9Sstevel@tonic-gate 	 * specified is a multicast or broadcast address.
15147c478bd9Sstevel@tonic-gate 	 */
15157c478bd9Sstevel@tonic-gate 	if ((len != ETHERADDRL) ||
15167c478bd9Sstevel@tonic-gate 	    IDNDL_ADDR_IS_MULTICAST(addrp) ||
15177c478bd9Sstevel@tonic-gate 	    (ether_cmp(addrp, &etherbroadcastaddr) == 0)) {
15187c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0);
15197c478bd9Sstevel@tonic-gate 		return;
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	/*
15237c478bd9Sstevel@tonic-gate 	 * Error if this stream is not attached to a device.
15247c478bd9Sstevel@tonic-gate 	 */
15257c478bd9Sstevel@tonic-gate 	if ((sip = stp->ss_sip) == NULL) {
15267c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
15277c478bd9Sstevel@tonic-gate 		return;
15287c478bd9Sstevel@tonic-gate 	}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/*
15317c478bd9Sstevel@tonic-gate 	 * Set new interface local address and re-init device.
15327c478bd9Sstevel@tonic-gate 	 * This is destructive to any other streams attached
15337c478bd9Sstevel@tonic-gate 	 * to this device.
15347c478bd9Sstevel@tonic-gate 	 */
15357c478bd9Sstevel@tonic-gate 	ether_copy(addrp, &sip->si_ouraddr);
15367c478bd9Sstevel@tonic-gate 	(void) idndl_init(stp->ss_sip);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	DLOKACK(wq, mp, DL_SET_PHYS_ADDR_REQ);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate #endif /* notdef */
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate static void
15437c478bd9Sstevel@tonic-gate idndl_udreq(queue_t *wq, mblk_t *mp)
15447c478bd9Sstevel@tonic-gate {
15457c478bd9Sstevel@tonic-gate 	struct idnstr			*stp;
15467c478bd9Sstevel@tonic-gate 	register struct idn		*sip;
15477c478bd9Sstevel@tonic-gate 	register dl_unitdata_req_t	*dludp;
15487c478bd9Sstevel@tonic-gate 	mblk_t				*nmp;
15497c478bd9Sstevel@tonic-gate 	struct idndladdr	*dlap;
15507c478bd9Sstevel@tonic-gate 	struct ether_header	*headerp;
15517c478bd9Sstevel@tonic-gate 	t_uscalar_t		off, len;
15527c478bd9Sstevel@tonic-gate 	t_uscalar_t		sap;
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
15557c478bd9Sstevel@tonic-gate 	sip = stp->ss_sip;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	if (stp->ss_state != DL_IDLE) {
15587c478bd9Sstevel@tonic-gate 		DLERRORACK(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
15597c478bd9Sstevel@tonic-gate 		return;
15607c478bd9Sstevel@tonic-gate 	}
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_rptr;
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	off = dludp->dl_dest_addr_offset;
15657c478bd9Sstevel@tonic-gate 	len = dludp->dl_dest_addr_length;
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	/*
15687c478bd9Sstevel@tonic-gate 	 * Validate destination address format.
15697c478bd9Sstevel@tonic-gate 	 */
15707c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len) || (len != IDNADDRL)) {
15717c478bd9Sstevel@tonic-gate 		dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADADDR, 0);
15727c478bd9Sstevel@tonic-gate 		return;
15737c478bd9Sstevel@tonic-gate 	}
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	/*
15767c478bd9Sstevel@tonic-gate 	 * Error if no M_DATA follows.
15777c478bd9Sstevel@tonic-gate 	 */
15787c478bd9Sstevel@tonic-gate 	nmp = mp->b_cont;
15797c478bd9Sstevel@tonic-gate 	if (nmp == NULL) {
15807c478bd9Sstevel@tonic-gate 		dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADDATA, 0);
15817c478bd9Sstevel@tonic-gate 		return;
15827c478bd9Sstevel@tonic-gate 	}
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	dlap = (struct idndladdr *)(mp->b_rptr + off);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	/*
15877c478bd9Sstevel@tonic-gate 	 * Create ethernet header by either prepending it onto the
15887c478bd9Sstevel@tonic-gate 	 * next mblk if potential, or reusing the M_PROTO block if not.
15897c478bd9Sstevel@tonic-gate 	 */
15907c478bd9Sstevel@tonic-gate 	if ((DB_REF(nmp) == 1) &&
15917c478bd9Sstevel@tonic-gate 	    (MBLKHEAD(nmp) >= sizeof (struct ether_header)) &&
15927c478bd9Sstevel@tonic-gate 	    (((ulong_t)nmp->b_rptr & 0x1) == 0)) {
15937c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct ether_header);
15947c478bd9Sstevel@tonic-gate 		headerp = (struct ether_header *)nmp->b_rptr;
15957c478bd9Sstevel@tonic-gate 		ether_copy(&dlap->dl_phys, &headerp->ether_dhost);
15967c478bd9Sstevel@tonic-gate 		ether_copy(&sip->si_ouraddr, &headerp->ether_shost);
15977c478bd9Sstevel@tonic-gate 		sap = dlap->dl_sap;
15987c478bd9Sstevel@tonic-gate 		freeb(mp);
15997c478bd9Sstevel@tonic-gate 		mp = nmp;
16007c478bd9Sstevel@tonic-gate 	} else {
16017c478bd9Sstevel@tonic-gate 		DB_TYPE(mp) = M_DATA;
16027c478bd9Sstevel@tonic-gate 		headerp = (struct ether_header *)mp->b_rptr;
16037c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (struct ether_header);
16047c478bd9Sstevel@tonic-gate 		ether_copy(&dlap->dl_phys, &headerp->ether_dhost);
16057c478bd9Sstevel@tonic-gate 		ether_copy(&sip->si_ouraddr, &headerp->ether_shost);
16067c478bd9Sstevel@tonic-gate 		sap = dlap->dl_sap;
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	/*
16107c478bd9Sstevel@tonic-gate 	 * For transmitting, the driver looks at the
16117c478bd9Sstevel@tonic-gate 	 * sap field of the DL_BIND_REQ being 0 in addition to the type
16127c478bd9Sstevel@tonic-gate 	 * field in the range [0-1500]. If either is true, then the driver
16137c478bd9Sstevel@tonic-gate 	 * computes the length of the message, not including initial M_PROTO
16147c478bd9Sstevel@tonic-gate 	 * mblk (message block), of all subsequent DL_UNITDATA_REQ messages and
16157c478bd9Sstevel@tonic-gate 	 * transmits 802.3 frames that have this value in the MAC frame header
16167c478bd9Sstevel@tonic-gate 	 * length field.
16177c478bd9Sstevel@tonic-gate 	 */
16187c478bd9Sstevel@tonic-gate 	if ((sap <= ETHERMTU) || (stp->ss_sap == 0))
16197c478bd9Sstevel@tonic-gate 		headerp->ether_type = (msgsize(mp) -
16207c478bd9Sstevel@tonic-gate 					sizeof (struct ether_header));
16217c478bd9Sstevel@tonic-gate 	else
16227c478bd9Sstevel@tonic-gate 		headerp->ether_type = sap;
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	/*
16257c478bd9Sstevel@tonic-gate 	 * The data transfer code requires only READ access (idn_wput_data).
16267c478bd9Sstevel@tonic-gate 	 */
16277c478bd9Sstevel@tonic-gate 	rw_downgrade(&stp->ss_rwlock);
16287c478bd9Sstevel@tonic-gate 	(void) idndl_start(wq, mp, sip);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate int
16327c478bd9Sstevel@tonic-gate idndl_start(queue_t *wq, register mblk_t *mp, register struct idn *sip)
16337c478bd9Sstevel@tonic-gate {
16347c478bd9Sstevel@tonic-gate 	int		rv = 0;
16357c478bd9Sstevel@tonic-gate 	int		flags;
16367c478bd9Sstevel@tonic-gate 	int		broadcast = 0;
16377c478bd9Sstevel@tonic-gate 	int		goagain = 0;
16387c478bd9Sstevel@tonic-gate 	int		goqueue = 0;
16397c478bd9Sstevel@tonic-gate 	int		msgcount;
16407c478bd9Sstevel@tonic-gate 	char		channel;
16417c478bd9Sstevel@tonic-gate 	mblk_t		*nmp = NULL;
16427c478bd9Sstevel@tonic-gate 	int		domid;
16437c478bd9Sstevel@tonic-gate 	domainset_t	domset;
16447c478bd9Sstevel@tonic-gate 	idn_netaddr_t	netaddr;
16457c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
16467c478bd9Sstevel@tonic-gate 	struct ether_header	*ehp;
16477c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_start";
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_DATA);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	stp = (struct idnstr *)wq->q_ptr;
16527c478bd9Sstevel@tonic-gate 	ASSERT(sip == stp->ss_sip);
16537c478bd9Sstevel@tonic-gate 	flags = sip->si_flags;
16547c478bd9Sstevel@tonic-gate 	channel = (char)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL];
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&stp->ss_rwlock));
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	if ((flags & (IDNRUNNING|IDNPROMISC)) != IDNRUNNING) {
16597c478bd9Sstevel@tonic-gate 		if (!(flags & IDNRUNNING))
16607c478bd9Sstevel@tonic-gate 			goto requeue;
16617c478bd9Sstevel@tonic-gate 	}
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	/*
16647c478bd9Sstevel@tonic-gate 	 * Translate an IDN ethernet address into a domainid
16657c478bd9Sstevel@tonic-gate 	 * and idnaddr.
16667c478bd9Sstevel@tonic-gate 	 */
16677c478bd9Sstevel@tonic-gate 	ehp = (struct ether_header *)mp->b_rptr;
16687c478bd9Sstevel@tonic-gate 	domid = IDNDL_ETHER2DOMAIN(&ehp->ether_dhost);
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	/*
16717c478bd9Sstevel@tonic-gate 	 * update MIB II statistics
16727c478bd9Sstevel@tonic-gate 	 */
16737c478bd9Sstevel@tonic-gate 	BUMP_OutNUcast(sip, ehp);
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: ether %x:%x:%x:%x:%x:%x (domid = %d)\n",
16767c478bd9Sstevel@tonic-gate 		proc, ehp->ether_dhost.ether_addr_octet[0],
16777c478bd9Sstevel@tonic-gate 		ehp->ether_dhost.ether_addr_octet[1],
16787c478bd9Sstevel@tonic-gate 		ehp->ether_dhost.ether_addr_octet[2],
16797c478bd9Sstevel@tonic-gate 		ehp->ether_dhost.ether_addr_octet[3],
16807c478bd9Sstevel@tonic-gate 		ehp->ether_dhost.ether_addr_octet[4],
16817c478bd9Sstevel@tonic-gate 		ehp->ether_dhost.ether_addr_octet[5],
16827c478bd9Sstevel@tonic-gate 		domid);
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	netaddr.net.chan = channel;
16857c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: source channel = %d\n", proc, (int)channel);
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	if ((ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0) ||
16887c478bd9Sstevel@tonic-gate 			IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost)) {
16897c478bd9Sstevel@tonic-gate 		/*
16907c478bd9Sstevel@tonic-gate 		 * Caller wants to broadcast!
16917c478bd9Sstevel@tonic-gate 		 * XXX - Send to everybody but ourself???
16927c478bd9Sstevel@tonic-gate 		 */
16937c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: broadcast/multicast requested!!!\n", proc);
16947c478bd9Sstevel@tonic-gate 		domset = ~DOMAINSET(idn.localid);
16957c478bd9Sstevel@tonic-gate 		broadcast = 1;
16967c478bd9Sstevel@tonic-gate 		netaddr.net.netid = IDN_BROADCAST_ALLNETID;
16977c478bd9Sstevel@tonic-gate 		if ((flags & IDNPROMISC) &&
16987c478bd9Sstevel@tonic-gate 		    ((nmp = copymsg(mp)) == NULL)) {
16997c478bd9Sstevel@tonic-gate 			IDN_KSTAT_INC(sip, si_allocbfail);
17007c478bd9Sstevel@tonic-gate 		}
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	} else if (domid != IDN_NIL_DOMID) {
17037c478bd9Sstevel@tonic-gate 		domset = DOMAINSET(domid);
17047c478bd9Sstevel@tonic-gate 		netaddr.net.netid = idn_domain[domid].dnetid;
17057c478bd9Sstevel@tonic-gate 		if ((flags & IDNPROMISC) &&
17067c478bd9Sstevel@tonic-gate 		    ((nmp = copymsg(mp)) == NULL)) {
17077c478bd9Sstevel@tonic-gate 			IDN_KSTAT_INC(sip, si_allocbfail);
17087c478bd9Sstevel@tonic-gate 		}
17097c478bd9Sstevel@tonic-gate 	} else {
17107c478bd9Sstevel@tonic-gate #ifdef DEBUG
17117c478bd9Sstevel@tonic-gate 		int	netid;
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 		netid = (int)
17147c478bd9Sstevel@tonic-gate 			ehp->ether_dhost.ether_addr_octet[IDNETHER_NETID];
17157c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: no domain found for netid 0x%x\n",
17167c478bd9Sstevel@tonic-gate 			proc, netid);
17177c478bd9Sstevel@tonic-gate #endif /* DEBUG */
17187c478bd9Sstevel@tonic-gate 		goto bad;
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: target domainset = 0x%x\n", proc, domset);
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	if ((domset == 0) && (domid == IDN_NIL_DOMID)) {
17247c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: not connected to any domains!!  Bailing\n",
17257c478bd9Sstevel@tonic-gate 			proc);
17267c478bd9Sstevel@tonic-gate 		goto bad;
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 	/*
17297c478bd9Sstevel@tonic-gate 	 * XXX - Need to find a better way to handle broadcasting.
17307c478bd9Sstevel@tonic-gate 	 *	 Should be able to take advantage of the fact that
17317c478bd9Sstevel@tonic-gate 	 *	 we can broadcast XDC's (xdc_some).  Need to use
17327c478bd9Sstevel@tonic-gate 	 *	 atomic counter (semaphore) instead of binary
17337c478bd9Sstevel@tonic-gate 	 *	 "owner" flag, or perhaps domain specific owner bytes.
17347c478bd9Sstevel@tonic-gate 	 *
17357c478bd9Sstevel@tonic-gate 	 * Transfer the data.
17367c478bd9Sstevel@tonic-gate 	 */
17377c478bd9Sstevel@tonic-gate 	msgcount = 0;
17387c478bd9Sstevel@tonic-gate 	if (!broadcast)
17397c478bd9Sstevel@tonic-gate 		goto noloop;
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	for (domid = 0; domid < MAX_DOMAINS; domid++) {
17427c478bd9Sstevel@tonic-gate 		if (!DOMAIN_IN_SET(domset, domid))
17437c478bd9Sstevel@tonic-gate 			continue;
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate noloop:
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 		if (idn_domain[domid].dcpu == IDN_NIL_DCPU) {
17487c478bd9Sstevel@tonic-gate 			if (broadcast)
17497c478bd9Sstevel@tonic-gate 				continue;
17507c478bd9Sstevel@tonic-gate 			else
17517c478bd9Sstevel@tonic-gate 				break;
17527c478bd9Sstevel@tonic-gate 		}
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 		rv = idn_send_data(domid, netaddr, wq, mp);
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 		switch (rv) {
17577c478bd9Sstevel@tonic-gate 		case IDNXMIT_LOOP:	/* handled in loopback */
17587c478bd9Sstevel@tonic-gate 			msgcount++;
17597c478bd9Sstevel@tonic-gate 			break;
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 		case IDNXMIT_OKAY:	/* handled, okay to free */
17627c478bd9Sstevel@tonic-gate 			msgcount++;
17637c478bd9Sstevel@tonic-gate 			break;
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 		case IDNXMIT_RETRY:
17667c478bd9Sstevel@tonic-gate 			if (!broadcast)
17677c478bd9Sstevel@tonic-gate 				goto tryagain;
17687c478bd9Sstevel@tonic-gate 			goagain++;
17697c478bd9Sstevel@tonic-gate 			break;
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate 		case IDNXMIT_REQUEUE:
17727c478bd9Sstevel@tonic-gate 			if (!broadcast)
17737c478bd9Sstevel@tonic-gate 				goto requeue;
17747c478bd9Sstevel@tonic-gate 			goqueue++;
17757c478bd9Sstevel@tonic-gate 			break;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 		default:
17787c478bd9Sstevel@tonic-gate 			if (!broadcast)
17797c478bd9Sstevel@tonic-gate 				goto bad;
17807c478bd9Sstevel@tonic-gate 			break;
17817c478bd9Sstevel@tonic-gate 		}
17827c478bd9Sstevel@tonic-gate 		if (!broadcast)
17837c478bd9Sstevel@tonic-gate 			break;
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	if (msgcount == 0)
17877c478bd9Sstevel@tonic-gate 		if (goqueue)
17887c478bd9Sstevel@tonic-gate 			goto requeue;
17897c478bd9Sstevel@tonic-gate 		else if (goagain)
17907c478bd9Sstevel@tonic-gate 			goto tryagain;
17917c478bd9Sstevel@tonic-gate 		else
17927c478bd9Sstevel@tonic-gate 			goto bad;
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	if ((flags & IDNPROMISC) && nmp)
17957c478bd9Sstevel@tonic-gate 		idndl_sendup(sip, nmp, idndl_paccept);
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	freemsg(mp);
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: successful transmit to domainset 0x%x.\n",
18007c478bd9Sstevel@tonic-gate 		proc, domset);
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	return (0);
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate bad:
18057c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: bad transmission to domainset 0x%x, dropping msg.\n",
18067c478bd9Sstevel@tonic-gate 		proc, domset);
18077c478bd9Sstevel@tonic-gate 	if (nmp)
18087c478bd9Sstevel@tonic-gate 		freemsg(nmp);
18097c478bd9Sstevel@tonic-gate 	freemsg(mp);
18107c478bd9Sstevel@tonic-gate 	qenable(wq);
18117c478bd9Sstevel@tonic-gate 	return (1);
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate requeue:
18147c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: requeue for domainset 0x%x, no qenable\n",
18157c478bd9Sstevel@tonic-gate 		proc, domset);
18167c478bd9Sstevel@tonic-gate 	if (nmp)
18177c478bd9Sstevel@tonic-gate 		freemsg(nmp);
18187c478bd9Sstevel@tonic-gate 	if (putbq(wq, mp) == 0)
18197c478bd9Sstevel@tonic-gate 		freemsg(mp);
18207c478bd9Sstevel@tonic-gate 	return (1);
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate tryagain:
18237c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: try again to domainset 0x%x, putbq.\n",
18247c478bd9Sstevel@tonic-gate 		proc, domset);
18257c478bd9Sstevel@tonic-gate 	if (nmp)
18267c478bd9Sstevel@tonic-gate 		freemsg(nmp);
18277c478bd9Sstevel@tonic-gate 	if (putbq(wq, mp) == 0)
18287c478bd9Sstevel@tonic-gate 		freemsg(mp);
18297c478bd9Sstevel@tonic-gate 	qenable(wq);
18307c478bd9Sstevel@tonic-gate 	return (1);
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate /*
18347c478bd9Sstevel@tonic-gate  * Called by:	idnh_recv_data, idn_recv_mboxdata.
18357c478bd9Sstevel@tonic-gate  */
18367c478bd9Sstevel@tonic-gate void
18377c478bd9Sstevel@tonic-gate idndl_read(struct idn *sip, mblk_t *mp)
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate 	struct ether_header	*ehp;
18407c478bd9Sstevel@tonic-gate 	queue_t			*ip4q;
18417c478bd9Sstevel@tonic-gate 	queue_t			*ip6q;
18427c478bd9Sstevel@tonic-gate 	int		pktlen;
18437c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_read";
18447c478bd9Sstevel@tonic-gate 
1845bf30efa4Smathue 	PR_DLPI("%s: incoming msgsize = %lu, msgdsize = %lu\n",
18467c478bd9Sstevel@tonic-gate 		proc, msgsize(mp), msgdsize(mp));
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	ehp = (struct ether_header *)mp->b_rptr;
18497c478bd9Sstevel@tonic-gate 	if (sip == NULL)
18507c478bd9Sstevel@tonic-gate 		sip = IDNDL_ETHER2SIP(&ehp->ether_dhost);
18517c478bd9Sstevel@tonic-gate 	if (sip == NULL) {
18527c478bd9Sstevel@tonic-gate 		/*
18537c478bd9Sstevel@tonic-gate 		 * If the sip is NULL, then I don't have a connection
18547c478bd9Sstevel@tonic-gate 		 * for this network.  No point in sending the message
18557c478bd9Sstevel@tonic-gate 		 * up.
18567c478bd9Sstevel@tonic-gate 		 */
18577c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: no plumbing to send message through.\n",
18587c478bd9Sstevel@tonic-gate 			proc);
18597c478bd9Sstevel@tonic-gate 		freemsg(mp);
18607c478bd9Sstevel@tonic-gate 		return;
18617c478bd9Sstevel@tonic-gate 	}
18627c478bd9Sstevel@tonic-gate 	IDN_KSTAT_INC(sip, si_ipackets);
18637c478bd9Sstevel@tonic-gate 	IDN_KSTAT_INC(sip, si_ipackets64);
18647c478bd9Sstevel@tonic-gate 	/*
18657c478bd9Sstevel@tonic-gate 	 * update MIB II statistics
18667c478bd9Sstevel@tonic-gate 	 */
18677c478bd9Sstevel@tonic-gate 	pktlen = mp->b_wptr - mp->b_rptr;
18687c478bd9Sstevel@tonic-gate 	BUMP_InNUcast(sip, ehp);
18697c478bd9Sstevel@tonic-gate 	IDN_KSTAT_ADD(sip, si_rcvbytes, pktlen);
18707c478bd9Sstevel@tonic-gate 	IDN_KSTAT_ADD(sip, si_rbytes64, (uint64_t)pktlen);
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	ip4q = sip->si_ip4q;
18737c478bd9Sstevel@tonic-gate 	ip6q = sip->si_ip6q;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	if (IS_ETHERTYPE_IPV4(ehp->ether_type) &&
18767c478bd9Sstevel@tonic-gate 			!IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) &&
18777c478bd9Sstevel@tonic-gate 			ip4q &&
18787c478bd9Sstevel@tonic-gate 			canputnext(ip4q)) {
18797c478bd9Sstevel@tonic-gate 		mp->b_rptr += sizeof (struct ether_header);
18807c478bd9Sstevel@tonic-gate 		(void) putnext(ip4q, mp);
18817c478bd9Sstevel@tonic-gate 		/*LINTED*/
18827c478bd9Sstevel@tonic-gate 	} else if (IS_ETHERTYPE_IPV6(ehp->ether_type) &&
18837c478bd9Sstevel@tonic-gate 			!IDNDL_ADDR_IS_MULTICAST(&ehp->ether_dhost) &&
18847c478bd9Sstevel@tonic-gate 			ip6q &&
18857c478bd9Sstevel@tonic-gate 			canputnext(ip6q)) {
18867c478bd9Sstevel@tonic-gate 		mp->b_rptr += sizeof (struct ether_header);
18877c478bd9Sstevel@tonic-gate 		(void) putnext(ip6q, mp);
18887c478bd9Sstevel@tonic-gate 	} else {
18897c478bd9Sstevel@tonic-gate 		/*
18907c478bd9Sstevel@tonic-gate 		 * Strip the PADs for 802.3
18917c478bd9Sstevel@tonic-gate 		 */
18927c478bd9Sstevel@tonic-gate 		pktlen = ehp->ether_type + sizeof (struct ether_header);
18937c478bd9Sstevel@tonic-gate 		PR_DLPI("%s: stripping PADs for 802.3 (pktlen=%d)\n",
18947c478bd9Sstevel@tonic-gate 			proc, pktlen);
18957c478bd9Sstevel@tonic-gate 		if (pktlen < ETHERMIN)
18967c478bd9Sstevel@tonic-gate 			mp->b_wptr = mp->b_rptr + pktlen;
18977c478bd9Sstevel@tonic-gate 		idndl_sendup(sip, mp, idndl_accept);
18987c478bd9Sstevel@tonic-gate 	}
18997c478bd9Sstevel@tonic-gate }
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate int
19027c478bd9Sstevel@tonic-gate idndl_init(struct idn *sip)
19037c478bd9Sstevel@tonic-gate {
19047c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	if (sip->si_flags & IDNSUSPENDED)
19077c478bd9Sstevel@tonic-gate 		(void) ddi_dev_is_needed(sip->si_dip, 0, 1);
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	sip->si_flags = 0;
19107c478bd9Sstevel@tonic-gate 	sip->si_wantw = 0;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	IDN_KSTAT_INC(sip, si_inits);
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	rw_enter(&idn.struprwlock, RW_WRITER);
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	for (stp = idn.strup; stp; stp = stp->ss_nextp) {
19177c478bd9Sstevel@tonic-gate 		if ((stp->ss_sip == sip) && (stp->ss_flags & IDNSALLPHYS)) {
19187c478bd9Sstevel@tonic-gate 			sip->si_flags |= IDNPROMISC;
19197c478bd9Sstevel@tonic-gate 			break;
19207c478bd9Sstevel@tonic-gate 		}
19217c478bd9Sstevel@tonic-gate 	}
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	sip->si_flags |= IDNRUNNING;
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	mutex_enter(&idn.sipwenlock);
19267c478bd9Sstevel@tonic-gate 	idndl_wenable(sip);
19277c478bd9Sstevel@tonic-gate 	mutex_exit(&idn.sipwenlock);
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	rw_exit(&idn.struprwlock);
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	return (!(sip->si_flags & IDNRUNNING));
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate void
19357c478bd9Sstevel@tonic-gate idndl_uninit(struct idn *sip)
19367c478bd9Sstevel@tonic-gate {
19377c478bd9Sstevel@tonic-gate 	int		channel;
19387c478bd9Sstevel@tonic-gate 	procname_t	proc = "idndl_uninit";
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	sip->si_flags &= ~IDNRUNNING;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	channel = (int)sip->si_ouraddr.ether_addr_octet[IDNETHER_CHANNEL];
19437c478bd9Sstevel@tonic-gate 	PR_DLPI("%s: IP SAP, uninit channel %d\n", proc, channel);
19447c478bd9Sstevel@tonic-gate 	/*
19457c478bd9Sstevel@tonic-gate 	 * A uninit is a hard close of an interface.
19467c478bd9Sstevel@tonic-gate 	 */
19477c478bd9Sstevel@tonic-gate 	idn_close_channel(channel, IDNCHAN_HARD_CLOSE);
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate /*
19517c478bd9Sstevel@tonic-gate  * Send packet upstream.
19527c478bd9Sstevel@tonic-gate  * Assume mp->b_rptr points to ether_header.
19537c478bd9Sstevel@tonic-gate  */
19547c478bd9Sstevel@tonic-gate void
19557c478bd9Sstevel@tonic-gate idndl_sendup(struct idn *sip, mblk_t *mp, struct idnstr *(*acceptfunc)())
19567c478bd9Sstevel@tonic-gate {
19577c478bd9Sstevel@tonic-gate 	int			type;
19587c478bd9Sstevel@tonic-gate 	struct ether_addr	*dhostp, *shostp;
19597c478bd9Sstevel@tonic-gate 	struct idnstr		*stp, *nstp;
19607c478bd9Sstevel@tonic-gate 	mblk_t 		*nmp;
19617c478bd9Sstevel@tonic-gate 	ulong_t		isgroupaddr;
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_START, "idnsendup start");
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	dhostp = &((struct ether_header *)mp->b_rptr)->ether_dhost;
19667c478bd9Sstevel@tonic-gate 	shostp = &((struct ether_header *)mp->b_rptr)->ether_shost;
19677c478bd9Sstevel@tonic-gate 	type = ((struct ether_header *)mp->b_rptr)->ether_type;
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	isgroupaddr = IDNDL_ADDR_IS_MULTICAST(dhostp);
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	/*
19727c478bd9Sstevel@tonic-gate 	 * While holding a reader lock on the linked list of streams structures,
19737c478bd9Sstevel@tonic-gate 	 * attempt to match the address criteria for each stream
19747c478bd9Sstevel@tonic-gate 	 * and pass up the raw M_DATA ("fastpath") or a DL_UNITDATA_IND.
19757c478bd9Sstevel@tonic-gate 	 */
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	rw_enter(&idn.struprwlock, RW_READER);
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	if ((stp = (*acceptfunc)(idn.strup, sip, type, dhostp)) == NULL) {
19807c478bd9Sstevel@tonic-gate 		rw_exit(&idn.struprwlock);
19817c478bd9Sstevel@tonic-gate 		freemsg(mp);
19827c478bd9Sstevel@tonic-gate 		TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end");
19837c478bd9Sstevel@tonic-gate 		return;
19847c478bd9Sstevel@tonic-gate 	}
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	/*
19877c478bd9Sstevel@tonic-gate 	 * Loop on matching open streams until (*acceptfunc)() returns NULL.
19887c478bd9Sstevel@tonic-gate 	 */
19897c478bd9Sstevel@tonic-gate 	for (; nstp = (*acceptfunc)(stp->ss_nextp, sip, type, dhostp);
19907c478bd9Sstevel@tonic-gate 		stp = nstp) {
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 		if (canputnext(stp->ss_rq) == 0) {
19937c478bd9Sstevel@tonic-gate 			IDN_KSTAT_INC(sip, si_nocanput);
19947c478bd9Sstevel@tonic-gate 			continue;
19957c478bd9Sstevel@tonic-gate 		}
19967c478bd9Sstevel@tonic-gate 		if ((nmp = dupmsg(mp)) == NULL)
19977c478bd9Sstevel@tonic-gate 			nmp = copymsg(mp);
19987c478bd9Sstevel@tonic-gate 		if (nmp) {
19997c478bd9Sstevel@tonic-gate 			if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) {
20007c478bd9Sstevel@tonic-gate 				nmp->b_rptr += sizeof (struct ether_header);
20017c478bd9Sstevel@tonic-gate 				(void) putnext(stp->ss_rq, nmp);
20027c478bd9Sstevel@tonic-gate 			} else if (stp->ss_flags & IDNSRAW) {
20037c478bd9Sstevel@tonic-gate 				(void) putnext(stp->ss_rq, nmp);
20047c478bd9Sstevel@tonic-gate 			} else if ((nmp = idndl_addudind(sip, nmp, shostp,
20057c478bd9Sstevel@tonic-gate 						dhostp, type, isgroupaddr))) {
20067c478bd9Sstevel@tonic-gate 				(void) putnext(stp->ss_rq, nmp);
20077c478bd9Sstevel@tonic-gate 			}
20087c478bd9Sstevel@tonic-gate 		} else {
20097c478bd9Sstevel@tonic-gate 			IDN_KSTAT_INC(sip, si_allocbfail);
20107c478bd9Sstevel@tonic-gate 		}
20117c478bd9Sstevel@tonic-gate 	}
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	/*
20157c478bd9Sstevel@tonic-gate 	 * Do the last one.
20167c478bd9Sstevel@tonic-gate 	 */
20177c478bd9Sstevel@tonic-gate 	if (canputnext(stp->ss_rq)) {
20187c478bd9Sstevel@tonic-gate 		if ((stp->ss_flags & IDNSFAST) && !isgroupaddr) {
20197c478bd9Sstevel@tonic-gate 			mp->b_rptr += sizeof (struct ether_header);
20207c478bd9Sstevel@tonic-gate 			(void) putnext(stp->ss_rq, mp);
20217c478bd9Sstevel@tonic-gate 		} else if (stp->ss_flags & IDNSRAW) {
20227c478bd9Sstevel@tonic-gate 			(void) putnext(stp->ss_rq, mp);
20237c478bd9Sstevel@tonic-gate 		} else if ((mp = idndl_addudind(sip, mp, shostp, dhostp,
20247c478bd9Sstevel@tonic-gate 					    type, isgroupaddr))) {
20257c478bd9Sstevel@tonic-gate 			(void) putnext(stp->ss_rq, mp);
20267c478bd9Sstevel@tonic-gate 		}
20277c478bd9Sstevel@tonic-gate 	} else {
20287c478bd9Sstevel@tonic-gate 		freemsg(mp);
20297c478bd9Sstevel@tonic-gate 		IDN_KSTAT_INC(sip, si_nocanput);
20307c478bd9Sstevel@tonic-gate 		IDN_KSTAT_INC(sip, si_norcvbuf);	/* MIB II */
20317c478bd9Sstevel@tonic-gate 	}
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	rw_exit(&idn.struprwlock);
20347c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_IDN, TR_IDN_SENDUP_END, "idnsendup end");
20357c478bd9Sstevel@tonic-gate }
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate /*
20387c478bd9Sstevel@tonic-gate  * Test upstream destination sap and address match.
20397c478bd9Sstevel@tonic-gate  */
20407c478bd9Sstevel@tonic-gate struct idnstr *
20417c478bd9Sstevel@tonic-gate idndl_accept(register struct idnstr *stp, register struct idn *sip,
20427c478bd9Sstevel@tonic-gate 	    int type, struct ether_addr *addrp)
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate 	t_uscalar_t	sap;
20457c478bd9Sstevel@tonic-gate 	uint_t		flags;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	for (; stp; stp = stp->ss_nextp) {
20487c478bd9Sstevel@tonic-gate 		sap   = stp->ss_sap;
20497c478bd9Sstevel@tonic-gate 		flags = stp->ss_flags;
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 		if ((stp->ss_sip == sip) && IDNSAPMATCH(sap, type, flags))
20527c478bd9Sstevel@tonic-gate 			if ((ether_cmp(addrp, &sip->si_ouraddr) == 0) ||
20537c478bd9Sstevel@tonic-gate 			    (ether_cmp(addrp, &etherbroadcastaddr) == 0) ||
20547c478bd9Sstevel@tonic-gate 			    (flags & IDNSALLPHYS) ||
20557c478bd9Sstevel@tonic-gate 			    idndl_mcmatch(stp, addrp))
20567c478bd9Sstevel@tonic-gate 				return (stp);
20577c478bd9Sstevel@tonic-gate 	}
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	return (NULL);
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate /*
20637c478bd9Sstevel@tonic-gate  * Test upstream destination sap and address match for IDNSALLPHYS only.
20647c478bd9Sstevel@tonic-gate  */
20657c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
20667c478bd9Sstevel@tonic-gate struct idnstr *
20677c478bd9Sstevel@tonic-gate idndl_paccept(register struct idnstr *stp, register struct idn *sip,
20687c478bd9Sstevel@tonic-gate 	    int type, struct ether_addr *addrp)
20697c478bd9Sstevel@tonic-gate {
20707c478bd9Sstevel@tonic-gate 	t_uscalar_t	sap;
20717c478bd9Sstevel@tonic-gate 	uint_t		flags;
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	for (; stp; stp = stp->ss_nextp) {
20747c478bd9Sstevel@tonic-gate 		sap   = stp->ss_sap;
20757c478bd9Sstevel@tonic-gate 		flags = stp->ss_flags;
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 		if ((stp->ss_sip == sip) &&
20787c478bd9Sstevel@tonic-gate 		    IDNSAPMATCH(sap, type, flags) &&
20797c478bd9Sstevel@tonic-gate 		    (flags & IDNSALLPHYS))
20807c478bd9Sstevel@tonic-gate 			return (stp);
20817c478bd9Sstevel@tonic-gate 	}
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	return (NULL);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate /*
20877c478bd9Sstevel@tonic-gate  * Set or clear the device ipq pointer.
20887c478bd9Sstevel@tonic-gate  * Assumes IPv4 and IPv6 are IDNSFAST.
20897c478bd9Sstevel@tonic-gate  */
20907c478bd9Sstevel@tonic-gate static void
20917c478bd9Sstevel@tonic-gate idndl_setipq(struct idn *sip)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
20947c478bd9Sstevel@tonic-gate 	int		ok4 = 1;
20957c478bd9Sstevel@tonic-gate 	int		ok6 = 1;
20967c478bd9Sstevel@tonic-gate 	queue_t		*ip4q = NULL;
20977c478bd9Sstevel@tonic-gate 	queue_t		*ip6q = NULL;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	rw_enter(&idn.struprwlock, RW_READER);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	for (stp = idn.strup; stp; stp = stp->ss_nextp) {
21027c478bd9Sstevel@tonic-gate 		if (stp->ss_sip == sip) {
21037c478bd9Sstevel@tonic-gate 			if (stp->ss_flags & (IDNSALLPHYS|IDNSALLSAP)) {
21047c478bd9Sstevel@tonic-gate 				ok4 = 0;
21057c478bd9Sstevel@tonic-gate 				ok6 = 0;
21067c478bd9Sstevel@tonic-gate 				break;
21077c478bd9Sstevel@tonic-gate 			}
21087c478bd9Sstevel@tonic-gate 			if (IS_ETHERTYPE_IPV4(stp->ss_sap)) {
21097c478bd9Sstevel@tonic-gate 				if (ip4q == NULL)
21107c478bd9Sstevel@tonic-gate 					ip4q = stp->ss_rq;
21117c478bd9Sstevel@tonic-gate 				else
21127c478bd9Sstevel@tonic-gate 					ok4 = 0;
21137c478bd9Sstevel@tonic-gate 				/*LINTED*/
21147c478bd9Sstevel@tonic-gate 			} else if (IS_ETHERTYPE_IPV6(stp->ss_sap)) {
21157c478bd9Sstevel@tonic-gate 				if (ip6q == NULL)
21167c478bd9Sstevel@tonic-gate 					ip6q = stp->ss_rq;
21177c478bd9Sstevel@tonic-gate 				else
21187c478bd9Sstevel@tonic-gate 					ok6 = 0;
21197c478bd9Sstevel@tonic-gate 			}
21207c478bd9Sstevel@tonic-gate 		}
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	rw_exit(&idn.struprwlock);
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	if (ok4)
21267c478bd9Sstevel@tonic-gate 		sip->si_ip4q = ip4q;
21277c478bd9Sstevel@tonic-gate 	else
21287c478bd9Sstevel@tonic-gate 		sip->si_ip4q = NULL;
21297c478bd9Sstevel@tonic-gate 	if (ok6)
21307c478bd9Sstevel@tonic-gate 		sip->si_ip6q = ip6q;
21317c478bd9Sstevel@tonic-gate 	else
21327c478bd9Sstevel@tonic-gate 		sip->si_ip6q = NULL;
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate /*
21367c478bd9Sstevel@tonic-gate  * Prefix msg with a DL_UNITDATA_IND mblk and return the new msg.
21377c478bd9Sstevel@tonic-gate  */
21387c478bd9Sstevel@tonic-gate static mblk_t *
21397c478bd9Sstevel@tonic-gate idndl_addudind(struct idn *sip, mblk_t *mp,
21407c478bd9Sstevel@tonic-gate 	    struct ether_addr *shostp, struct ether_addr *dhostp,
21417c478bd9Sstevel@tonic-gate 	    int type, ulong_t isgroupaddr)
21427c478bd9Sstevel@tonic-gate {
21437c478bd9Sstevel@tonic-gate 	dl_unitdata_ind_t	*dludindp;
21447c478bd9Sstevel@tonic-gate 	struct idndladdr	*dlap;
21457c478bd9Sstevel@tonic-gate 	mblk_t	*nmp;
21467c478bd9Sstevel@tonic-gate 	int	size;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_START, "idndl_addudind start");
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	mp->b_rptr += sizeof (struct ether_header);
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	/*
21537c478bd9Sstevel@tonic-gate 	 * Allocate an M_PROTO mblk for the DL_UNITDATA_IND.
21547c478bd9Sstevel@tonic-gate 	 */
21557c478bd9Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) + IDNADDRL + IDNADDRL;
21567c478bd9Sstevel@tonic-gate 	nmp = allocb(IDNROUNDUP(IDNHEADROOM + size, sizeof (double)), BPRI_LO);
21577c478bd9Sstevel@tonic-gate 	if (nmp == NULL) {
21587c478bd9Sstevel@tonic-gate 		IDN_KSTAT_INC(sip, si_allocbfail);
21597c478bd9Sstevel@tonic-gate 		IDN_KSTAT_INC(sip, si_ierrors);
21607c478bd9Sstevel@tonic-gate 		if (idn_debug)
21617c478bd9Sstevel@tonic-gate 			serror(sip->si_dip, 451, "allocb failed");
21627c478bd9Sstevel@tonic-gate 		freemsg(mp);
21637c478bd9Sstevel@tonic-gate 		TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end");
21647c478bd9Sstevel@tonic-gate 		return (NULL);
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 	DB_TYPE(nmp) = M_PROTO;
21677c478bd9Sstevel@tonic-gate 	nmp->b_wptr = nmp->b_datap->db_lim;
21687c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr - size;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 	/*
21717c478bd9Sstevel@tonic-gate 	 * Construct a DL_UNITDATA_IND primitive.
21727c478bd9Sstevel@tonic-gate 	 */
21737c478bd9Sstevel@tonic-gate 	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
21747c478bd9Sstevel@tonic-gate 	dludindp->dl_primitive = DL_UNITDATA_IND;
21757c478bd9Sstevel@tonic-gate 	dludindp->dl_dest_addr_length = IDNADDRL;
21767c478bd9Sstevel@tonic-gate 	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
21777c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_length = IDNADDRL;
21787c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_offset = sizeof (dl_unitdata_ind_t) + IDNADDRL;
21797c478bd9Sstevel@tonic-gate 	dludindp->dl_group_address = isgroupaddr;
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t));
21827c478bd9Sstevel@tonic-gate 	ether_copy(dhostp, &dlap->dl_phys);
21837c478bd9Sstevel@tonic-gate 	dlap->dl_sap = (ushort_t)type;
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	dlap = (struct idndladdr *)(nmp->b_rptr + sizeof (dl_unitdata_ind_t)
21867c478bd9Sstevel@tonic-gate 					+ IDNADDRL);
21877c478bd9Sstevel@tonic-gate 	ether_copy(shostp, &dlap->dl_phys);
21887c478bd9Sstevel@tonic-gate 	dlap->dl_sap = (ushort_t)type;
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	/*
21917c478bd9Sstevel@tonic-gate 	 * Link the M_PROTO and M_DATA together.
21927c478bd9Sstevel@tonic-gate 	 */
21937c478bd9Sstevel@tonic-gate 	nmp->b_cont = mp;
21947c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_IDN, TR_IDN_ADDUDIND_END, "idndl_addudind end");
21957c478bd9Sstevel@tonic-gate 	return (nmp);
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate /*
21997c478bd9Sstevel@tonic-gate  * Return TRUE if the given multicast address is one
22007c478bd9Sstevel@tonic-gate  * of those that this particular Stream is interested in.
22017c478bd9Sstevel@tonic-gate  */
22027c478bd9Sstevel@tonic-gate static int
22037c478bd9Sstevel@tonic-gate idndl_mcmatch(register struct idnstr *stp, register struct ether_addr *addrp)
22047c478bd9Sstevel@tonic-gate {
22057c478bd9Sstevel@tonic-gate 	register struct ether_addr	*mctab;
22067c478bd9Sstevel@tonic-gate 	register int	mccount;
22077c478bd9Sstevel@tonic-gate 	register int	i;
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	/*
22107c478bd9Sstevel@tonic-gate 	 * Return FALSE if not a multicast address.
22117c478bd9Sstevel@tonic-gate 	 */
22127c478bd9Sstevel@tonic-gate 	if (!IDNDL_ADDR_IS_MULTICAST(addrp))
22137c478bd9Sstevel@tonic-gate 		return (0);
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	/*
22167c478bd9Sstevel@tonic-gate 	 * Check if all multicasts have been enabled for this Stream
22177c478bd9Sstevel@tonic-gate 	 */
22187c478bd9Sstevel@tonic-gate 	if (stp->ss_flags & IDNSALLMULTI)
22197c478bd9Sstevel@tonic-gate 		return (1);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	/*
22227c478bd9Sstevel@tonic-gate 	 * Return FALSE if no multicast addresses enabled for this Stream.
22237c478bd9Sstevel@tonic-gate 	 */
22247c478bd9Sstevel@tonic-gate 	if (stp->ss_mccount == 0)
22257c478bd9Sstevel@tonic-gate 		return (0);
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	/*
22287c478bd9Sstevel@tonic-gate 	 * Otherwise, find it in the table.
22297c478bd9Sstevel@tonic-gate 	 */
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	mccount = stp->ss_mccount;
22327c478bd9Sstevel@tonic-gate 	mctab = stp->ss_mctab;
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	for (i = 0; i < mccount; i++)
22357c478bd9Sstevel@tonic-gate 		if (!ether_cmp(addrp, &mctab[i]))
22367c478bd9Sstevel@tonic-gate 			return (1);
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	return (0);
22397c478bd9Sstevel@tonic-gate }
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate /*
22427c478bd9Sstevel@tonic-gate  * Start xmit on any msgs previously enqueued on any write queues.
22437c478bd9Sstevel@tonic-gate  * If the caller passes NULL, then we need to check all
22447c478bd9Sstevel@tonic-gate  * our interfaces.
22457c478bd9Sstevel@tonic-gate  */
22467c478bd9Sstevel@tonic-gate void
22477c478bd9Sstevel@tonic-gate idndl_wenable(struct idn *sip)
22487c478bd9Sstevel@tonic-gate {
22497c478bd9Sstevel@tonic-gate 	struct idnstr	*stp;
22507c478bd9Sstevel@tonic-gate 	queue_t		*wq;
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	/*
22537c478bd9Sstevel@tonic-gate 	 * Order of wantw accesses is important.
22547c478bd9Sstevel@tonic-gate 	 */
22557c478bd9Sstevel@tonic-gate 	ASSERT((sip == NULL) ? RW_LOCK_HELD(&idn.struprwlock) : 1);
22567c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&idn.sipwenlock));
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	do {
22597c478bd9Sstevel@tonic-gate 		if (sip)
22607c478bd9Sstevel@tonic-gate 			sip->si_wantw = 0;
22617c478bd9Sstevel@tonic-gate 		for (stp = idn.strup; stp; stp = stp->ss_nextp) {
22627c478bd9Sstevel@tonic-gate 			if ((!sip || (stp->ss_sip == sip)) &&
22637c478bd9Sstevel@tonic-gate 			    stp->ss_rq && ((wq = WR(stp->ss_rq))->q_first))
22647c478bd9Sstevel@tonic-gate 				qenable(wq);
22657c478bd9Sstevel@tonic-gate 		}
22667c478bd9Sstevel@tonic-gate 	} while (sip && sip->si_wantw);
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate /*VARARGS*/
22707c478bd9Sstevel@tonic-gate static void
22717c478bd9Sstevel@tonic-gate serror(dev_info_t *dip, int idnerr, char *fmt, ...)
22727c478bd9Sstevel@tonic-gate {
22737c478bd9Sstevel@tonic-gate 	static	long	last;
22747c478bd9Sstevel@tonic-gate 	static	char	*lastfmt;
22757c478bd9Sstevel@tonic-gate 	char		msg_buffer[255];
22767c478bd9Sstevel@tonic-gate 	va_list ap;
22777c478bd9Sstevel@tonic-gate 	time_t	now;
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 	/*
22807c478bd9Sstevel@tonic-gate 	 * Don't print same error message too often.
22817c478bd9Sstevel@tonic-gate 	 */
22827c478bd9Sstevel@tonic-gate 	now = gethrestime_sec();
22837c478bd9Sstevel@tonic-gate 	if ((last == (now & ~1)) && (lastfmt == fmt))
22847c478bd9Sstevel@tonic-gate 		return;
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	last = now & ~1;
22877c478bd9Sstevel@tonic-gate 	lastfmt = fmt;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
22907c478bd9Sstevel@tonic-gate 	(void) vsprintf(msg_buffer, fmt, ap);
22917c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "IDN: %d: %s%d: %s\n",
22927c478bd9Sstevel@tonic-gate 		idnerr, ddi_get_name(dip),
22937c478bd9Sstevel@tonic-gate 		ddi_get_instance(dip), msg_buffer);
22947c478bd9Sstevel@tonic-gate 	va_end(ap);
22957c478bd9Sstevel@tonic-gate }
2296