9348 mii: duplicate 'const' declaration specifier
[unleashed.git] / usr / src / uts / common / io / llc1.c
blobf673d7c12816b9f6d0db0bd1178dd8e1b9cd58c4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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.
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>
57 * function prototypes, etc.
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);
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);
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);
83 static minor_t llc1_findminor(llc1dev_t *device);
84 static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *);
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);
114 * the standard streams glue for defining the type of streams entity and the
115 * operational parameters.
118 static struct module_info llc1_minfo = {
119 LLC1IDNUM,
120 "llc1",
122 LLC1_DEFMAX,
123 LLC1_HIWATER, /* high water mark */
124 LLC1_LOWATER, /* low water mark */
127 static struct qinit llc1_rint = {
128 NULL,
129 NULL,
130 llc1_open,
131 llc1_close,
132 NULL,
133 &llc1_minfo,
134 NULL
137 static struct qinit llc1_wint = {
138 llc1_uwput,
139 llc1_uwsrv,
140 NULL,
141 NULL,
142 NULL,
143 &llc1_minfo,
144 NULL
147 static struct qinit llc1_muxrint = {
148 putq,
149 llc1_lrsrv,
150 NULL,
151 NULL,
152 NULL,
153 &llc1_minfo,
154 NULL
157 static struct qinit llc1_muxwint = {
158 NULL,
159 NULL,
160 NULL,
161 NULL,
162 NULL,
163 &llc1_minfo,
164 NULL
167 struct streamtab llc1_info = {
168 &llc1_rint,
169 &llc1_wint,
170 &llc1_muxrint,
171 &llc1_muxwint
175 * loadable module/driver wrapper this allows llc1 to be unloaded later
178 #if !defined(BUILD_STATIC)
179 #include <sys/modctl.h>
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);
187 * Module linkage information for the kernel.
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 */
195 static struct modlinkage modlinkage = {
196 MODREV_1, (void *)&modldrv, NULL
200 _init(void)
202 return (mod_install(&modlinkage));
206 _fini(void)
208 return (mod_remove(&modlinkage));
212 _info(struct modinfo *modinfop)
214 return (mod_info(&modlinkage, modinfop));
217 #endif
219 #ifdef LLC1_DEBUG
220 extern int llc1_debug = 0x0;
222 #endif
225 * Allocate and zero-out "number" structures each of type "structure" in
226 * kernel memory.
228 #define GETSTRUCT(structure, number) \
229 (kmem_zalloc(sizeof (structure) * (number), KM_NOSLEEP))
230 #define GETBUF(structure, size) \
231 (kmem_zalloc(size, KM_NOSLEEP))
233 static struct llc1device llc1_device_list;
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
240 static int
241 llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
243 if (cmd != DDI_ATTACH)
244 return (DDI_FAILURE);
247 * there isn't any hardware but we do need to initialize things
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);
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;
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;
265 * now do all the DDI stuff necessary
268 ddi_set_driver_private(devinfo, &llc1_device_list);
271 * create the file system device node
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);
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;
284 ddi_report_dev(devinfo);
285 return (DDI_SUCCESS);
289 * llc1_detach standard kernel interface routine
292 static int
293 llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
295 if (cmd != DDI_DETACH) {
296 return (DDI_FAILURE);
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);
308 * llc1_devinfo(dev, cmd, arg, result) standard kernel devinfo lookup
309 * function
311 /*ARGSUSED2*/
312 static int
313 llc1_getinfo(dev_info_t *dev, ddi_info_cmd_t cmd, void *arg, void **result)
315 int error;
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;
325 break;
326 case DDI_INFO_DEVT2INSTANCE:
327 *result = (void *)0;
328 error = DDI_SUCCESS;
329 break;
330 default:
331 error = DDI_FAILURE;
333 return (error);
337 * llc1_open()
338 * LLC1 open routine, called when device is opened by the user
341 /*ARGSUSED2*/
342 static int
343 llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
345 llc1_t *llc1;
346 minor_t minordev;
347 int status = 0;
349 ASSERT(q);
352 * Stream already open, sucess.
354 if (q->q_ptr)
355 return (0);
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.
361 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
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);
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);
380 * get a per-stream structure and link things together so we
381 * can easily find them later.
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;
388 * fill in the structure and state info
390 llc1->llc_state = DL_UNATTACHED;
391 llc1->llc_style = DL_STYLE2;
392 llc1->llc_minor = minordev;
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);
402 * llc1_close(q)
403 * normal stream close call checks current status and cleans up
404 * data structures that were dynamically allocated
406 /*ARGSUSED1*/
407 static int
408 llc1_close(queue_t *q, int flag, cred_t *cred)
410 llc1_t *llc1;
412 ASSERT(q);
413 ASSERT(q->q_ptr);
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;
421 (void) llc1remque(llc1); /* remove from active list */
422 rw_exit(&llc1_device_list.llc1_rwlock);
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 */
429 if (llc1->llc_mcast != NULL) {
430 int i;
432 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
433 llc_mcast_t *mcast;
435 if ((mcast = llc1->llc_mcast[i]) != NULL) {
437 * disable from stream and possibly
438 * lower stream
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;
449 kmem_free(llc1->llc_mcast,
450 sizeof (llc_mcast_t *) * llc1->llc_multicnt);
451 llc1->llc_mcast = NULL;
453 llc1->llc_state = DL_UNATTACHED;
455 mutex_exit(&llc1->llc_lock);
457 mutex_destroy(&llc1->llc_lock);
459 kmem_free(llc1, sizeof (llc1_t));
461 return (0);
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.
472 static int
473 llc1_uwput(queue_t *q, mblk_t *mp)
475 llc1_t *ld = (llc1_t *)(q->q_ptr);
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)) {
483 case M_IOCTL: /* no waiting in ioctl's */
484 (void) llc1_ioctl(q, mp);
485 break;
487 case M_FLUSH: /* canonical flush handling */
488 if (*mp->b_rptr & FLUSHW)
489 flushq(q, 0);
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;
499 /* for now, we will always queue */
500 case M_PROTO:
501 case M_PCPROTO:
502 (void) putq(q, mp);
503 break;
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;
512 /* need to do further checking */
513 (void) putq(q, mp);
514 break;
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);
524 return (0);
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.
533 static int
534 llc1_lrsrv(queue_t *q)
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;
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*/
551 printf("\n");
553 #endif
556 * determine where message goes, then call the proper handler
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) {
569 * we are in the midst of completing
570 * the I_LINK/I_PLINK and needed this
571 * info
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;
584 * size of max header
585 * (including SNAP)
587 macinfo->llcp_maxpkt -= 8;
589 macinfo->llcp_addrlen =
590 prim->info_ack.dl_addr_length -
591 ABS(prim->info_ack.dl_sap_length);
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);
604 if (prim->info_ack.dl_current_state ==
605 DL_UNBOUND)
606 llc1_send_bindreq(macinfo);
607 freemsg(mp);
609 * need to put the lower stream into
610 * DLRAW mode. Currently only DL_ETHER
611 * or DL_CSMACD
613 switch (macinfo->llcp_type) {
614 case DL_ETHER:
615 case DL_CSMACD:
617 * raw mode is optimal so ask
618 * for it * we might not get
619 * it but that's OK
621 llc1_req_raw(macinfo);
622 break;
623 default:
625 * don't want raw mode so don't
626 * ask for it
628 break;
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);
640 break;
641 case DL_BIND_ACK:
643 * if we had to bind, the macaddr is wrong
644 * so get it again
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);
676 break;
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;
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;
700 /* need to find the correct queue */
701 freemsg(mp);
702 break;
703 case M_DATA:
704 llc1_recv(macinfo, mp);
705 break;
708 return (0);
712 * llc1_uwsrv - Incoming messages are processed according to the DLPI
713 * protocol specification
716 static int
717 llc1_uwsrv(queue_t *q)
719 mblk_t *mp;
720 llc1_t *lld = (llc1_t *)q->q_ptr;
721 union DL_primitives *prim;
722 int err;
724 #ifdef LLC1_DEBUG
725 if (llc1_debug & LLCTRACE)
726 printf("llc1_wsrv(%x)\n", q);
727 #endif
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);
748 } else {
749 dlerrorack(q, mp,
750 prim->dl_primitive,
751 err, 0);
754 break;
755 case M_DATA:
757 * retry of a previously processed
758 * UNITDATA_REQ or is a RAW message from
759 * above
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;
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;
779 return (0);
783 * llc1_multicast used to determine if the address is a multicast address for
784 * this user.
787 llc1_multicast(struct ether_addr *addr, llc1_t *lld)
789 int i;
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);
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.
807 int llc1_doreqinfo;
809 static void
810 llc1_ioctl(queue_t *q, mblk_t *mp)
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;
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;
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;
848 /* need to do an info_req before an info_req or attach */
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);
857 /* initiate getting the info */
858 (void) llc1_req_info(macinfo->llcp_queue);
860 miocack(q, mp, 0, 0);
861 return;
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 */
876 ASSERT(macinfo->llcp_next);
878 /* remove from device list */
879 llc1_device_list.llc1_ndevice--;
880 llc1remque(macinfo);
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;
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);
896 lld->llc_mac_info = NULL;
898 miocack(q, mp, 0, 0);
900 /* finish any necessary setup */
901 if (llc1_device_list.llc1_ndevice == 0)
902 llc1_device_list.llc1_nextppa = 0;
904 rw_exit(&llc1_device_list.llc1_rwlock);
905 return;
908 rw_exit(&llc1_device_list.llc1_rwlock);
910 * what should really be done here -- force errors on all
911 * streams?
913 miocnak(q, mp, 0, EINVAL);
914 return;
916 case L_SETPPA:
917 error = miocpullup(mp, sizeof (struct ll_snioc));
918 if (error != 0) {
919 miocnak(q, mp, 0, error);
920 return;
923 if (llc1_setppa((struct ll_snioc *)mp->b_cont->b_rptr) >= 0) {
924 miocack(q, mp, 0, 0);
925 return;
927 miocnak(q, mp, 0, EINVAL);
928 return;
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;
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;
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);
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.
965 static int
966 llc1_setppa(struct ll_snioc *snioc)
968 llc_mac_info_t *macinfo;
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);
979 return (-1);
983 * llc1_getppa(macinfo, snioc) returns the PPA for this stream
985 static int
986 llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc)
988 if (macinfo == NULL)
989 return (-1);
990 snioc->lli_ppa = macinfo->llcp_ppa;
991 snioc->lli_index = macinfo->llcp_lindex;
992 return (0);
996 * llc1_cmds - process the DL commands as defined in dlpi.h
998 static int
999 llc1_cmds(queue_t *q, mblk_t *mp)
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;
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);
1015 switch (dlp->dl_primitive) {
1016 case DL_BIND_REQ:
1017 result = llc1_bind(q, mp);
1018 break;
1020 case DL_UNBIND_REQ:
1021 result = llc1_unbind(q, mp);
1022 break;
1024 case DL_SUBS_BIND_REQ:
1025 result = llc1_subs_bind(q, mp);
1026 break;
1028 case DL_SUBS_UNBIND_REQ:
1029 result = llc1_subs_unbind();
1030 break;
1032 case DL_UNITDATA_REQ:
1033 result = llc1_unitdata(q, mp);
1034 break;
1036 case DL_INFO_REQ:
1037 result = llc1_inforeq(q, mp);
1038 break;
1040 case DL_ATTACH_REQ:
1041 result = llc1attach(q, mp);
1042 break;
1044 case DL_DETACH_REQ:
1045 result = llc1unattach(q, mp);
1046 break;
1048 case DL_ENABMULTI_REQ:
1049 result = llc1_enable_multi(q, mp);
1050 break;
1052 case DL_DISABMULTI_REQ:
1053 result = llc1_disable_multi(q, mp);
1054 break;
1056 case DL_XID_REQ:
1057 result = llc1_xid_req_res(q, mp, 0);
1058 break;
1060 case DL_XID_RES:
1061 result = llc1_xid_req_res(q, mp, 1);
1062 break;
1064 case DL_TEST_REQ:
1065 result = llc1_test_req_res(q, mp, 0);
1066 break;
1068 case DL_TEST_RES:
1069 result = llc1_test_req_res(q, mp, 1);
1070 break;
1072 case DL_SET_PHYS_ADDR_REQ:
1073 result = DL_NOTSUPPORTED;
1074 break;
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;
1084 break;
1086 case DL_PROMISCON_REQ:
1087 case DL_PROMISCOFF_REQ:
1088 result = DL_NOTSUPPORTED;
1089 break;
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;
1100 rw_exit(&llc1_device_list.llc1_rwlock);
1101 mutex_exit(&llc->llc_lock);
1102 return (result);
1106 * llc1_bind - determine if a SAP is already allocated and whether it is
1107 * legal to do the bind at this time
1109 static int
1110 llc1_bind(queue_t *q, mblk_t *mp)
1112 int sap;
1113 dl_bind_req_t *dlp;
1114 llc1_t *lld = (llc1_t *)q->q_ptr;
1116 ASSERT(lld);
1118 #ifdef LLC1_DEBUG
1119 if (llc1_debug & LLCTRACE)
1120 printf("llc1_bind(%x %x)\n", q, mp);
1121 #endif
1123 dlp = (dl_bind_req_t *)mp->b_rptr;
1124 sap = dlp->dl_sap;
1126 #ifdef LLC1_DEBUG
1127 if (llc1_debug & LLCPROT)
1128 printf("llc1_bind: lsap=%x\n", sap);
1129 #endif
1131 if (lld->llc_mac_info == NULL)
1132 return (DL_OUTSTATE);
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);
1143 if (dlp->dl_service_mode != DL_CLDLS || dlp->dl_max_conind != 0) {
1144 return (DL_UNSUPPORTED);
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.
1153 if (sap == 0 || (sap <= 0xFF && (sap & 1 && sap != 0xFF)) ||
1154 sap > 0xFFFF) {
1155 return (DL_BADSAP);
1157 lld->llc_state = DL_BIND_PENDING;
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);
1166 lld->llc_sap = sap;
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;
1178 #ifdef LLC1_DEBUG
1179 if (llc1_debug & LLCPROT)
1180 printf("llc1_bind: ok - type = %d\n", lld->llc_type);
1181 #endif
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;
1188 /* ACK the BIND, if possible */
1190 dlbindack(q, mp, sap, lld->llc_mac_info->llcp_macaddr, 6, 0, 0);
1192 lld->llc_state = DL_IDLE; /* bound and ready */
1194 return (LLCE_OK);
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.
1201 static int
1202 llc1_unbind(queue_t *q, mblk_t *mp)
1204 llc1_t *lld;
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;
1212 if (lld->llc_mac_info == NULL)
1213 return (DL_OUTSTATE);
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);
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);
1231 * llc1_inforeq - generate the response to an info request
1233 static int
1234 llc1_inforeq(queue_t *q, mblk_t *mp)
1236 llc1_t *lld;
1237 mblk_t *nmp;
1238 dl_info_ack_t *dlp;
1239 int bufsize;
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;
1253 nmp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK);
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;
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;
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 */
1297 dlp->dl_version = DL_VERSION_2;
1298 qreply(q, nmp);
1300 return (LLCE_OK);
1304 * llc1_unitdata
1305 * send a datagram. Destination address/lsap is in M_PROTO
1306 * message (first mblock), data is in remainder of message.
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.
1313 static int
1314 llc1_unitdata(queue_t *q, mblk_t *mp)
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;
1326 #ifdef LLC1_DEBUG
1327 if (llc1_debug & LLCTRACE)
1328 printf("llc1_unitdata(%x %x)\n", q, mp);
1329 #endif
1331 if ((macinfo = lld->llc_mac_info) == NULL)
1332 return (DL_OUTSTATE);
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);
1343 /* need the destination address in all cases */
1344 llcp = (struct llcaddr *)((caddr_t)dlp + dlp->dl_dest_addr_offset);
1346 if (macinfo->llcp_flags & LLC1_USING_RAW) {
1348 * make a valid header for transmission
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);
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);
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));
1373 /* need an LLC header, otherwise is Novell */
1374 /* bound sap is always source */
1375 llchdr->llc_ssap = lld->llc_sap;
1377 /* destination sap */
1378 llchdr->llc_dsap = llcp->llca_sap;
1380 /* always Unnumbered Information */
1381 llchdr->llc_ctl = LLC_UI;
1383 nmp->b_wptr += sizeof (struct llchdr);
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;
1390 } else {
1391 /* set length without llc header size */
1392 hdr->ether_type = ntohs(msglen);
1394 /* we don't do anything else for Netware */
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;
1405 break;
1407 default: /* either RAW or unknown, send as is */
1408 break;
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;
1427 * if we are using SNAP, insert the header here
1429 if (lld->llc_flags & LLC_SNAP) {
1430 bcopy(lld->llc_snap, nmp->b_wptr, 5);
1431 nmp->b_wptr += 5;
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;
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;
1456 putnext(macinfo->llcp_queue, mp);
1457 return (LLCE_OK); /* this is almost correct, the result */
1458 } else {
1459 lld->llc_stats->llcs_nobuffer++;
1461 if (nmp != NULL)
1462 freemsg(nmp); /* free on failure */
1463 return (LLCE_OK);
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.
1472 static void
1473 llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp)
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;
1482 #ifdef LLC1_DEBUG
1483 if (llc1_debug & LLCTRACE)
1484 printf("llc1_recv(%x, %x)\n", mp, macinfo);
1485 #endif
1487 if (DB_TYPE(mp) == M_PROTO) {
1488 dl_unitdata_ind_t *udata;
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));
1503 } else {
1504 struct ether_header *hdr;
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));
1518 udmp = NULL;
1520 msgsap = llchdr->llc_dsap;
1522 #ifdef LLC1_DEBUG
1523 if (llc1_debug & LLCRECV) {
1524 printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr));
1526 #endif
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);
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.
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) {
1553 * is this a potentially usable SAP on the
1554 * right MAC layer?
1556 if (lld->llc_qptr == NULL ||
1557 lld->llc_state != DL_IDLE ||
1558 lld->llc_mac_info != macinfo) {
1559 continue;
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;
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;
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;
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) {
1603 /* A Novell packet */
1604 nmp = llc1_form_udata(lld, macinfo, mp);
1605 continue;
1607 switch (llchdr->llc_ctl) {
1608 case LLC_UI:
1610 * this is an Unnumbered Information
1611 * packet so form a DL_UNITDATA_IND and
1612 * send to user
1614 nmp = llc1_form_udata(lld, macinfo, mp);
1615 break;
1617 case LLC_XID:
1618 case LLC_XID | LLC_P:
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
1628 if (lld->llc_flags & LLC1_AUTO_XID) {
1629 nmp = llc1_xid_reply(macinfo,
1630 mp, lld->llc_sap);
1631 } else {
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.
1641 nmp = llc1_xid_ind_con(lld,
1642 macinfo, mp);
1644 macinfo->llcp_stats.llcs_xidrcv++;
1645 break;
1647 case LLC_TEST:
1648 case LLC_TEST | LLC_P:
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
1659 if (lld->llc_flags & LLC1_AUTO_TEST) {
1660 nmp = llc1_test_reply(macinfo,
1661 mp, lld->llc_sap);
1662 } else {
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.
1674 nmp = llc1_test_ind_con(lld,
1675 macinfo, mp);
1677 macinfo->llcp_stats.llcs_testrcv++;
1678 break;
1679 default:
1680 nmp = mp;
1681 break;
1683 mp = nmp;
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++;
1695 if (statcnt_normal) {
1696 macinfo->llcp_stats.llcs_bytercv += statcnt_normal;
1697 macinfo->llcp_stats.llcs_pktrcv++;
1702 * llc1_local - check to see if the message is addressed to this system by
1703 * comparing with the board's address.
1705 static int
1706 llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo)
1708 return (bcmp(addr->ether_addr_octet, macinfo->llcp_macaddr,
1709 macinfo->llcp_addrlen) == 0);
1713 * llc1_broadcast - check to see if a broadcast address is the destination of
1714 * this received packet
1716 static int
1717 llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo)
1719 return (bcmp(addr->ether_addr_octet, macinfo->llcp_broadcast,
1720 macinfo->llcp_addrlen) == 0);
1724 * llc1attach(q, mp) DLPI DL_ATTACH_REQ this attaches the stream to a PPA
1726 static int
1727 llc1attach(queue_t *q, mblk_t *mp)
1729 dl_attach_req_t *at;
1730 llc_mac_info_t *mac;
1731 llc1_t *llc = (llc1_t *)q->q_ptr;
1733 at = (dl_attach_req_t *)mp->b_rptr;
1735 if (llc->llc_state != DL_UNATTACHED) {
1736 return (DL_OUTSTATE);
1738 llc->llc_state = DL_ATTACH_PENDING;
1740 if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
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.
1746 rw_exit(&llc1_device_list.llc1_rwlock);
1747 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
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) {
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.
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);
1769 /* this links us to the PPA */
1770 mac->llcp_nstreams++;
1771 llc->llc_mac_info = mac;
1773 llc->llc_state = DL_UNBOUND; /* now ready for action */
1774 llc->llc_stats = &mac->llcp_stats;
1775 dlokack(q, mp, DL_ATTACH_REQ);
1777 return (LLCE_OK);
1780 llc->llc_state = DL_UNATTACHED;
1781 return (DL_BADPPA);
1785 * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the
1786 * stream
1788 static int
1789 llc1unattach(queue_t *q, mblk_t *mp)
1791 llc1_t *llc = (llc1_t *)q->q_ptr;
1792 int state;
1793 int i;
1795 state = llc->llc_state;
1796 if (state != DL_UNBOUND)
1797 return (DL_OUTSTATE);
1799 /* can now detach from the PPA */
1800 llc->llc_state = DL_DETACH_PENDING;
1802 if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
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.
1808 rw_exit(&llc1_device_list.llc1_rwlock);
1809 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
1812 if (llc->llc_mcast) {
1813 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1814 llc_mcast_t *mcast;
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;
1823 kmem_free(llc->llc_mcast,
1824 sizeof (llc_mcast_t *) * llc->llc_multicnt);
1825 llc->llc_mcast = NULL;
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);
1834 return (LLCE_OK);
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.
1841 static int
1842 llc1_enable_multi(queue_t *q, mblk_t *mp)
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;
1852 #if defined(LLC1_DEBUG)
1853 if (llc1_debug & LLCPROT) {
1854 printf("llc1_enable_multi(%x, %x)\n", q, mp);
1856 #endif
1858 llc = (llc1_t *)q->q_ptr;
1860 if (llc->llc_state == DL_UNATTACHED)
1861 return (DL_OUTSTATE);
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);
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.
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);
1901 * there wasn't one so check to see if the mac layer has one
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);
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;
1919 if (mcast == NULL) {
1920 mblk_t *nmp;
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);
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;
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);
1948 status = DL_TOOMANY;
1950 return (status);
1954 * llc1_disable_multi disable the multicast address on the stream if last
1955 * reference for the mac layer, disable there as well
1957 static int
1958 llc1_disable_multi(queue_t *q, mblk_t *mp)
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;
1967 #if defined(LLC1_DEBUG)
1968 if (llc1_debug & LLCPROT) {
1969 printf("llc1_enable_multi(%x, %x)\n", q, mp);
1971 #endif
1973 llc = (llc1_t *)q->q_ptr;
1975 if (llc->llc_state == DL_UNATTACHED)
1976 return (DL_OUTSTATE);
1978 macinfo = llc->llc_mac_info;
1979 multi = (dl_enabmulti_req_t *)mp->b_rptr;
1980 maddr = (struct ether_addr *)(multi + 1);
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);
1998 status = DL_NOTENAB;
2001 return (status);
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.
2009 static void
2010 llc1_send_disable_multi(llc_mac_info_t *macinfo, llc_mcast_t *mcast)
2012 mblk_t *mp;
2013 dl_disabmulti_req_t *dis;
2015 if (mcast == NULL) {
2016 return;
2018 if (macinfo == NULL || macinfo->llcp_queue == NULL) {
2019 return;
2021 if (--mcast->llcm_refcnt > 0)
2022 return;
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);
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.
2045 static minor_t
2046 llc1_findminor(llc1dev_t *device)
2048 llc1_t *next;
2049 minor_t minor;
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;
2059 return (minor);
2060 nextminor:
2061 /* don't need to do anything */
2064 /*NOTREACHED*/
2065 return (0);
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.
2072 static int
2073 llc1_req_info(queue_t *q)
2075 dl_info_req_t *info;
2076 mblk_t *mp;
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);
2090 * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode
2092 static void
2093 llc1_req_raw(llc_mac_info_t *macinfo)
2095 mblk_t *mp;
2097 mp = mkiocb(DLIOCRAW);
2098 if (mp == NULL)
2099 return;
2101 macinfo->llcp_iocid = ((struct iocblk *)mp->b_rptr)->ioc_id;
2103 putnext(macinfo->llcp_queue, mp);
2104 macinfo->llcp_flags |= LLC1_RAW_WAIT;
2108 * llc1_send_bindreq
2109 * if lower stream isn't bound, bind it to something appropriate
2111 static void
2112 llc1_send_bindreq(llc_mac_info_t *macinfo)
2114 mblk_t *mp;
2115 dl_bind_req_t *bind;
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;
2123 mp = allocb(sizeof (dl_bind_req_t), BPRI_MED);
2124 if (mp == NULL)
2125 return;
2127 bind = (dl_bind_req_t *)mp->b_rptr;
2128 mp->b_wptr = mp->b_rptr + sizeof (dl_bind_req_t);
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);
2141 * llc1_form_udata(lld, macinfo, mp) format a DL_UNITDATA_IND message to be
2142 * sent to the user
2144 static mblk_t *
2145 llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2147 mblk_t *udmp, *nmp;
2148 dl_unitdata_ind_t *udata;
2149 struct ether_header *hdr;
2150 struct llchdr *llchdr;
2151 struct snaphdr *snap;
2153 if (macinfo->llcp_flags & LLC1_USING_RAW) {
2154 hdr = (struct ether_header *)mp->b_rptr;
2155 llchdr = (struct llchdr *)(hdr + 1);
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);
2165 udata = (dl_unitdata_ind_t *)udmp->b_rptr;
2166 udmp->b_wptr += sizeof (dl_unitdata_ind_t);
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);
2175 if (lld->llc_flags & LLC_SNAP) {
2176 mp->b_rptr += sizeof (struct snaphdr);
2177 snap = (struct snaphdr *)(llchdr + 1);
2181 * now setup the DL_UNITDATA_IND header
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);
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;
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;
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 */
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);
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;
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);
2264 * llc1_xid_reply(macinfo, mp) automatic reply to an XID command
2266 static mblk_t *
2267 llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2269 mblk_t *nmp, *rmp;
2270 struct ether_header *hdr, *msgether;
2271 struct llchdr *llchdr;
2272 struct llchdr *msgllc;
2273 struct llchdr_xid *xid;
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);
2284 /* we only want to respond to commands to avoid response loops */
2285 if (llchdr->llc_ssap & LLC_RESPONSE)
2286 return (mp);
2288 nmp = allocb(msgdsize(mp) + LLC_XID_INFO_SIZE, BPRI_MED);
2289 if (nmp == NULL) {
2290 return (mp);
2294 * now construct the XID reply frame
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;
2313 rmp = allocb(sizeof (dl_unitdata_req_t) +
2314 macinfo->llcp_addrlen + 5, BPRI_MED);
2315 if (rmp == NULL)
2316 return (mp);
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;
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;
2335 msgllc = (struct llchdr *)nmp->b_wptr;
2336 xid = (struct llchdr_xid *)(msgllc + 1);
2337 nmp->b_wptr += sizeof (struct llchdr);
2339 msgllc->llc_dsap = llchdr->llc_ssap;
2341 /* mark it a response */
2342 msgllc->llc_ssap = sap | LLC_RESPONSE;
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 */
2349 nmp->b_wptr += sizeof (struct llchdr_xid);
2350 macinfo->llcp_stats.llcs_xidxmt++;
2351 putnext(WR(macinfo->llcp_queue), rmp);
2352 return (mp);
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
2360 static mblk_t *
2361 llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2363 mblk_t *nmp;
2364 dl_xid_ind_t *xid;
2365 struct ether_header *hdr;
2366 struct llchdr *llchdr;
2367 int raw;
2369 nmp = allocb(sizeof (dl_xid_ind_t) + 2 * (macinfo->llcp_addrlen + 1),
2370 BPRI_MED);
2371 if (nmp == NULL)
2372 return (mp);
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;
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;
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);
2400 LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap =
2401 llchdr->llc_dsap;
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;
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);
2418 LLCADDR(nmp->b_rptr, xid->dl_src_addr_offset)->llca_sap =
2419 llchdr->llc_ssap & ~LLC_RESPONSE;
2421 nmp->b_wptr = nmp->b_rptr + sizeof (dl_xid_ind_t) +
2422 2 * xid->dl_dest_addr_length;
2424 if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2425 xid->dl_primitive = DL_XID_IND;
2426 } else {
2427 xid->dl_primitive = DL_XID_CON;
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);
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));
2446 putnext(RD(lld->llc_qptr), nmp);
2447 return (mp);
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
2454 static int
2455 llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res)
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;
2464 if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2465 return (DL_OUTSTATE);
2467 if (llc->llc_sap == LLC_NOVELL_SAP)
2468 return (DL_NOTSUPPORTED);
2470 if (llc->llc_flags & DL_AUTO_XID)
2471 return (DL_XIDAUTO);
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);
2479 nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr) +
2480 sizeof (struct llchdr_xid), BPRI_MED);
2482 if (nmp == NULL)
2483 return (LLCE_NOBUFFER);
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);
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);
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);
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);
2535 * llc1_test_reply(macinfo, mp)
2536 * automatic reply to a TEST message
2538 static mblk_t *
2539 llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2541 mblk_t *nmp;
2542 struct ether_header *hdr, *msgether;
2543 struct llchdr *llchdr;
2544 struct llchdr *msgllc;
2545 int poll_final;
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);
2557 /* we only want to respond to commands to avoid response loops */
2558 if (llchdr->llc_ssap & LLC_RESPONSE)
2559 return (mp);
2561 nmp = copymsg(mp); /* so info field is duplicated */
2562 if (nmp == NULL) {
2563 nmp = mp;
2564 mp = NULL;
2567 * now construct the TEST reply frame
2571 poll_final = llchdr->llc_ctl & LLC_P;
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;
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);
2594 msgllc->llc_dsap = llchdr->llc_ssap;
2596 /* mark it as a response */
2597 msgllc->llc_ssap = sap | LLC_RESPONSE;
2598 msgllc->llc_ctl = LLC_TEST | poll_final;
2600 macinfo->llcp_stats.llcs_testxmt++;
2601 putnext(WR(macinfo->llcp_queue), nmp);
2602 return (mp);
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
2610 static mblk_t *
2611 llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2613 mblk_t *nmp;
2614 dl_test_ind_t *test;
2615 struct ether_header *hdr;
2616 struct llchdr *llchdr;
2617 int raw;
2619 nmp = allocb(sizeof (dl_test_ind_t) + 2 * (ETHERADDRL + 1), BPRI_MED);
2620 if (nmp == NULL)
2621 return (NULL);
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;
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;
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);
2649 LLCADDR(test, test->dl_dest_addr_offset)->llca_sap =
2650 llchdr->llc_dsap;
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;
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);
2667 LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_sap =
2668 llchdr->llc_ssap & ~LLC_RESPONSE;
2670 nmp->b_wptr = nmp->b_rptr + sizeof (dl_test_ind_t) +
2671 2 * test->dl_dest_addr_length;
2673 if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2674 test->dl_primitive = DL_TEST_IND;
2675 } else {
2676 test->dl_primitive = DL_TEST_CON;
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);
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));
2695 putnext(RD(lld->llc_qptr), nmp);
2696 return (mp);
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
2703 static int
2704 llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res)
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;
2713 if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2714 return (DL_OUTSTATE);
2716 if (llc->llc_sap == LLC_NOVELL_SAP)
2717 return (DL_NOTSUPPORTED);
2719 if (llc->llc_flags & DL_AUTO_TEST)
2720 return (DL_TESTAUTO);
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);
2729 nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr),
2730 BPRI_MED);
2732 if (nmp == NULL)
2733 return (LLCE_NOBUFFER);
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;
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);
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);
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);
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);
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.
2790 static void
2791 llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim)
2793 llc1_t *llc;
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;
2804 freemsg(mp);
2807 static void
2808 llc1insque(void *elem, void *pred)
2810 struct qelem *pelem = elem;
2811 struct qelem *ppred = pred;
2812 struct qelem *pnext = ppred->q_forw;
2814 pelem->q_forw = pnext;
2815 pelem->q_back = ppred;
2816 ppred->q_forw = pelem;
2817 pnext->q_back = pelem;
2820 static void
2821 llc1remque(void *arg)
2823 struct qelem *pelem = arg;
2824 struct qelem *elem = arg;
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;
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;
2838 static long last;
2839 static char *lastfmt;
2840 time_t now;
2843 * Don't print same error message too often.
2845 now = gethrestime_sec();
2846 if ((last == (now & ~1)) && (lastfmt == fmt))
2847 return;
2848 last = now & ~1;
2849 lastfmt = fmt;
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");
2857 /*ARGSUSED1*/
2858 static int
2859 llc1_update_kstat(kstat_t *ksp, int rw)
2861 llc_mac_info_t *macinfo;
2862 kstat_named_t *kstat;
2863 struct llc_stats *stats;
2865 if (ksp == NULL)
2866 return (0);
2868 kstat = (kstat_named_t *)(ksp->ks_data);
2869 macinfo = (llc_mac_info_t *)(ksp->ks_private);
2870 stats = &macinfo->llcp_stats;
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);
2891 static void
2892 llc1_init_kstat(llc_mac_info_t *macinfo)
2894 kstat_named_t *ksp;
2897 * Note that the temporary macinfo->llcp_ppa number is negative.
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;
2905 macinfo->llcp_kstatp->ks_update = llc1_update_kstat;
2906 macinfo->llcp_kstatp->ks_private = (void *)macinfo;
2908 ksp = (kstat_named_t *)(macinfo->llcp_kstatp->ks_data);
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);
2929 static void
2930 llc1_uninit_kstat(llc_mac_info_t *macinfo)
2932 if (macinfo->llcp_kstatp) {
2933 kstat_delete(macinfo->llcp_kstatp);
2934 macinfo->llcp_kstatp = NULL;
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
2950 static int
2951 llc1_subs_bind(queue_t *q, mblk_t *mp)
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;
2960 #if defined(LLC1_DEBUG)
2961 if (llc1_debug & (LLCTRACE|LLCPROT)) {
2962 printf("llc1_subs_bind (%x, %x)\n", q, mp);
2964 #endif
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 {
2974 lld->llc_state = DL_SUBS_BIND_PND;
2976 sapstr = (uchar_t *)(mp->b_rptr + subs->dl_subs_sap_offset);
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;
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;
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;
2999 bcopy(sapstr, lld->llc_snap, 3);
3000 lld->llc_flags |= LLC_SNAP_OID;
3001 break;
3003 case 5: /* full SNAP header */
3004 if (lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) {
3005 result = DL_BADADDR;
3006 break;
3008 bcopy(sapstr, lld->llc_snap, 5);
3009 lld->llc_flags |= LLC_SNAP|LLC_SNAP_OID;
3010 break;
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;
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);
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,
3032 DB_TYPE(nmp) = M_PCPROTO;
3033 qreply(q, nmp);
3036 lld->llc_state = DL_IDLE;
3038 return (result);
3044 static int
3045 llc1_subs_unbind(void)
3047 return (DL_UNSUPPORTED);
3050 char *
3051 snapdmp(uchar_t *bstr)
3053 static char buff[32];
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);
3064 static int
3065 llc1_snap_match(llc1_t *lld, struct snaphdr *snap)
3067 return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0);