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