llc1.c revision 7656:2621e50fdf4a
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 */
59static int llc1_open(queue_t *q, dev_t *dev, int flag, int sflag,
60	cred_t *cred);
61static int llc1_close(queue_t *q, int flag, cred_t *cred);
62static int llc1_uwput(queue_t *q, mblk_t *mp);
63static int llc1_uwsrv(queue_t *q);
64static int llc1_lrsrv(queue_t *q);
65static int llc1_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
66static int llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
67static int llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
68
69static mblk_t *llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo,
70	mblk_t *mp);
71static mblk_t *llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
72static mblk_t *llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
73	mblk_t *mp);
74static mblk_t *llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
75static mblk_t *llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
76	mblk_t *mp);
77
78static void llc1_ioctl(queue_t *q, mblk_t *mp);
79static void llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp);
80static void llc1_req_raw(llc_mac_info_t *macinfo);
81static void llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim);
82
83static minor_t llc1_findminor(llc1dev_t *device);
84static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *);
85
86static void llc1insque(void *elem, void *pred);
87static void llc1remque(void *arg);
88static void llc1error();
89static int llc1_subs_unbind(void);
90static void llc1_init_kstat(llc_mac_info_t *macinfo);
91static void llc1_uninit_kstat(llc_mac_info_t *macinfo);
92static int llc1_update_kstat(kstat_t *ksp, int rw);
93static int llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo);
94static int llc1_unbind(queue_t *q, mblk_t *mp);
95static int llc1_subs_bind(queue_t *q, mblk_t *mp);
96static int llc1_unitdata(queue_t *q, mblk_t *mp);
97static int llc1_inforeq(queue_t *q, mblk_t *mp);
98static int llc1attach(queue_t *q, mblk_t *mp);
99static void llc1_send_bindreq(llc_mac_info_t *macinfo);
100static int llc1_req_info(queue_t *q);
101static int llc1_cmds(queue_t *q, mblk_t *mp);
102static int llc1_setppa(struct ll_snioc *snioc);
103static int llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc);
104static int llc1_bind(queue_t *q, mblk_t *mp);
105static int llc1unattach(queue_t *q, mblk_t *mp);
106static int llc1_enable_multi(queue_t *q, mblk_t *mp);
107static int llc1_disable_multi(queue_t *q, mblk_t *mp);
108static int llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res);
109static int llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res);
110static int llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo);
111static 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
118static 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
127static struct qinit llc1_rint = {
128	NULL,
129	NULL,
130	llc1_open,
131	llc1_close,
132	NULL,
133	&llc1_minfo,
134	NULL
135};
136
137static struct qinit llc1_wint = {
138	llc1_uwput,
139	llc1_uwsrv,
140	NULL,
141	NULL,
142	NULL,
143	&llc1_minfo,
144	NULL
145};
146
147static struct qinit llc1_muxrint = {
148	putq,
149	llc1_lrsrv,
150	NULL,
151	NULL,
152	NULL,
153	&llc1_minfo,
154	NULL
155};
156
157static struct qinit llc1_muxwint = {
158	NULL,
159	NULL,
160	NULL,
161	NULL,
162	NULL,
163	&llc1_minfo,
164	NULL
165};
166
167struct 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 */
182DDI_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 */
189static 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
195static struct modlinkage modlinkage = {
196	MODREV_1, (void *)&modldrv, NULL
197};
198
199int
200_init(void)
201{
202	return (mod_install(&modlinkage));
203}
204
205int
206_fini(void)
207{
208	return (mod_remove(&modlinkage));
209}
210
211int
212_info(struct modinfo *modinfop)
213{
214	return (mod_info(&modlinkage, modinfop));
215}
216
217#endif
218
219#ifdef LLC1_DEBUG
220extern 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
233static 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
240static int
241llc1_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
292static int
293llc1_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*/
312static int
313llc1_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*/
342static int
343llc1_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*/
407static int
408llc1_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
472static int
473llc1_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 */
533static int
534llc1_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
716static int
717llc1_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 */
786int
787llc1_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
807int	llc1_doreqinfo;
808
809static void
810llc1_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
965static int
966llc1_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 */
985static int
986llc1_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 */
998static int
999llc1_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 */
1109static int
1110llc1_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 */
1201static int
1202llc1_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 */
1233static int
1234llc1_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 */
1313static int
1314llc1_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 */
1472static void
1473llc1_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 */
1705static int
1706llc1_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 */
1716static int
1717llc1_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 */
1726static int
1727llc1attach(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 */
1788static int
1789llc1unattach(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 */
1841static int
1842llc1_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 */
1957static int
1958llc1_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 */
2009static void
2010llc1_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
2045static minor_t
2046llc1_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);
2060nextminor:
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 */
2072static int
2073llc1_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 */
2092static void
2093llc1_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 */
2111static void
2112llc1_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 */
2144static mblk_t *
2145llc1_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 */
2266static mblk_t *
2267llc1_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 */
2360static mblk_t *
2361llc1_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 */
2454static int
2455llc1_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 */
2538static mblk_t *
2539llc1_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 */
2610static mblk_t *
2611llc1_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 */
2703static int
2704llc1_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 */
2790static void
2791llc1_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
2807static void
2808llc1insque(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
2820static void
2821llc1remque(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 */
2833static void
2834llc1error(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*/
2858static int
2859llc1_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
2891static void
2892llc1_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
2929static void
2930llc1_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 */
2950static int
2951llc1_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 */
3044static int
3045llc1_subs_unbind(void)
3046{
3047	return (DL_UNSUPPORTED);
3048}
3049
3050char *
3051snapdmp(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
3064static int
3065llc1_snap_match(llc1_t *lld, struct snaphdr *snap)
3066{
3067	return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0);
3068}
3069