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