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]
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>
44 #include <sys/devops.h>
45 #include <sys/sunddi.h>
46 #include <sys/ksynch.h>
48 #include <sys/ethernet.h>
49 #include <sys/strsun.h>
51 #include <netinet/in.h> /* for byteorder macros on machines that define them */
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
,
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
,
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
,
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
,
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
= {
123 LLC1_HIWATER
, /* high water mark */
124 LLC1_LOWATER
, /* low water mark */
127 static struct qinit llc1_rint
= {
137 static struct qinit llc1_wint
= {
147 static struct qinit llc1_muxrint
= {
157 static struct qinit llc1_muxwint
= {
167 struct streamtab llc1_info
= {
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
202 return (mod_install(&modlinkage
));
208 return (mod_remove(&modlinkage
));
212 _info(struct modinfo
*modinfop
)
214 return (mod_info(&modlinkage
, modinfop
));
220 extern int llc1_debug
= 0x0;
225 * Allocate and zero-out "number" structures each of type "structure" in
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
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
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
313 llc1_getinfo(dev_info_t
*dev
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
318 case DDI_INFO_DEVT2DEVINFO
:
322 *result
= (void *)dev
;
326 case DDI_INFO_DEVT2INSTANCE
:
338 * LLC1 open routine, called when device is opened by the user
343 llc1_open(queue_t
*q
, dev_t
*dev
, int flag
, int sflag
, cred_t
*cred
)
352 * Stream already open, sucess.
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
);
367 rw_exit(&llc1_device_list
.llc1_rwlock
);
370 *dev
= makedevice(getmajor(*dev
), minordev
);
372 minordev
= getminor (*dev
);
373 if ((minordev
> MAXMIN32
) || (minordev
== 0)) {
374 rw_exit(&llc1_device_list
.llc1_rwlock
);
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
);
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 */
403 * normal stream close call checks current status and cleans up
404 * data structures that were dynamically allocated
408 llc1_close(queue_t
*q
, int flag
, cred_t
*cred
)
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
) {
432 for (i
= 0; i
< llc1_device_list
.llc1_multisize
; i
++) {
435 if ((mcast
= llc1
->llc_mcast
[i
]) != NULL
) {
437 * disable from stream and possibly
440 if (llc1
->llc_mac_info
&&
441 llc1
->llc_mac_info
->llcp_flags
&
443 llc1_send_disable_multi(
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
));
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
473 llc1_uwput(queue_t
*q
, mblk_t
*mp
)
475 llc1_t
*ld
= (llc1_t
*)(q
->q_ptr
);
478 if (llc1_debug
& LLCTRACE
)
479 printf("llc1_wput(%x %x): type %d\n", q
, mp
, DB_TYPE(mp
));
481 switch (DB_TYPE(mp
)) {
483 case M_IOCTL
: /* no waiting in ioctl's */
484 (void) llc1_ioctl(q
, mp
);
487 case M_FLUSH
: /* canonical flush handling */
488 if (*mp
->b_rptr
& FLUSHW
)
491 if (*mp
->b_rptr
& FLUSHR
) {
493 *mp
->b_rptr
&= ~FLUSHW
;
499 /* for now, we will always queue */
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
);
512 /* need to do further checking */
518 if (llc1_debug
& LLCERRS
)
519 printf("llc1: Unexpected packet type from queue: %d\n",
520 mp
->b_datap
->db_type
);
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.
534 llc1_lrsrv(queue_t
*q
)
537 union DL_primitives
*prim
;
538 llc_mac_info_t
*macinfo
= (llc_mac_info_t
*)q
->q_ptr
;
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");
556 * determine where message goes, then call the proper handler
559 while ((mp
= getq(q
)) != NULL
) {
560 switch (DB_TYPE(mp
)) {
563 prim
= (union DL_primitives
*)mp
->b_rptr
;
564 /* only some primitives ever get passed through */
565 switch (prim
->dl_primitive
) {
567 if (macinfo
->llcp_flags
& LLC1_LINKED
) {
569 * we are in the midst of completing
570 * the I_LINK/I_PLINK and needed this
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
;
580 prim
->info_ack
.dl_mac_type
;
581 if (macinfo
->llcp_type
== DL_ETHER
) {
582 macinfo
->llcp_type
= DL_CSMACD
;
587 macinfo
->llcp_maxpkt
-= 8;
589 macinfo
->llcp_addrlen
=
590 prim
->info_ack
.dl_addr_length
-
591 ABS(prim
->info_ack
.dl_sap_length
);
594 prim
->info_ack
.dl_addr_offset
,
595 macinfo
->llcp_macaddr
,
596 macinfo
->llcp_addrlen
);
599 dl_brdcst_addr_offset
,
600 macinfo
->llcp_broadcast
,
602 dl_brdcst_addr_length
);
604 if (prim
->info_ack
.dl_current_state
==
606 llc1_send_bindreq(macinfo
);
609 * need to put the lower stream into
610 * DLRAW mode. Currently only DL_ETHER
613 switch (macinfo
->llcp_type
) {
617 * raw mode is optimal so ask
618 * for it * we might not get
621 llc1_req_raw(macinfo
);
625 * don't want raw mode so don't
631 if (prim
->info_ack
.dl_current_state
==
633 /* address was wrong before */
635 prim
->info_ack
.dl_addr_offset
,
636 macinfo
->llcp_macaddr
,
637 macinfo
->llcp_addrlen
);
643 * if we had to bind, the macaddr is wrong
647 (void) llc1_req_info(q
);
649 case DL_UNITDATA_IND
:
650 /* when not using raw mode we get these */
651 (void) llc1_recv(macinfo
, mp
);
654 /* binding is a special case */
655 if (prim
->error_ack
.dl_error_primitive
==
658 if (macinfo
->llcp_flags
& LLC1_BINDING
)
659 llc1_send_bindreq(macinfo
);
661 llc1_find_waiting(macinfo
, mp
,
662 prim
->error_ack
.dl_error_primitive
);
664 case DL_PHYS_ADDR_ACK
:
665 llc1_find_waiting(macinfo
, mp
,
669 if (prim
->ok_ack
.dl_correct_primitive
==
671 macinfo
->llcp_flags
&= ~LLC1_BINDING
;
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
;
689 /* need to find the correct queue */
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
;
700 /* need to find the correct queue */
704 llc1_recv(macinfo
, mp
);
712 * llc1_uwsrv - Incoming messages are processed according to the DLPI
713 * protocol specification
717 llc1_uwsrv(queue_t
*q
)
720 llc1_t
*lld
= (llc1_t
*)q
->q_ptr
;
721 union DL_primitives
*prim
;
725 if (llc1_debug
& LLCTRACE
)
726 printf("llc1_wsrv(%x)\n", q
);
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 */
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
++;
740 if (llc1_debug
& LLCERRS
)
742 "llc1_cmds: nonfatal err=%d\n",
757 * retry of a previously processed
758 * UNITDATA_REQ or is a RAW message from
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 */
768 /* This should never happen */
771 if (llc1_debug
& LLCERRS
)
772 printf("llc1_wsrv: type(%x) not supported\n",
773 mp
->b_datap
->db_type
);
775 freemsg(mp
); /* unknown types are discarded */
783 * llc1_multicast used to determine if the address is a multicast address for
787 llc1_multicast(struct ether_addr
*addr
, llc1_t
*lld
)
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)
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.
810 llc1_ioctl(queue_t
*q
, mblk_t
*mp
)
814 struct linkblk
*link
;
815 llc_mac_info_t
*macinfo
;
820 if (llc1_debug
& LLCTRACE
)
821 printf("llc1_ioctl(%x %x)\n", q
, mp
);
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 */
829 link
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
830 tmp
= allocb(sizeof (llc_mac_info_t
), BPRI_MED
);
832 (void) miocnak(q
, mp
, 0, ENOSR
);
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
;
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
=
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);
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
;
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
) {
876 ASSERT(macinfo
->llcp_next
);
878 /* remove from device list */
879 llc1_device_list
.llc1_ndevice
--;
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
);
908 rw_exit(&llc1_device_list
.llc1_rwlock
);
910 * what should really be done here -- force errors on all
913 miocnak(q
, mp
, 0, EINVAL
);
917 error
= miocpullup(mp
, sizeof (struct ll_snioc
));
919 miocnak(q
, mp
, 0, error
);
923 if (llc1_setppa((struct ll_snioc
*)mp
->b_cont
->b_rptr
) >= 0) {
924 miocack(q
, mp
, 0, 0);
927 miocnak(q
, mp
, 0, EINVAL
);
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
);
938 mp
->b_cont
->b_rptr
+ sizeof (struct ll_snioc
);
940 error
= miocpullup(mp
, sizeof (struct ll_snioc
));
942 miocnak(q
, mp
, 0, error
);
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);
952 miocnak(q
, mp
, 0, EINVAL
);
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.
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
;
983 * llc1_getppa(macinfo, snioc) returns the PPA for this stream
986 llc1_getppa(llc_mac_info_t
*macinfo
, struct ll_snioc
*snioc
)
990 snioc
->lli_ppa
= macinfo
->llcp_ppa
;
991 snioc
->lli_index
= macinfo
->llcp_lindex
;
996 * llc1_cmds - process the DL commands as defined in dlpi.h
999 llc1_cmds(queue_t
*q
, mblk_t
*mp
)
1001 union DL_primitives
*dlp
;
1002 llc1_t
*llc
= (llc1_t
*)q
->q_ptr
;
1004 llc_mac_info_t
*macinfo
= llc
->llc_mac_info
;
1006 dlp
= (union DL_primitives
*)mp
->b_rptr
;
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
);
1012 mutex_enter(&llc
->llc_lock
);
1013 rw_enter(&llc1_device_list
.llc1_rwlock
, RW_READER
);
1015 switch (dlp
->dl_primitive
) {
1017 result
= llc1_bind(q
, mp
);
1021 result
= llc1_unbind(q
, mp
);
1024 case DL_SUBS_BIND_REQ
:
1025 result
= llc1_subs_bind(q
, mp
);
1028 case DL_SUBS_UNBIND_REQ
:
1029 result
= llc1_subs_unbind();
1032 case DL_UNITDATA_REQ
:
1033 result
= llc1_unitdata(q
, mp
);
1037 result
= llc1_inforeq(q
, mp
);
1041 result
= llc1attach(q
, mp
);
1045 result
= llc1unattach(q
, mp
);
1048 case DL_ENABMULTI_REQ
:
1049 result
= llc1_enable_multi(q
, mp
);
1052 case DL_DISABMULTI_REQ
:
1053 result
= llc1_disable_multi(q
, mp
);
1057 result
= llc1_xid_req_res(q
, mp
, 0);
1061 result
= llc1_xid_req_res(q
, mp
, 1);
1065 result
= llc1_test_req_res(q
, mp
, 0);
1069 result
= llc1_test_req_res(q
, mp
, 1);
1072 case DL_SET_PHYS_ADDR_REQ
:
1073 result
= DL_NOTSUPPORTED
;
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
);
1082 result
= DL_OUTSTATE
;
1086 case DL_PROMISCON_REQ
:
1087 case DL_PROMISCOFF_REQ
:
1088 result
= DL_NOTSUPPORTED
;
1093 if (llc1_debug
& LLCERRS
)
1094 printf("llc1_cmds: Received unknown primitive: %d\n",
1097 result
= DL_BADPRIM
;
1100 rw_exit(&llc1_device_list
.llc1_rwlock
);
1101 mutex_exit(&llc
->llc_lock
);
1106 * llc1_bind - determine if a SAP is already allocated and whether it is
1107 * legal to do the bind at this time
1110 llc1_bind(queue_t
*q
, mblk_t
*mp
)
1114 llc1_t
*lld
= (llc1_t
*)q
->q_ptr
;
1119 if (llc1_debug
& LLCTRACE
)
1120 printf("llc1_bind(%x %x)\n", q
, mp
);
1123 dlp
= (dl_bind_req_t
*)mp
->b_rptr
;
1127 if (llc1_debug
& LLCPROT
)
1128 printf("llc1_bind: lsap=%x\n", sap
);
1131 if (lld
->llc_mac_info
== NULL
)
1132 return (DL_OUTSTATE
);
1134 if (lld
->llc_qptr
&& lld
->llc_state
!= DL_UNBOUND
) {
1136 if (llc1_debug
& LLCERRS
)
1137 printf("llc1_bind: stream bound/not attached (%d)\n",
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
1153 if (sap
== 0 || (sap
<= 0xFF && (sap
& 1 && sap
!= 0xFF)) ||
1157 lld
->llc_state
= DL_BIND_PENDING
;
1159 /* if we fall through, then the SAP is legal */
1161 if (lld
->llc_mac_info
->llcp_type
== DL_CSMACD
)
1162 sap
= LLC_NOVELL_SAP
;
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
;
1179 if (llc1_debug
& LLCPROT
)
1180 printf("llc1_bind: ok - type = %d\n", lld
->llc_type
);
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 */
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.
1202 llc1_unbind(queue_t
*q
, mblk_t
*mp
)
1207 if (llc1_debug
& LLCTRACE
)
1208 printf("llc1_unbind(%x %x)\n", q
, mp
);
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
) {
1217 if (llc1_debug
& LLCERRS
)
1218 printf("llc1_unbind: wrong state (%d)\n",
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
;
1231 * llc1_inforeq - generate the response to an info request
1234 llc1_inforeq(queue_t
*q
, mblk_t
*mp
)
1242 if (llc1_debug
& LLCTRACE
)
1243 printf("llc1_inforeq(%x %x)\n", q
, mp
);
1245 lld
= (llc1_t
*)q
->q_ptr
;
1247 if (lld
->llc_mac_info
== NULL
)
1248 bufsize
= sizeof (dl_info_ack_t
) + ETHERADDRL
;
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
);
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
);
1293 dlp
->dl_addr_length
= 0; /* not attached yet */
1294 dlp
->dl_addr_offset
= 0;
1295 dlp
->dl_sap_length
= 0; /* 1 bytes on end */
1297 dlp
->dl_version
= DL_VERSION_2
;
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.
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
;
1322 struct llchdr
*llchdr
;
1323 llc_mac_info_t
*macinfo
;
1327 if (llc1_debug
& LLCTRACE
)
1328 printf("llc1_unitdata(%x %x)\n", q
, mp
);
1331 if ((macinfo
= lld
->llc_mac_info
) == NULL
)
1332 return (DL_OUTSTATE
);
1334 if (lld
->llc_state
!= DL_IDLE
) {
1336 if (llc1_debug
& LLCERRS
)
1337 printf("llc1_unitdata: wrong state (%d)\n",
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
,
1364 bcopy(macinfo
->llcp_macaddr
,
1365 hdr
->ether_shost
.ether_addr_octet
,
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
;
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)
1407 default: /* either RAW or unknown, send as is */
1410 DB_TYPE(nmp
) = M_DATA
; /* ether/llc header is data */
1411 nmp
->b_cont
= mp
->b_cont
; /* use the data given */
1415 /* need to format a DL_UNITDATA_REQ with LLC1 header inserted */
1416 nmp
= allocb(sizeof (struct llchdr
)+sizeof (struct snaphdr
),
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);
1433 nmp
->b_cont
= mp
->b_cont
;
1436 if (ismulticast(llcp
->llca_addr
)) {
1437 if (bcmp(llcp
->llca_addr
,
1438 macinfo
->llcp_broadcast
, ETHERADDRL
) == 0)
1444 if (canput(macinfo
->llcp_queue
)) {
1445 lld
->llc_stats
->llcs_bytexmt
+= msgdsize(mp
);
1446 lld
->llc_stats
->llcs_pktxmt
++;
1449 macinfo
->llcp_stats
.llcs_multixmt
++;
1452 macinfo
->llcp_stats
.llcs_brdcstxmt
++;
1456 putnext(macinfo
->llcp_queue
, mp
);
1457 return (LLCE_OK
); /* this is almost correct, the result */
1459 lld
->llc_stats
->llcs_nobuffer
++;
1462 freemsg(nmp
); /* free on failure */
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.
1473 llc1_recv(llc_mac_info_t
*macinfo
, mblk_t
*mp
)
1475 struct ether_addr
*addr
;
1478 int i
, nmcast
= 0, statcnt_normal
= 0, statcnt_brdcst
= 0;
1480 struct llchdr
*llchdr
;
1483 if (llc1_debug
& LLCTRACE
)
1484 printf("llc1_recv(%x, %x)\n", mp
, macinfo
);
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 */
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
;
1500 valid
= adjmsg(mp
->b_cont
, i
- msgdsize(mp
));
1504 struct ether_header
*hdr
;
1506 /* Note that raw mode currently assumes Ethernet */
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
);
1514 (void) adjmsg(mp
, i
+ sizeof (struct ether_header
) -
1520 msgsap
= llchdr
->llc_dsap
;
1523 if (llc1_debug
& LLCRECV
) {
1524 printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr
));
1528 if (llc1_broadcast(addr
, macinfo
)) {
1529 valid
= 2; /* 2 means valid but multicast */
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);
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
1556 if (lld
->llc_qptr
== NULL
||
1557 lld
->llc_state
!= DL_IDLE
||
1558 lld
->llc_mac_info
!= macinfo
) {
1562 if (llc1_debug
& LLCRECV
)
1564 "llc1_recv: type=%d, sap=%x, pkt-dsap=%x\n",
1565 lld
->llc_type
, lld
->llc_sap
,
1568 if (!valid
&& ismulticast(addr
->ether_addr_octet
) &&
1569 lld
->llc_multicnt
> 0 &&
1570 llc1_multicast(addr
, lld
)) {
1572 } else if (lld
->llc_flags
& LLC_PROM
)
1573 /* promiscuous mode */
1576 if ((lld
->llc_flags
& LLC_PROM
) ||
1577 /* promiscuous streams */
1579 (lld
->llc_sap
== msgsap
||
1580 msgsap
== LLC_GLOBAL_SAP
))) {
1582 if (msgsap
== LLC_SNAP_SAP
&&
1583 (lld
->llc_flags
& (LLC_SNAP
|LLC_PROM
)) ==
1585 if (!llc1_snap_match(lld
,
1586 (struct snaphdr
*)(llchdr
+1)))
1589 if (!canputnext(RD(lld
->llc_qptr
))) {
1591 if (llc1_debug
& LLCRECV
)
1593 "llc1_recv: canput failed\n");
1595 lld
->llc_stats
->llcs_blocked
++;
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
);
1607 switch (llchdr
->llc_ctl
) {
1610 * this is an Unnumbered Information
1611 * packet so form a DL_UNITDATA_IND and
1614 nmp
= llc1_form_udata(lld
, macinfo
, mp
);
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
1628 if (lld
->llc_flags
& LLC1_AUTO_XID
) {
1629 nmp
= llc1_xid_reply(macinfo
,
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
1641 nmp
= llc1_xid_ind_con(lld
,
1644 macinfo
->llcp_stats
.llcs_xidrcv
++;
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
,
1664 * hand to the user for
1665 * handling. if this is
1668 * DL_TEST_IND. If it
1669 * is a "response" to
1670 * one of our requests,
1674 nmp
= llc1_test_ind_con(lld
,
1677 macinfo
->llcp_stats
.llcs_testrcv
++;
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.
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
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
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
) {
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
)) {
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
);
1780 llc
->llc_state
= DL_UNATTACHED
;
1785 * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the
1789 llc1unattach(queue_t
*q
, mblk_t
*mp
)
1791 llc1_t
*llc
= (llc1_t
*)q
->q_ptr
;
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
++) {
1816 if ((mcast
= llc
->llc_mcast
[i
]) != NULL
) {
1817 /* disable from stream and possibly lower */
1818 llc1_send_disable_multi(llc
->llc_mac_info
,
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
--;
1830 llc
->llc_state
= DL_UNATTACHED
;
1832 dlokack(q
, mp
, DL_DETACH_REQ
);
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.
1842 llc1_enable_multi(queue_t
*q
, mblk_t
*mp
)
1845 llc_mac_info_t
*macinfo
;
1846 struct ether_addr
*maddr
;
1847 dl_enabmulti_req_t
*multi
;
1849 int status
= DL_BADADDR
;
1852 #if defined(LLC1_DEBUG)
1853 if (llc1_debug
& LLCPROT
) {
1854 printf("llc1_enable_multi(%x, %x)\n", q
, mp
);
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 */
1884 GETSTRUCT(llc_mcast_t
*,
1885 llc1_device_list
.llc1_multisize
);
1886 if (llc
->llc_mcast
== NULL
)
1888 llc
->llc_multicnt
= llc1_device_list
.llc1_multisize
;
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
);
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
)
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
];
1919 if (mcast
== 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
);
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
);
1948 status
= DL_TOOMANY
;
1954 * llc1_disable_multi disable the multicast address on the stream if last
1955 * reference for the mac layer, disable there as well
1958 llc1_disable_multi(queue_t
*q
, mblk_t
*mp
)
1961 llc_mac_info_t
*macinfo
;
1962 struct ether_addr
*maddr
;
1963 dl_enabmulti_req_t
*multi
;
1964 int status
= DL_BADADDR
, i
;
1967 #if defined(LLC1_DEBUG)
1968 if (llc1_debug
& LLCPROT
) {
1969 printf("llc1_enable_multi(%x, %x)\n", q
, mp
);
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
,
1994 llc
->llc_mcast
[i
] = NULL
;
1995 dlokack(q
, mp
, DL_DISABMULTI_REQ
);
1998 status
= DL_NOTENAB
;
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.
2010 llc1_send_disable_multi(llc_mac_info_t
*macinfo
, llc_mcast_t
*mcast
)
2013 dl_disabmulti_req_t
*dis
;
2015 if (mcast
== NULL
) {
2018 if (macinfo
== NULL
|| macinfo
->llcp_queue
== NULL
) {
2021 if (--mcast
->llcm_refcnt
> 0)
2024 mp
= allocb(sizeof (dl_disabmulti_req_t
) + ETHERADDRL
, BPRI_MED
);
2026 dis
= (dl_disabmulti_req_t
*)mp
->b_rptr
;
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
2046 llc1_findminor(llc1dev_t
*device
)
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
)
2061 /* don't need to do anything */
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.
2073 llc1_req_info(queue_t
*q
)
2075 dl_info_req_t
*info
;
2078 mp
= allocb(DL_INFO_REQ_SIZE
, BPRI_MED
);
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
;
2090 * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode
2093 llc1_req_raw(llc_mac_info_t
*macinfo
)
2097 mp
= mkiocb(DLIOCRAW
);
2101 macinfo
->llcp_iocid
= ((struct iocblk
*)mp
->b_rptr
)->ioc_id
;
2103 putnext(macinfo
->llcp_queue
, mp
);
2104 macinfo
->llcp_flags
|= LLC1_RAW_WAIT
;
2109 * if lower stream isn't bound, bind it to something appropriate
2112 llc1_send_bindreq(llc_mac_info_t
*macinfo
)
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
);
2123 mp
= allocb(sizeof (dl_bind_req_t
), BPRI_MED
);
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
2145 llc1_form_udata(llc1_t
*lld
, llc_mac_info_t
*macinfo
, mblk_t
*mp
)
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
);
2161 /* might as well discard since we can't go further */
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
);
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
);
2195 udata
->dl_dest_addr_length
= macinfo
->llcp_addrlen
+ 1;
2196 LLCADDR(udata
, udata
->dl_dest_addr_offset
)->llca_sap
=
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
);
2210 udata
->dl_src_addr_length
= macinfo
->llcp_addrlen
+ 1;
2211 LLCADDR(udata
, udata
->dl_src_addr_offset
)->llca_sap
=
2214 udata
->dl_group_address
= hdr
->ether_dhost
.ether_addr_octet
[0] &
2216 udmp
->b_wptr
+= udata
->dl_src_addr_length
;
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
);
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
=
2249 LLCADDR(udata
, udata
->dl_src_addr_offset
)->llca_sap
=
2253 if (llc1_debug
& LLCRECV
)
2254 printf("llc1_recv: queued message to %x (%d)\n",
2255 lld
->llc_qptr
, lld
->llc_minor
);
2257 /* enqueue for the service routine to process */
2258 putnext(RD(lld
->llc_qptr
), udmp
);
2264 * llc1_xid_reply(macinfo, mp) automatic reply to an XID command
2267 llc1_xid_reply(llc_mac_info_t
*macinfo
, mblk_t
*mp
, int sap
)
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);
2279 if (mp
->b_cont
== NULL
)
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
)
2288 nmp
= allocb(msgdsize(mp
) + LLC_XID_INFO_SIZE
, BPRI_MED
);
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
));
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
);
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
);
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
);
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
2361 llc1_xid_ind_con(llc1_t
*lld
, llc_mac_info_t
*macinfo
, mblk_t
*mp
)
2365 struct ether_header
*hdr
;
2366 struct llchdr
*llchdr
;
2369 nmp
= allocb(sizeof (dl_xid_ind_t
) + 2 * (macinfo
->llcp_addrlen
+ 1),
2374 if ((raw
= (DB_TYPE(mp
) == M_DATA
)) != 0) {
2375 hdr
= (struct ether_header
*)mp
->b_rptr
;
2376 llchdr
= (struct llchdr
*)(hdr
+ 1);
2378 if (mp
->b_rptr
== NULL
)
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;
2389 bcopy(hdr
->ether_dhost
.ether_addr_octet
,
2390 (nmp
->b_rptr
+ xid
->dl_dest_addr_offset
),
2391 xid
->dl_dest_addr_length
);
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
=
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
;
2408 bcopy(hdr
->ether_shost
.ether_addr_octet
,
2409 (nmp
->b_rptr
+ xid
->dl_src_addr_offset
),
2410 xid
->dl_src_addr_length
);
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
;
2427 xid
->dl_primitive
= DL_XID_CON
;
2430 DB_TYPE(nmp
) = M_PROTO
;
2433 (sizeof (struct ether_header
) + sizeof (struct llchdr
))) {
2434 nmp
->b_cont
= dupmsg(mp
);
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
);
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
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
;
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
);
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);
2497 dl_unitdata_req_t
*ud
;
2498 rmp
= allocb(sizeof (dl_unitdata_req_t
) +
2499 (macinfo
->llcp_addrlen
+ 2), BPRI_MED
);
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
=
2515 rmp
->b_wptr
+= xid
->dl_dest_addr_length
;
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);
2524 LLC_XID
| ((xid
->dl_flag
& DL_POLL_FINAL
) ? LLC_P
: 0);
2526 nmp
->b_cont
= mp
->b_cont
;
2529 macinfo
->llcp_stats
.llcs_xidxmt
++;
2530 putnext(WR(macinfo
->llcp_queue
), rmp
);
2535 * llc1_test_reply(macinfo, mp)
2536 * automatic reply to a TEST message
2539 llc1_test_reply(llc_mac_info_t
*macinfo
, mblk_t
*mp
, int sap
)
2542 struct ether_header
*hdr
, *msgether
;
2543 struct llchdr
*llchdr
;
2544 struct llchdr
*msgllc
;
2547 if (DB_TYPE(mp
) == M_PROTO
) {
2548 if (mp
->b_cont
== NULL
)
2550 llchdr
= (struct llchdr
*)mp
->b_cont
->b_rptr
;
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
)
2561 nmp
= copymsg(mp
); /* so info field is duplicated */
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
;
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
);
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
2611 llc1_test_ind_con(llc1_t
*lld
, llc_mac_info_t
*macinfo
, mblk_t
*mp
)
2614 dl_test_ind_t
*test
;
2615 struct ether_header
*hdr
;
2616 struct llchdr
*llchdr
;
2619 nmp
= allocb(sizeof (dl_test_ind_t
) + 2 * (ETHERADDRL
+ 1), BPRI_MED
);
2623 if ((raw
= (DB_TYPE(mp
) == M_DATA
)) != 0) {
2624 hdr
= (struct ether_header
*)mp
->b_rptr
;
2625 llchdr
= (struct llchdr
*)(hdr
+ 1);
2627 if (mp
->b_rptr
== NULL
)
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;
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
);
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
=
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
;
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
);
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
;
2676 test
->dl_primitive
= DL_TEST_CON
;
2679 DB_TYPE(nmp
) = M_PROTO
;
2682 (sizeof (struct ether_header
) + sizeof (struct llchdr
))) {
2683 nmp
->b_cont
= dupmsg(mp
);
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
);
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
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
;
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
),
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);
2747 dl_unitdata_req_t
*ud
;
2749 rmp
= allocb(sizeof (dl_unitdata_req_t
) +
2750 (macinfo
->llcp_addrlen
+ 2), BPRI_MED
);
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
=
2767 rmp
->b_wptr
+= test
->dl_dest_addr_length
;
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);
2776 LLC_TEST
| ((test
->dl_flag
& DL_POLL_FINAL
) ? LLC_P
: 0);
2778 nmp
->b_cont
= mp
->b_cont
;
2781 macinfo
->llcp_stats
.llcs_testxmt
++;
2782 putnext(WR(macinfo
->llcp_queue
), rmp
);
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.
2791 llc1_find_waiting(llc_mac_info_t
*macinfo
, mblk_t
*mp
, long prim
)
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;
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
;
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
;
2834 llc1error(dev_info_t
*dip
, char *fmt
, char *a1
, char *a2
, char *a3
, char *a4
,
2838 static char *lastfmt
;
2842 * Don't print same error message too often.
2844 now
= gethrestime_sec();
2845 if ((last
== (now
& ~1)) && (lastfmt
== fmt
))
2850 cmn_err(CE_CONT
, "%s%d: ",
2851 ddi_get_name(dip
), ddi_get_instance(dip
));
2852 cmn_err(CE_CONT
, fmt
, a1
, a2
, a3
, a4
, a5
, a6
);
2853 cmn_err(CE_CONT
, "\n");
2858 llc1_update_kstat(kstat_t
*ksp
, int rw
)
2860 llc_mac_info_t
*macinfo
;
2861 kstat_named_t
*kstat
;
2862 struct llc_stats
*stats
;
2867 kstat
= (kstat_named_t
*)(ksp
->ks_data
);
2868 macinfo
= (llc_mac_info_t
*)(ksp
->ks_private
);
2869 stats
= &macinfo
->llcp_stats
;
2871 kstat
[LLCS_NOBUFFER
].value
.ul
= stats
->llcs_nobuffer
;
2872 kstat
[LLCS_MULTIXMT
].value
.ul
= stats
->llcs_multixmt
;
2873 kstat
[LLCS_MULTIRCV
].value
.ul
= stats
->llcs_multircv
;
2874 kstat
[LLCS_BRDCSTXMT
].value
.ul
= stats
->llcs_brdcstxmt
;
2875 kstat
[LLCS_BRDCSTRCV
].value
.ul
= stats
->llcs_brdcstrcv
;
2876 kstat
[LLCS_BLOCKED
].value
.ul
= stats
->llcs_blocked
;
2877 kstat
[LLCS_PKTXMT
].value
.ul
= stats
->llcs_pktxmt
;
2878 kstat
[LLCS_PKTRCV
].value
.ul
= stats
->llcs_pktrcv
;
2879 kstat
[LLCS_BYTEXMT
].value
.ul
= stats
->llcs_bytexmt
;
2880 kstat
[LLCS_BYTERCV
].value
.ul
= stats
->llcs_bytercv
;
2881 kstat
[LLCS_XIDXMT
].value
.ul
= stats
->llcs_xidxmt
;
2882 kstat
[LLCS_XIDRCV
].value
.ul
= stats
->llcs_xidrcv
;
2883 kstat
[LLCS_TESTXMT
].value
.ul
= stats
->llcs_testxmt
;
2884 kstat
[LLCS_TESTRCV
].value
.ul
= stats
->llcs_testrcv
;
2885 kstat
[LLCS_IERRORS
].value
.ul
= stats
->llcs_ierrors
;
2886 kstat
[LLCS_OERRORS
].value
.ul
= stats
->llcs_oerrors
;
2891 llc1_init_kstat(llc_mac_info_t
*macinfo
)
2896 * Note that the temporary macinfo->llcp_ppa number is negative.
2898 macinfo
->llcp_kstatp
= kstat_create("llc", (-macinfo
->llcp_ppa
- 1),
2899 NULL
, "net", KSTAT_TYPE_NAMED
,
2900 sizeof (struct llc_stats
) / sizeof (long), 0);
2901 if (macinfo
->llcp_kstatp
== NULL
)
2904 macinfo
->llcp_kstatp
->ks_update
= llc1_update_kstat
;
2905 macinfo
->llcp_kstatp
->ks_private
= (void *)macinfo
;
2907 ksp
= (kstat_named_t
*)(macinfo
->llcp_kstatp
->ks_data
);
2909 kstat_named_init(&ksp
[LLCS_NOBUFFER
], "nobuffer", KSTAT_DATA_ULONG
);
2910 kstat_named_init(&ksp
[LLCS_MULTIXMT
], "multixmt", KSTAT_DATA_ULONG
);
2911 kstat_named_init(&ksp
[LLCS_MULTIRCV
], "multircv", KSTAT_DATA_ULONG
);
2912 kstat_named_init(&ksp
[LLCS_BRDCSTXMT
], "brdcstxmt", KSTAT_DATA_ULONG
);
2913 kstat_named_init(&ksp
[LLCS_BRDCSTRCV
], "brdcstrcv", KSTAT_DATA_ULONG
);
2914 kstat_named_init(&ksp
[LLCS_BLOCKED
], "blocked", KSTAT_DATA_ULONG
);
2915 kstat_named_init(&ksp
[LLCS_PKTXMT
], "pktxmt", KSTAT_DATA_ULONG
);
2916 kstat_named_init(&ksp
[LLCS_PKTRCV
], "pktrcv", KSTAT_DATA_ULONG
);
2917 kstat_named_init(&ksp
[LLCS_BYTEXMT
], "bytexmt", KSTAT_DATA_ULONG
);
2918 kstat_named_init(&ksp
[LLCS_BYTERCV
], "bytercv", KSTAT_DATA_ULONG
);
2919 kstat_named_init(&ksp
[LLCS_XIDXMT
], "xidxmt", KSTAT_DATA_ULONG
);
2920 kstat_named_init(&ksp
[LLCS_XIDRCV
], "xidrcv", KSTAT_DATA_ULONG
);
2921 kstat_named_init(&ksp
[LLCS_TESTXMT
], "testxmt", KSTAT_DATA_ULONG
);
2922 kstat_named_init(&ksp
[LLCS_TESTRCV
], "testrcv", KSTAT_DATA_ULONG
);
2923 kstat_named_init(&ksp
[LLCS_IERRORS
], "ierrors", KSTAT_DATA_ULONG
);
2924 kstat_named_init(&ksp
[LLCS_OERRORS
], "oerrors", KSTAT_DATA_ULONG
);
2925 kstat_install(macinfo
->llcp_kstatp
);
2929 llc1_uninit_kstat(llc_mac_info_t
*macinfo
)
2931 if (macinfo
->llcp_kstatp
) {
2932 kstat_delete(macinfo
->llcp_kstatp
);
2933 macinfo
->llcp_kstatp
= NULL
;
2938 * llc1_subs_bind(q, mp)
2939 * implements the DL_SUBS_BIND_REQ primitive
2940 * this only works for a STREAM bound to LLC_SNAP_SAP
2941 * or one bound to the automatic SNAP mode.
2942 * If bound to LLC_SNAP_SAP, the subs bind can be:
2943 * - 2 octets treated as a native byte order short (ethertype)
2944 * - 3 octets treated as a network order byte string (OID part)
2945 * - 5 octets treated as a network order byte string (full SNAP header)
2946 * If bound to an automatic SNAP mode sap, then only the 3 octet
2950 llc1_subs_bind(queue_t
*q
, mblk_t
*mp
)
2952 llc1_t
*lld
= (llc1_t
*)q
->q_ptr
;
2953 dl_subs_bind_req_t
*subs
= (dl_subs_bind_req_t
*)mp
->b_rptr
;
2959 #if defined(LLC1_DEBUG)
2960 if (llc1_debug
& (LLCTRACE
|LLCPROT
)) {
2961 printf("llc1_subs_bind (%x, %x)\n", q
, mp
);
2965 if (lld
== NULL
|| lld
->llc_state
!= DL_IDLE
) {
2966 result
= DL_OUTSTATE
;
2967 } else if (lld
->llc_sap
!= LLC_SNAP_SAP
||
2968 subs
->dl_subs_bind_class
!= DL_HIERARCHICAL_BIND
) {
2969 /* we only want to support this for SNAP at present */
2970 result
= DL_UNSUPPORTED
;
2973 lld
->llc_state
= DL_SUBS_BIND_PND
;
2975 sapstr
= (uchar_t
*)(mp
->b_rptr
+ subs
->dl_subs_sap_offset
);
2978 switch (subs
->dl_subs_sap_length
) {
2979 case 2: /* just the ethertype part */
2980 if (lld
->llc_flags
& LLC_SNAP
) {
2981 result
= DL_BADADDR
;
2984 ((uchar_t
*)&subssap
)[0] = sapstr
[0];
2985 ((uchar_t
*)&subssap
)[1] = sapstr
[1];
2986 subssap
= htons(subssap
);
2987 lld
->llc_snap
[3] = ((uchar_t
*)&subssap
)[0];
2988 lld
->llc_snap
[4] = ((uchar_t
*)&subssap
)[1];
2989 lld
->llc_flags
|= LLC_SNAP
;
2992 case 3: /* just the OID part */
2993 if ((lld
->llc_flags
& (LLC_SNAP
|LLC_SNAP_OID
)) ==
2994 (LLC_SNAP
|LLC_SNAP_OID
)) {
2995 result
= DL_BADADDR
;
2998 bcopy(sapstr
, lld
->llc_snap
, 3);
2999 lld
->llc_flags
|= LLC_SNAP_OID
;
3002 case 5: /* full SNAP header */
3003 if (lld
->llc_flags
& (LLC_SNAP
|LLC_SNAP_OID
)) {
3004 result
= DL_BADADDR
;
3007 bcopy(sapstr
, lld
->llc_snap
, 5);
3008 lld
->llc_flags
|= LLC_SNAP
|LLC_SNAP_OID
;
3011 /* if successful, acknowledge and enter the proper state */
3012 if (result
== LLCE_OK
) {
3014 dl_subs_bind_ack_t
*ack
;
3016 if (DB_REF(mp
) != 1 ||
3017 MBLKL(mp
) < (sizeof (dl_subs_bind_ack_t
) + 5)) {
3019 nmp
= allocb(sizeof (dl_subs_bind_ack_t
) + 5,
3022 ack
= (dl_subs_bind_ack_t
*)nmp
->b_rptr
;
3023 nmp
->b_wptr
= nmp
->b_rptr
+
3024 sizeof (dl_subs_bind_ack_t
) + 5;
3025 ack
->dl_primitive
= DL_SUBS_BIND_ACK
;
3026 ack
->dl_subs_sap_offset
= sizeof (dl_subs_bind_ack_t
);
3027 ack
->dl_subs_sap_length
= 5;
3028 bcopy(lld
->llc_snap
,
3029 (caddr_t
)nmp
->b_rptr
+ ack
->dl_subs_sap_offset
+ 5,
3031 DB_TYPE(nmp
) = M_PCPROTO
;
3035 lld
->llc_state
= DL_IDLE
;
3044 llc1_subs_unbind(void)
3046 return (DL_UNSUPPORTED
);
3050 snapdmp(uchar_t
*bstr
)
3052 static char buff
[32];
3054 (void) sprintf(buff
, "%x.%x.%x.%x.%x",
3064 llc1_snap_match(llc1_t
*lld
, struct snaphdr
*snap
)
3066 return (bcmp(snap
->snap_oid
, lld
->llc_snap
, 5) == 0);