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