10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * llc1 - an LLC Class 1 MUX compatible with SunConnect LLC2 uses DLPI
290Sstevel@tonic-gate * interface. Its primary use is to support RPL for network boot but can be
300Sstevel@tonic-gate * used by other protocols.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/mkdev.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/systm.h>
390Sstevel@tonic-gate #include <sys/stropts.h>
400Sstevel@tonic-gate #include <sys/stream.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/conf.h>
430Sstevel@tonic-gate #include <sys/ddi.h>
440Sstevel@tonic-gate #include <sys/devops.h>
450Sstevel@tonic-gate #include <sys/sunddi.h>
460Sstevel@tonic-gate #include <sys/ksynch.h>
470Sstevel@tonic-gate #include <sys/dlpi.h>
480Sstevel@tonic-gate #include <sys/ethernet.h>
490Sstevel@tonic-gate #include <sys/strsun.h>
500Sstevel@tonic-gate #include <sys/stat.h>
510Sstevel@tonic-gate #include <netinet/in.h> /* for byteorder macros on machines that define them */
520Sstevel@tonic-gate #include <sys/llc1.h>
530Sstevel@tonic-gate #include <sys/kstat.h>
540Sstevel@tonic-gate #include <sys/debug.h>
550Sstevel@tonic-gate
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate * function prototypes, etc.
580Sstevel@tonic-gate */
590Sstevel@tonic-gate static int llc1_open(queue_t *q, dev_t *dev, int flag, int sflag,
600Sstevel@tonic-gate cred_t *cred);
610Sstevel@tonic-gate static int llc1_close(queue_t *q, int flag, cred_t *cred);
620Sstevel@tonic-gate static int llc1_uwput(queue_t *q, mblk_t *mp);
630Sstevel@tonic-gate static int llc1_uwsrv(queue_t *q);
640Sstevel@tonic-gate static int llc1_lrsrv(queue_t *q);
650Sstevel@tonic-gate static int llc1_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
660Sstevel@tonic-gate static int llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
670Sstevel@tonic-gate static int llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
680Sstevel@tonic-gate
690Sstevel@tonic-gate static mblk_t *llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo,
700Sstevel@tonic-gate mblk_t *mp);
710Sstevel@tonic-gate static mblk_t *llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
720Sstevel@tonic-gate static mblk_t *llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
730Sstevel@tonic-gate mblk_t *mp);
740Sstevel@tonic-gate static mblk_t *llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
750Sstevel@tonic-gate static mblk_t *llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
760Sstevel@tonic-gate mblk_t *mp);
770Sstevel@tonic-gate
780Sstevel@tonic-gate static void llc1_ioctl(queue_t *q, mblk_t *mp);
790Sstevel@tonic-gate static void llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp);
800Sstevel@tonic-gate static void llc1_req_raw(llc_mac_info_t *macinfo);
810Sstevel@tonic-gate static void llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim);
820Sstevel@tonic-gate
830Sstevel@tonic-gate static minor_t llc1_findminor(llc1dev_t *device);
840Sstevel@tonic-gate static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *);
850Sstevel@tonic-gate
860Sstevel@tonic-gate static void llc1insque(void *elem, void *pred);
870Sstevel@tonic-gate static void llc1remque(void *arg);
880Sstevel@tonic-gate static void llc1error();
890Sstevel@tonic-gate static int llc1_subs_unbind(void);
900Sstevel@tonic-gate static void llc1_init_kstat(llc_mac_info_t *macinfo);
910Sstevel@tonic-gate static void llc1_uninit_kstat(llc_mac_info_t *macinfo);
920Sstevel@tonic-gate static int llc1_update_kstat(kstat_t *ksp, int rw);
930Sstevel@tonic-gate static int llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo);
940Sstevel@tonic-gate static int llc1_unbind(queue_t *q, mblk_t *mp);
950Sstevel@tonic-gate static int llc1_subs_bind(queue_t *q, mblk_t *mp);
960Sstevel@tonic-gate static int llc1_unitdata(queue_t *q, mblk_t *mp);
970Sstevel@tonic-gate static int llc1_inforeq(queue_t *q, mblk_t *mp);
980Sstevel@tonic-gate static int llc1attach(queue_t *q, mblk_t *mp);
990Sstevel@tonic-gate static void llc1_send_bindreq(llc_mac_info_t *macinfo);
1000Sstevel@tonic-gate static int llc1_req_info(queue_t *q);
1010Sstevel@tonic-gate static int llc1_cmds(queue_t *q, mblk_t *mp);
1020Sstevel@tonic-gate static int llc1_setppa(struct ll_snioc *snioc);
1030Sstevel@tonic-gate static int llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc);
1040Sstevel@tonic-gate static int llc1_bind(queue_t *q, mblk_t *mp);
1050Sstevel@tonic-gate static int llc1unattach(queue_t *q, mblk_t *mp);
1060Sstevel@tonic-gate static int llc1_enable_multi(queue_t *q, mblk_t *mp);
1070Sstevel@tonic-gate static int llc1_disable_multi(queue_t *q, mblk_t *mp);
1080Sstevel@tonic-gate static int llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res);
1090Sstevel@tonic-gate static int llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res);
1100Sstevel@tonic-gate static int llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo);
1110Sstevel@tonic-gate static int llc1_snap_match(llc1_t *lld, struct snaphdr *snap);
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate * the standard streams glue for defining the type of streams entity and the
1150Sstevel@tonic-gate * operational parameters.
1160Sstevel@tonic-gate */
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate static struct module_info llc1_minfo = {
1190Sstevel@tonic-gate LLC1IDNUM,
1200Sstevel@tonic-gate "llc1",
1210Sstevel@tonic-gate 0,
1220Sstevel@tonic-gate LLC1_DEFMAX,
1230Sstevel@tonic-gate LLC1_HIWATER, /* high water mark */
1240Sstevel@tonic-gate LLC1_LOWATER, /* low water mark */
1250Sstevel@tonic-gate };
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate static struct qinit llc1_rint = {
1280Sstevel@tonic-gate NULL,
1290Sstevel@tonic-gate NULL,
1300Sstevel@tonic-gate llc1_open,
1310Sstevel@tonic-gate llc1_close,
1320Sstevel@tonic-gate NULL,
1330Sstevel@tonic-gate &llc1_minfo,
1340Sstevel@tonic-gate NULL
1350Sstevel@tonic-gate };
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate static struct qinit llc1_wint = {
1380Sstevel@tonic-gate llc1_uwput,
1390Sstevel@tonic-gate llc1_uwsrv,
1400Sstevel@tonic-gate NULL,
1410Sstevel@tonic-gate NULL,
1420Sstevel@tonic-gate NULL,
1430Sstevel@tonic-gate &llc1_minfo,
1440Sstevel@tonic-gate NULL
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate static struct qinit llc1_muxrint = {
1480Sstevel@tonic-gate putq,
1490Sstevel@tonic-gate llc1_lrsrv,
1500Sstevel@tonic-gate NULL,
1510Sstevel@tonic-gate NULL,
1520Sstevel@tonic-gate NULL,
1530Sstevel@tonic-gate &llc1_minfo,
1540Sstevel@tonic-gate NULL
1550Sstevel@tonic-gate };
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate static struct qinit llc1_muxwint = {
1580Sstevel@tonic-gate NULL,
1590Sstevel@tonic-gate NULL,
1600Sstevel@tonic-gate NULL,
1610Sstevel@tonic-gate NULL,
1620Sstevel@tonic-gate NULL,
1630Sstevel@tonic-gate &llc1_minfo,
1640Sstevel@tonic-gate NULL
1650Sstevel@tonic-gate };
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate struct streamtab llc1_info = {
1680Sstevel@tonic-gate &llc1_rint,
1690Sstevel@tonic-gate &llc1_wint,
1700Sstevel@tonic-gate &llc1_muxrint,
1710Sstevel@tonic-gate &llc1_muxwint
1720Sstevel@tonic-gate };
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate * loadable module/driver wrapper this allows llc1 to be unloaded later
1760Sstevel@tonic-gate */
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate #if !defined(BUILD_STATIC)
1790Sstevel@tonic-gate #include <sys/modctl.h>
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /* define the "ops" structure for a STREAMS driver */
1820Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(llc1_ops, nulldev, nulldev, llc1_attach,
183*7656SSherry.Moore@Sun.COM llc1_detach, nodev, llc1_getinfo, D_MP | D_MTPERMOD, &llc1_info,
184*7656SSherry.Moore@Sun.COM ddi_quiesce_not_supported);
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * Module linkage information for the kernel.
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate static struct modldrv modldrv = {
1900Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */
191*7656SSherry.Moore@Sun.COM "LLC Class 1 Driver",
1920Sstevel@tonic-gate &llc1_ops, /* driver ops */
1930Sstevel@tonic-gate };
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate static struct modlinkage modlinkage = {
1960Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
1970Sstevel@tonic-gate };
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate int
_init(void)2000Sstevel@tonic-gate _init(void)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate return (mod_install(&modlinkage));
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate int
_fini(void)2060Sstevel@tonic-gate _fini(void)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate return (mod_remove(&modlinkage));
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2120Sstevel@tonic-gate _info(struct modinfo *modinfop)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate #endif
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate #ifdef LLC1_DEBUG
2200Sstevel@tonic-gate extern int llc1_debug = 0x0;
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate #endif
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * Allocate and zero-out "number" structures each of type "structure" in
2260Sstevel@tonic-gate * kernel memory.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate #define GETSTRUCT(structure, number) \
2290Sstevel@tonic-gate (kmem_zalloc(sizeof (structure) * (number), KM_NOSLEEP))
2300Sstevel@tonic-gate #define GETBUF(structure, size) \
2310Sstevel@tonic-gate (kmem_zalloc(size, KM_NOSLEEP))
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate static struct llc1device llc1_device_list;
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * llc1_attach - init time attach support When the hardware specific attach
2370Sstevel@tonic-gate * is called, it must call this procedure with the device class structure
2380Sstevel@tonic-gate */
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate static int
llc1_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)2410Sstevel@tonic-gate llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate if (cmd != DDI_ATTACH)
2440Sstevel@tonic-gate return (DDI_FAILURE);
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * there isn't any hardware but we do need to initialize things
2480Sstevel@tonic-gate */
2490Sstevel@tonic-gate if (!(llc1_device_list.llc1_status & LLC1_ATTACHED)) {
2500Sstevel@tonic-gate llc1_device_list.llc1_status |= LLC1_ATTACHED;
2510Sstevel@tonic-gate rw_init(&llc1_device_list.llc1_rwlock, NULL, RW_DRIVER, NULL);
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /* make sure minor device lists are initialized */
2540Sstevel@tonic-gate llc1_device_list.llc1_str_next =
255*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_str_prev =
256*7656SSherry.Moore@Sun.COM (llc1_t *)&llc1_device_list.llc1_str_next;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate /* make sure device list is initialized */
2590Sstevel@tonic-gate llc1_device_list.llc1_mac_next =
260*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_mac_prev =
261*7656SSherry.Moore@Sun.COM (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * now do all the DDI stuff necessary
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate ddi_set_driver_private(devinfo, &llc1_device_list);
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate * create the file system device node
2720Sstevel@tonic-gate */
2730Sstevel@tonic-gate if (ddi_create_minor_node(devinfo, "llc1", S_IFCHR,
2740Sstevel@tonic-gate 0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
2750Sstevel@tonic-gate llc1error(devinfo, "ddi_create_minor_node failed");
2760Sstevel@tonic-gate ddi_remove_minor_node(devinfo, NULL);
2770Sstevel@tonic-gate return (DDI_FAILURE);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate llc1_device_list.llc1_multisize = ddi_getprop(DDI_DEV_T_NONE,
280*7656SSherry.Moore@Sun.COM devinfo, 0, "multisize", 0);
2810Sstevel@tonic-gate if (llc1_device_list.llc1_multisize == 0)
2820Sstevel@tonic-gate llc1_device_list.llc1_multisize = LLC1_MAX_MULTICAST;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate ddi_report_dev(devinfo);
2850Sstevel@tonic-gate return (DDI_SUCCESS);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * llc1_detach standard kernel interface routine
2900Sstevel@tonic-gate */
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate static int
llc1_detach(dev_info_t * dev,ddi_detach_cmd_t cmd)2930Sstevel@tonic-gate llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate if (cmd != DDI_DETACH) {
2960Sstevel@tonic-gate return (DDI_FAILURE);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate if (llc1_device_list.llc1_ndevice > 0)
2990Sstevel@tonic-gate return (DDI_FAILURE);
3000Sstevel@tonic-gate /* remove all mutex and locks */
3010Sstevel@tonic-gate rw_destroy(&llc1_device_list.llc1_rwlock);
3020Sstevel@tonic-gate llc1_device_list.llc1_status = 0; /* no longer attached */
3030Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL);
3040Sstevel@tonic-gate return (DDI_SUCCESS);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate * llc1_devinfo(dev, cmd, arg, result) standard kernel devinfo lookup
3090Sstevel@tonic-gate * function
3100Sstevel@tonic-gate */
3110Sstevel@tonic-gate /*ARGSUSED2*/
3120Sstevel@tonic-gate static int
llc1_getinfo(dev_info_t * dev,ddi_info_cmd_t cmd,void * arg,void ** result)3130Sstevel@tonic-gate llc1_getinfo(dev_info_t *dev, ddi_info_cmd_t cmd, void *arg, void **result)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate int error;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate switch (cmd) {
3180Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
3190Sstevel@tonic-gate if (dev == NULL) {
3200Sstevel@tonic-gate error = DDI_FAILURE;
3210Sstevel@tonic-gate } else {
3220Sstevel@tonic-gate *result = (void *)dev;
3230Sstevel@tonic-gate error = DDI_SUCCESS;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate break;
3260Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
3270Sstevel@tonic-gate *result = (void *)0;
3280Sstevel@tonic-gate error = DDI_SUCCESS;
3290Sstevel@tonic-gate break;
3300Sstevel@tonic-gate default:
3310Sstevel@tonic-gate error = DDI_FAILURE;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate return (error);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * llc1_open()
3380Sstevel@tonic-gate * LLC1 open routine, called when device is opened by the user
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /*ARGSUSED2*/
3420Sstevel@tonic-gate static int
llc1_open(queue_t * q,dev_t * dev,int flag,int sflag,cred_t * cred)3430Sstevel@tonic-gate llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate llc1_t *llc1;
3460Sstevel@tonic-gate minor_t minordev;
3470Sstevel@tonic-gate int status = 0;
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate ASSERT(q);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate /*
3520Sstevel@tonic-gate * Stream already open, sucess.
3530Sstevel@tonic-gate */
3540Sstevel@tonic-gate if (q->q_ptr)
3550Sstevel@tonic-gate return (0);
3560Sstevel@tonic-gate /*
3570Sstevel@tonic-gate * Serialize access through open/close this will serialize across all
3580Sstevel@tonic-gate * llc1 devices, but open and close are not frequent so should not
3590Sstevel@tonic-gate * induce much, if any delay.
3600Sstevel@tonic-gate */
3610Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate if (sflag == CLONEOPEN) {
3640Sstevel@tonic-gate /* need to find a minor dev */
3650Sstevel@tonic-gate minordev = llc1_findminor(&llc1_device_list);
3660Sstevel@tonic-gate if (minordev == 0) {
3670Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
3680Sstevel@tonic-gate return (ENXIO);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), minordev);
3710Sstevel@tonic-gate } else {
3720Sstevel@tonic-gate minordev = getminor (*dev);
3730Sstevel@tonic-gate if ((minordev > MAXMIN32) || (minordev == 0)) {
3740Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
3750Sstevel@tonic-gate return (ENXIO);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate * get a per-stream structure and link things together so we
3810Sstevel@tonic-gate * can easily find them later.
3820Sstevel@tonic-gate */
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate llc1 = kmem_zalloc(sizeof (llc1_t), KM_SLEEP);
3850Sstevel@tonic-gate llc1->llc_qptr = q;
3860Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)llc1;
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate * fill in the structure and state info
3890Sstevel@tonic-gate */
3900Sstevel@tonic-gate llc1->llc_state = DL_UNATTACHED;
3910Sstevel@tonic-gate llc1->llc_style = DL_STYLE2;
3920Sstevel@tonic-gate llc1->llc_minor = minordev;
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate mutex_init(&llc1->llc_lock, NULL, MUTEX_DRIVER, NULL);
3950Sstevel@tonic-gate llc1insque(llc1, llc1_device_list.llc1_str_prev);
3960Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
3970Sstevel@tonic-gate qprocson(q); /* start the queues running */
3980Sstevel@tonic-gate return (status);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate * llc1_close(q)
4030Sstevel@tonic-gate * normal stream close call checks current status and cleans up
4040Sstevel@tonic-gate * data structures that were dynamically allocated
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate /*ARGSUSED1*/
4070Sstevel@tonic-gate static int
llc1_close(queue_t * q,int flag,cred_t * cred)4080Sstevel@tonic-gate llc1_close(queue_t *q, int flag, cred_t *cred)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate llc1_t *llc1;
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate ASSERT(q);
4130Sstevel@tonic-gate ASSERT(q->q_ptr);
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate qprocsoff(q);
4160Sstevel@tonic-gate llc1 = (llc1_t *)q->q_ptr;
4170Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
4180Sstevel@tonic-gate /* completely disassociate the stream from the device */
4190Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL;
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate (void) llc1remque(llc1); /* remove from active list */
4220Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate mutex_enter(&llc1->llc_lock);
4250Sstevel@tonic-gate if (llc1->llc_state == DL_IDLE || llc1->llc_state == DL_UNBOUND) {
4260Sstevel@tonic-gate llc1->llc_state = DL_UNBOUND; /* force the issue */
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate if (llc1->llc_mcast != NULL) {
4300Sstevel@tonic-gate int i;
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
4330Sstevel@tonic-gate llc_mcast_t *mcast;
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate if ((mcast = llc1->llc_mcast[i]) != NULL) {
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate * disable from stream and possibly
4380Sstevel@tonic-gate * lower stream
4390Sstevel@tonic-gate */
4400Sstevel@tonic-gate if (llc1->llc_mac_info &&
4410Sstevel@tonic-gate llc1->llc_mac_info->llcp_flags &
442*7656SSherry.Moore@Sun.COM LLC1_AVAILABLE)
4430Sstevel@tonic-gate llc1_send_disable_multi(
444*7656SSherry.Moore@Sun.COM llc1->llc_mac_info,
445*7656SSherry.Moore@Sun.COM mcast);
4460Sstevel@tonic-gate llc1->llc_mcast[i] = NULL;
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate kmem_free(llc1->llc_mcast,
4500Sstevel@tonic-gate sizeof (llc_mcast_t *) * llc1->llc_multicnt);
4510Sstevel@tonic-gate llc1->llc_mcast = NULL;
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate llc1->llc_state = DL_UNATTACHED;
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate mutex_exit(&llc1->llc_lock);
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate mutex_destroy(&llc1->llc_lock);
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate kmem_free(llc1, sizeof (llc1_t));
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate return (0);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate * llc1_uwput()
4660Sstevel@tonic-gate * general llc stream write put routine. Receives ioctl's from
4670Sstevel@tonic-gate * user level and data from upper modules and processes them immediately.
4680Sstevel@tonic-gate * M_PROTO/M_PCPROTO are queued for later processing by the service
4690Sstevel@tonic-gate * procedure.
4700Sstevel@tonic-gate */
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate static int
llc1_uwput(queue_t * q,mblk_t * mp)4730Sstevel@tonic-gate llc1_uwput(queue_t *q, mblk_t *mp)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate llc1_t *ld = (llc1_t *)(q->q_ptr);
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate #ifdef LLC1_DEBUG
4780Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
4790Sstevel@tonic-gate printf("llc1_wput(%x %x): type %d\n", q, mp, DB_TYPE(mp));
4800Sstevel@tonic-gate #endif
4810Sstevel@tonic-gate switch (DB_TYPE(mp)) {
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate case M_IOCTL: /* no waiting in ioctl's */
4840Sstevel@tonic-gate (void) llc1_ioctl(q, mp);
4850Sstevel@tonic-gate break;
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate case M_FLUSH: /* canonical flush handling */
4880Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
4890Sstevel@tonic-gate flushq(q, 0);
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
4920Sstevel@tonic-gate flushq(RD(q), 0);
4930Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
4940Sstevel@tonic-gate qreply(q, mp);
4950Sstevel@tonic-gate } else
4960Sstevel@tonic-gate freemsg(mp);
4970Sstevel@tonic-gate break;
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate /* for now, we will always queue */
5000Sstevel@tonic-gate case M_PROTO:
5010Sstevel@tonic-gate case M_PCPROTO:
5020Sstevel@tonic-gate (void) putq(q, mp);
5030Sstevel@tonic-gate break;
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate case M_DATA:
5060Sstevel@tonic-gate /* fast data / raw support */
5070Sstevel@tonic-gate if ((ld->llc_flags & (LLC_RAW | LLC_FAST)) == 0 ||
5080Sstevel@tonic-gate ld->llc_state != DL_IDLE) {
5090Sstevel@tonic-gate (void) merror(q, mp, EPROTO);
5100Sstevel@tonic-gate break;
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate /* need to do further checking */
5130Sstevel@tonic-gate (void) putq(q, mp);
5140Sstevel@tonic-gate break;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate default:
5170Sstevel@tonic-gate #ifdef LLC1_DEBUG
5180Sstevel@tonic-gate if (llc1_debug & LLCERRS)
5190Sstevel@tonic-gate printf("llc1: Unexpected packet type from queue: %d\n",
520*7656SSherry.Moore@Sun.COM mp->b_datap->db_type);
5210Sstevel@tonic-gate #endif
5220Sstevel@tonic-gate freemsg(mp);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate return (0);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * llc1_lrsrv()
5290Sstevel@tonic-gate * called when data is put into the service queue from below.
5300Sstevel@tonic-gate * Determines additional processing that might be needed and sends the data
5310Sstevel@tonic-gate * upstream in the form of a Data Indication packet.
5320Sstevel@tonic-gate */
5330Sstevel@tonic-gate static int
llc1_lrsrv(queue_t * q)5340Sstevel@tonic-gate llc1_lrsrv(queue_t *q)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate mblk_t *mp;
5370Sstevel@tonic-gate union DL_primitives *prim;
5380Sstevel@tonic-gate llc_mac_info_t *macinfo = (llc_mac_info_t *)q->q_ptr;
5390Sstevel@tonic-gate struct iocblk *iocp;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate #ifdef LLC1_DEBUG
5420Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
5430Sstevel@tonic-gate printf("llc1_rsrv(%x)\n", q);
5440Sstevel@tonic-gate if (llc1_debug & LLCRECV) {
5450Sstevel@tonic-gate printf("llc1_lrsrv: q=%x macinfo=%x", q, macinfo);
5460Sstevel@tonic-gate if (macinfo == NULL) {
5470Sstevel@tonic-gate printf("NULL macinfo");
5480Sstevel@tonic-gate panic("null macinfo in lrsrv");
5490Sstevel@tonic-gate /*NOTREACHED*/
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate printf("\n");
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate #endif
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate * determine where message goes, then call the proper handler
5570Sstevel@tonic-gate */
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
5600Sstevel@tonic-gate switch (DB_TYPE(mp)) {
5610Sstevel@tonic-gate case M_PROTO:
5620Sstevel@tonic-gate case M_PCPROTO:
5630Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr;
5640Sstevel@tonic-gate /* only some primitives ever get passed through */
5650Sstevel@tonic-gate switch (prim->dl_primitive) {
5660Sstevel@tonic-gate case DL_INFO_ACK:
5670Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_LINKED) {
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate * we are in the midst of completing
5700Sstevel@tonic-gate * the I_LINK/I_PLINK and needed this
5710Sstevel@tonic-gate * info
5720Sstevel@tonic-gate */
5730Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_LINKED;
5740Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_AVAILABLE;
5750Sstevel@tonic-gate macinfo->llcp_maxpkt =
576*7656SSherry.Moore@Sun.COM prim->info_ack.dl_max_sdu;
5770Sstevel@tonic-gate macinfo->llcp_minpkt =
578*7656SSherry.Moore@Sun.COM prim->info_ack.dl_min_sdu;
5790Sstevel@tonic-gate macinfo->llcp_type =
580*7656SSherry.Moore@Sun.COM prim->info_ack.dl_mac_type;
5810Sstevel@tonic-gate if (macinfo->llcp_type == DL_ETHER) {
5820Sstevel@tonic-gate macinfo->llcp_type = DL_CSMACD;
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * size of max header
5850Sstevel@tonic-gate * (including SNAP)
5860Sstevel@tonic-gate */
5870Sstevel@tonic-gate macinfo->llcp_maxpkt -= 8;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate macinfo->llcp_addrlen =
5900Sstevel@tonic-gate prim->info_ack.dl_addr_length -
5910Sstevel@tonic-gate ABS(prim->info_ack.dl_sap_length);
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate bcopy(mp->b_rptr +
5940Sstevel@tonic-gate prim->info_ack.dl_addr_offset,
5950Sstevel@tonic-gate macinfo->llcp_macaddr,
5960Sstevel@tonic-gate macinfo->llcp_addrlen);
5970Sstevel@tonic-gate bcopy(mp->b_rptr +
598*7656SSherry.Moore@Sun.COM prim->info_ack.
599*7656SSherry.Moore@Sun.COM dl_brdcst_addr_offset,
600*7656SSherry.Moore@Sun.COM macinfo->llcp_broadcast,
601*7656SSherry.Moore@Sun.COM prim->info_ack.
602*7656SSherry.Moore@Sun.COM dl_brdcst_addr_length);
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate if (prim->info_ack.dl_current_state ==
605*7656SSherry.Moore@Sun.COM DL_UNBOUND)
6060Sstevel@tonic-gate llc1_send_bindreq(macinfo);
6070Sstevel@tonic-gate freemsg(mp);
6080Sstevel@tonic-gate /*
6090Sstevel@tonic-gate * need to put the lower stream into
6100Sstevel@tonic-gate * DLRAW mode. Currently only DL_ETHER
6110Sstevel@tonic-gate * or DL_CSMACD
6120Sstevel@tonic-gate */
6130Sstevel@tonic-gate switch (macinfo->llcp_type) {
6140Sstevel@tonic-gate case DL_ETHER:
6150Sstevel@tonic-gate case DL_CSMACD:
6160Sstevel@tonic-gate /*
6170Sstevel@tonic-gate * raw mode is optimal so ask
6180Sstevel@tonic-gate * for it * we might not get
6190Sstevel@tonic-gate * it but that's OK
6200Sstevel@tonic-gate */
6210Sstevel@tonic-gate llc1_req_raw(macinfo);
6220Sstevel@tonic-gate break;
6230Sstevel@tonic-gate default:
6240Sstevel@tonic-gate /*
6250Sstevel@tonic-gate * don't want raw mode so don't
6260Sstevel@tonic-gate * ask for it
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate break;
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate } else {
631*7656SSherry.Moore@Sun.COM if (prim->info_ack.dl_current_state ==
632*7656SSherry.Moore@Sun.COM DL_IDLE)
6330Sstevel@tonic-gate /* address was wrong before */
6340Sstevel@tonic-gate bcopy(mp->b_rptr +
6350Sstevel@tonic-gate prim->info_ack.dl_addr_offset,
6360Sstevel@tonic-gate macinfo->llcp_macaddr,
6370Sstevel@tonic-gate macinfo->llcp_addrlen);
6380Sstevel@tonic-gate freemsg(mp);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate break;
6410Sstevel@tonic-gate case DL_BIND_ACK:
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate * if we had to bind, the macaddr is wrong
6440Sstevel@tonic-gate * so get it again
6450Sstevel@tonic-gate */
6460Sstevel@tonic-gate freemsg(mp);
6470Sstevel@tonic-gate (void) llc1_req_info(q);
6480Sstevel@tonic-gate break;
6490Sstevel@tonic-gate case DL_UNITDATA_IND:
6500Sstevel@tonic-gate /* when not using raw mode we get these */
6510Sstevel@tonic-gate (void) llc1_recv(macinfo, mp);
6520Sstevel@tonic-gate break;
6530Sstevel@tonic-gate case DL_ERROR_ACK:
6540Sstevel@tonic-gate /* binding is a special case */
6550Sstevel@tonic-gate if (prim->error_ack.dl_error_primitive ==
656*7656SSherry.Moore@Sun.COM DL_BIND_REQ) {
6570Sstevel@tonic-gate freemsg(mp);
6580Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_BINDING)
6590Sstevel@tonic-gate llc1_send_bindreq(macinfo);
6600Sstevel@tonic-gate } else
6610Sstevel@tonic-gate llc1_find_waiting(macinfo, mp,
6620Sstevel@tonic-gate prim->error_ack.dl_error_primitive);
6630Sstevel@tonic-gate break;
6640Sstevel@tonic-gate case DL_PHYS_ADDR_ACK:
6650Sstevel@tonic-gate llc1_find_waiting(macinfo, mp,
666*7656SSherry.Moore@Sun.COM DL_PHYS_ADDR_REQ);
6670Sstevel@tonic-gate break;
6680Sstevel@tonic-gate case DL_OK_ACK:
6690Sstevel@tonic-gate if (prim->ok_ack.dl_correct_primitive ==
670*7656SSherry.Moore@Sun.COM DL_BIND_REQ)
6710Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_BINDING;
6720Sstevel@tonic-gate /* FALLTHROUGH */
6730Sstevel@tonic-gate default:
6740Sstevel@tonic-gate freemsg(mp);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate break;
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate case M_IOCACK:
6790Sstevel@tonic-gate /* probably our DLIOCRAW completing */
6800Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
6810Sstevel@tonic-gate if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
6820Sstevel@tonic-gate macinfo->llcp_iocid == iocp->ioc_id) {
6830Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
6840Sstevel@tonic-gate /* we can use this form */
6850Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_USING_RAW;
6860Sstevel@tonic-gate freemsg(mp);
6870Sstevel@tonic-gate break;
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate /* need to find the correct queue */
6900Sstevel@tonic-gate freemsg(mp);
6910Sstevel@tonic-gate break;
6920Sstevel@tonic-gate case M_IOCNAK:
6930Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
6940Sstevel@tonic-gate if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
6950Sstevel@tonic-gate macinfo->llcp_iocid == iocp->ioc_id) {
6960Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
6970Sstevel@tonic-gate freemsg(mp);
6980Sstevel@tonic-gate break;
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate /* need to find the correct queue */
7010Sstevel@tonic-gate freemsg(mp);
7020Sstevel@tonic-gate break;
7030Sstevel@tonic-gate case M_DATA:
7040Sstevel@tonic-gate llc1_recv(macinfo, mp);
7050Sstevel@tonic-gate break;
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate return (0);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate * llc1_uwsrv - Incoming messages are processed according to the DLPI
7130Sstevel@tonic-gate * protocol specification
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate static int
llc1_uwsrv(queue_t * q)7170Sstevel@tonic-gate llc1_uwsrv(queue_t *q)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate mblk_t *mp;
7200Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr;
7210Sstevel@tonic-gate union DL_primitives *prim;
7220Sstevel@tonic-gate int err;
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate #ifdef LLC1_DEBUG
7250Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
7260Sstevel@tonic-gate printf("llc1_wsrv(%x)\n", q);
7270Sstevel@tonic-gate #endif
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
7310Sstevel@tonic-gate switch (mp->b_datap->db_type) {
7320Sstevel@tonic-gate case M_PROTO: /* Will be an DLPI message of some type */
7330Sstevel@tonic-gate case M_PCPROTO:
7340Sstevel@tonic-gate if ((err = llc1_cmds(q, mp)) != LLCE_OK) {
7350Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr;
7360Sstevel@tonic-gate if (err == LLCE_NOBUFFER || err == DL_SYSERR) {
7370Sstevel@tonic-gate /* quit while we're ahead */
7380Sstevel@tonic-gate lld->llc_stats->llcs_nobuffer++;
7390Sstevel@tonic-gate #ifdef LLC1_DEBUG
7400Sstevel@tonic-gate if (llc1_debug & LLCERRS)
7410Sstevel@tonic-gate printf(
7420Sstevel@tonic-gate "llc1_cmds: nonfatal err=%d\n",
743*7656SSherry.Moore@Sun.COM err);
7440Sstevel@tonic-gate #endif
7450Sstevel@tonic-gate (void) putbq(q, mp);
7460Sstevel@tonic-gate return (0);
7470Sstevel@tonic-gate
7480Sstevel@tonic-gate } else {
7490Sstevel@tonic-gate dlerrorack(q, mp,
750*7656SSherry.Moore@Sun.COM prim->dl_primitive,
751*7656SSherry.Moore@Sun.COM err, 0);
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate break;
7550Sstevel@tonic-gate case M_DATA:
7560Sstevel@tonic-gate /*
7570Sstevel@tonic-gate * retry of a previously processed
7580Sstevel@tonic-gate * UNITDATA_REQ or is a RAW message from
7590Sstevel@tonic-gate * above
7600Sstevel@tonic-gate */
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate mutex_enter(&lld->llc_lock);
7630Sstevel@tonic-gate putnext(lld->llc_mac_info->llcp_queue, mp);
7640Sstevel@tonic-gate mutex_exit(&lld->llc_lock);
7650Sstevel@tonic-gate freemsg(mp); /* free on success */
7660Sstevel@tonic-gate break;
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate /* This should never happen */
7690Sstevel@tonic-gate default:
7700Sstevel@tonic-gate #ifdef LLC1_DEBUG
7710Sstevel@tonic-gate if (llc1_debug & LLCERRS)
7720Sstevel@tonic-gate printf("llc1_wsrv: type(%x) not supported\n",
773*7656SSherry.Moore@Sun.COM mp->b_datap->db_type);
7740Sstevel@tonic-gate #endif
7750Sstevel@tonic-gate freemsg(mp); /* unknown types are discarded */
7760Sstevel@tonic-gate break;
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate return (0);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate * llc1_multicast used to determine if the address is a multicast address for
7840Sstevel@tonic-gate * this user.
7850Sstevel@tonic-gate */
7860Sstevel@tonic-gate int
llc1_multicast(struct ether_addr * addr,llc1_t * lld)7870Sstevel@tonic-gate llc1_multicast(struct ether_addr *addr, llc1_t *lld)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate int i;
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate if (lld->llc_mcast)
7920Sstevel@tonic-gate for (i = 0; i < lld->llc_multicnt; i++)
7930Sstevel@tonic-gate if (lld->llc_mcast[i] &&
7940Sstevel@tonic-gate lld->llc_mcast[i]->llcm_refcnt &&
7950Sstevel@tonic-gate bcmp(lld->llc_mcast[i]->llcm_addr,
7960Sstevel@tonic-gate addr->ether_addr_octet, ETHERADDRL) == 0)
7970Sstevel@tonic-gate return (1);
7980Sstevel@tonic-gate return (0);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate * llc1_ioctl handles all ioctl requests passed downstream. This routine is
8030Sstevel@tonic-gate * passed a pointer to the message block with the ioctl request in it, and a
8040Sstevel@tonic-gate * pointer to the queue so it can respond to the ioctl request with an ack.
8050Sstevel@tonic-gate */
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate int llc1_doreqinfo;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate static void
llc1_ioctl(queue_t * q,mblk_t * mp)8100Sstevel@tonic-gate llc1_ioctl(queue_t *q, mblk_t *mp)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate struct iocblk *iocp;
8130Sstevel@tonic-gate llc1_t *lld;
8140Sstevel@tonic-gate struct linkblk *link;
8150Sstevel@tonic-gate llc_mac_info_t *macinfo;
8160Sstevel@tonic-gate mblk_t *tmp;
8170Sstevel@tonic-gate int error;
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate #ifdef LLC1_DEBUG
8200Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
8210Sstevel@tonic-gate printf("llc1_ioctl(%x %x)\n", q, mp);
8220Sstevel@tonic-gate #endif
8230Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr;
8240Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
8250Sstevel@tonic-gate switch (iocp->ioc_cmd) {
8260Sstevel@tonic-gate /* XXX need to lock the data structures */
8270Sstevel@tonic-gate case I_PLINK:
8280Sstevel@tonic-gate case I_LINK:
8290Sstevel@tonic-gate link = (struct linkblk *)mp->b_cont->b_rptr;
8300Sstevel@tonic-gate tmp = allocb(sizeof (llc_mac_info_t), BPRI_MED);
8310Sstevel@tonic-gate if (tmp == NULL) {
8320Sstevel@tonic-gate (void) miocnak(q, mp, 0, ENOSR);
8330Sstevel@tonic-gate return;
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate bzero(tmp->b_rptr, sizeof (llc_mac_info_t));
8360Sstevel@tonic-gate macinfo = (llc_mac_info_t *)tmp->b_rptr;
8370Sstevel@tonic-gate macinfo->llcp_mb = tmp;
8380Sstevel@tonic-gate macinfo->llcp_next = macinfo->llcp_prev = macinfo;
8390Sstevel@tonic-gate macinfo->llcp_queue = link->l_qbot;
8400Sstevel@tonic-gate macinfo->llcp_lindex = link->l_index;
8410Sstevel@tonic-gate /* tentative */
8420Sstevel@tonic-gate macinfo->llcp_ppa = --llc1_device_list.llc1_nextppa;
8430Sstevel@tonic-gate llc1_device_list.llc1_ndevice++;
8440Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_LINKED | LLC1_DEF_PPA;
8450Sstevel@tonic-gate macinfo->llcp_lqtop = q;
8460Sstevel@tonic-gate macinfo->llcp_data = NULL;
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate /* need to do an info_req before an info_req or attach */
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
8510Sstevel@tonic-gate llc1insque(macinfo, llc1_device_list.llc1_mac_prev);
8520Sstevel@tonic-gate macinfo->llcp_queue->q_ptr = RD(macinfo->llcp_queue)->q_ptr =
853*7656SSherry.Moore@Sun.COM (caddr_t)macinfo;
8540Sstevel@tonic-gate llc1_init_kstat(macinfo);
8550Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate /* initiate getting the info */
8580Sstevel@tonic-gate (void) llc1_req_info(macinfo->llcp_queue);
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate miocack(q, mp, 0, 0);
8610Sstevel@tonic-gate return;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate case I_PUNLINK:
8640Sstevel@tonic-gate case I_UNLINK:
8650Sstevel@tonic-gate link = (struct linkblk *)mp->b_cont->b_rptr;
8660Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
8670Sstevel@tonic-gate for (macinfo = llc1_device_list.llc1_mac_next;
8680Sstevel@tonic-gate macinfo != NULL &&
8690Sstevel@tonic-gate macinfo !=
870*7656SSherry.Moore@Sun.COM (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
8710Sstevel@tonic-gate macinfo = macinfo->llcp_next) {
8720Sstevel@tonic-gate if (macinfo->llcp_lindex == link->l_index &&
8730Sstevel@tonic-gate macinfo->llcp_queue == link->l_qbot) {
8740Sstevel@tonic-gate /* found it */
8750Sstevel@tonic-gate
876*7656SSherry.Moore@Sun.COM ASSERT(macinfo->llcp_next);
8770Sstevel@tonic-gate
8780Sstevel@tonic-gate /* remove from device list */
879*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_ndevice--;
880*7656SSherry.Moore@Sun.COM llc1remque(macinfo);
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate /* remove any mcast structs */
883*7656SSherry.Moore@Sun.COM if (macinfo->llcp_mcast != NULL) {
8840Sstevel@tonic-gate kmem_free(macinfo->llcp_mcast,
8850Sstevel@tonic-gate sizeof (llc_mcast_t) *
886*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_multisize);
8870Sstevel@tonic-gate macinfo->llcp_mcast = NULL;
888*7656SSherry.Moore@Sun.COM }
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /* remove any kstat counters */
891*7656SSherry.Moore@Sun.COM if (macinfo->llcp_kstatp != NULL)
8920Sstevel@tonic-gate llc1_uninit_kstat(macinfo);
893*7656SSherry.Moore@Sun.COM if (macinfo->llcp_mb != NULL)
8940Sstevel@tonic-gate freeb(macinfo->llcp_mb);
8950Sstevel@tonic-gate
896*7656SSherry.Moore@Sun.COM lld->llc_mac_info = NULL;
897*7656SSherry.Moore@Sun.COM
898*7656SSherry.Moore@Sun.COM miocack(q, mp, 0, 0);
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate /* finish any necessary setup */
901*7656SSherry.Moore@Sun.COM if (llc1_device_list.llc1_ndevice == 0)
9020Sstevel@tonic-gate llc1_device_list.llc1_nextppa = 0;
9030Sstevel@tonic-gate
904*7656SSherry.Moore@Sun.COM rw_exit(&llc1_device_list.llc1_rwlock);
905*7656SSherry.Moore@Sun.COM return;
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * what should really be done here -- force errors on all
9110Sstevel@tonic-gate * streams?
9120Sstevel@tonic-gate */
9130Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
9140Sstevel@tonic-gate return;
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate case L_SETPPA:
9170Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ll_snioc));
9180Sstevel@tonic-gate if (error != 0) {
9190Sstevel@tonic-gate miocnak(q, mp, 0, error);
9200Sstevel@tonic-gate return;
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate if (llc1_setppa((struct ll_snioc *)mp->b_cont->b_rptr) >= 0) {
9240Sstevel@tonic-gate miocack(q, mp, 0, 0);
9250Sstevel@tonic-gate return;
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
9280Sstevel@tonic-gate return;
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate case L_GETPPA:
9310Sstevel@tonic-gate if (mp->b_cont == NULL) {
9320Sstevel@tonic-gate mp->b_cont = allocb(sizeof (struct ll_snioc), BPRI_MED);
9330Sstevel@tonic-gate if (mp->b_cont == NULL) {
9340Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR);
9350Sstevel@tonic-gate return;
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate mp->b_cont->b_wptr =
938*7656SSherry.Moore@Sun.COM mp->b_cont->b_rptr + sizeof (struct ll_snioc);
9390Sstevel@tonic-gate } else {
9400Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ll_snioc));
9410Sstevel@tonic-gate if (error != 0) {
9420Sstevel@tonic-gate miocnak(q, mp, 0, error);
9430Sstevel@tonic-gate return;
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr;
9480Sstevel@tonic-gate if (llc1_getppa(lld->llc_mac_info,
9490Sstevel@tonic-gate (struct ll_snioc *)mp->b_cont->b_rptr) >= 0)
9500Sstevel@tonic-gate miocack(q, mp, 0, 0);
9510Sstevel@tonic-gate else
9520Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
9530Sstevel@tonic-gate return;
9540Sstevel@tonic-gate default:
9550Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate * llc1_setppa(snioc) this function sets the real PPA number for a previously
9610Sstevel@tonic-gate * I_LINKED stream. Be careful to select the macinfo struct associated
9620Sstevel@tonic-gate * with our llc struct, to avoid erroneous references.
9630Sstevel@tonic-gate */
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate static int
llc1_setppa(struct ll_snioc * snioc)9660Sstevel@tonic-gate llc1_setppa(struct ll_snioc *snioc)
9670Sstevel@tonic-gate {
9680Sstevel@tonic-gate llc_mac_info_t *macinfo;
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate for (macinfo = llc1_device_list.llc1_mac_next;
971*7656SSherry.Moore@Sun.COM macinfo != (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
972*7656SSherry.Moore@Sun.COM macinfo = macinfo->llcp_next)
9730Sstevel@tonic-gate if (macinfo->llcp_lindex == snioc->lli_index &&
9740Sstevel@tonic-gate (macinfo->llcp_flags & LLC1_DEF_PPA)) {
9750Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_DEF_PPA;
9760Sstevel@tonic-gate macinfo->llcp_ppa = snioc->lli_ppa;
9770Sstevel@tonic-gate return (0);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate return (-1);
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate /*
9830Sstevel@tonic-gate * llc1_getppa(macinfo, snioc) returns the PPA for this stream
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate static int
llc1_getppa(llc_mac_info_t * macinfo,struct ll_snioc * snioc)9860Sstevel@tonic-gate llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc)
9870Sstevel@tonic-gate {
9880Sstevel@tonic-gate if (macinfo == NULL)
9890Sstevel@tonic-gate return (-1);
9900Sstevel@tonic-gate snioc->lli_ppa = macinfo->llcp_ppa;
9910Sstevel@tonic-gate snioc->lli_index = macinfo->llcp_lindex;
9920Sstevel@tonic-gate return (0);
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate /*
9960Sstevel@tonic-gate * llc1_cmds - process the DL commands as defined in dlpi.h
9970Sstevel@tonic-gate */
9980Sstevel@tonic-gate static int
llc1_cmds(queue_t * q,mblk_t * mp)9990Sstevel@tonic-gate llc1_cmds(queue_t *q, mblk_t *mp)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate union DL_primitives *dlp;
10020Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr;
10030Sstevel@tonic-gate int result = 0;
10040Sstevel@tonic-gate llc_mac_info_t *macinfo = llc->llc_mac_info;
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
10070Sstevel@tonic-gate #ifdef LLC1_DEBUG
10080Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
10090Sstevel@tonic-gate printf("llc1_cmds(%x, %x):dlp=%x, dlp->dl_primitive=%d\n",
1010*7656SSherry.Moore@Sun.COM q, mp, dlp, dlp->dl_primitive);
10110Sstevel@tonic-gate #endif
10120Sstevel@tonic-gate mutex_enter(&llc->llc_lock);
10130Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_READER);
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate switch (dlp->dl_primitive) {
10160Sstevel@tonic-gate case DL_BIND_REQ:
10170Sstevel@tonic-gate result = llc1_bind(q, mp);
10180Sstevel@tonic-gate break;
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate case DL_UNBIND_REQ:
10210Sstevel@tonic-gate result = llc1_unbind(q, mp);
10220Sstevel@tonic-gate break;
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate case DL_SUBS_BIND_REQ:
10250Sstevel@tonic-gate result = llc1_subs_bind(q, mp);
10260Sstevel@tonic-gate break;
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate case DL_SUBS_UNBIND_REQ:
10290Sstevel@tonic-gate result = llc1_subs_unbind();
10300Sstevel@tonic-gate break;
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate case DL_UNITDATA_REQ:
10330Sstevel@tonic-gate result = llc1_unitdata(q, mp);
10340Sstevel@tonic-gate break;
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate case DL_INFO_REQ:
10370Sstevel@tonic-gate result = llc1_inforeq(q, mp);
10380Sstevel@tonic-gate break;
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate case DL_ATTACH_REQ:
10410Sstevel@tonic-gate result = llc1attach(q, mp);
10420Sstevel@tonic-gate break;
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate case DL_DETACH_REQ:
10450Sstevel@tonic-gate result = llc1unattach(q, mp);
10460Sstevel@tonic-gate break;
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate case DL_ENABMULTI_REQ:
10490Sstevel@tonic-gate result = llc1_enable_multi(q, mp);
10500Sstevel@tonic-gate break;
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate case DL_DISABMULTI_REQ:
10530Sstevel@tonic-gate result = llc1_disable_multi(q, mp);
10540Sstevel@tonic-gate break;
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate case DL_XID_REQ:
10570Sstevel@tonic-gate result = llc1_xid_req_res(q, mp, 0);
10580Sstevel@tonic-gate break;
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate case DL_XID_RES:
10610Sstevel@tonic-gate result = llc1_xid_req_res(q, mp, 1);
10620Sstevel@tonic-gate break;
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate case DL_TEST_REQ:
10650Sstevel@tonic-gate result = llc1_test_req_res(q, mp, 0);
10660Sstevel@tonic-gate break;
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate case DL_TEST_RES:
10690Sstevel@tonic-gate result = llc1_test_req_res(q, mp, 1);
10700Sstevel@tonic-gate break;
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate case DL_SET_PHYS_ADDR_REQ:
10730Sstevel@tonic-gate result = DL_NOTSUPPORTED;
10740Sstevel@tonic-gate break;
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate case DL_PHYS_ADDR_REQ:
10770Sstevel@tonic-gate if (llc->llc_state != DL_UNATTACHED && macinfo) {
10780Sstevel@tonic-gate llc->llc_waiting_for = dlp->dl_primitive;
10790Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), mp);
10800Sstevel@tonic-gate result = LLCE_OK;
10810Sstevel@tonic-gate } else {
10820Sstevel@tonic-gate result = DL_OUTSTATE;
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate break;
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate case DL_PROMISCON_REQ:
10870Sstevel@tonic-gate case DL_PROMISCOFF_REQ:
10880Sstevel@tonic-gate result = DL_NOTSUPPORTED;
10890Sstevel@tonic-gate break;
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate default:
10920Sstevel@tonic-gate #ifdef LLC1_DEBUG
10930Sstevel@tonic-gate if (llc1_debug & LLCERRS)
10940Sstevel@tonic-gate printf("llc1_cmds: Received unknown primitive: %d\n",
1095*7656SSherry.Moore@Sun.COM dlp->dl_primitive);
10960Sstevel@tonic-gate #endif
10970Sstevel@tonic-gate result = DL_BADPRIM;
10980Sstevel@tonic-gate break;
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
11010Sstevel@tonic-gate mutex_exit(&llc->llc_lock);
11020Sstevel@tonic-gate return (result);
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate /*
11060Sstevel@tonic-gate * llc1_bind - determine if a SAP is already allocated and whether it is
11070Sstevel@tonic-gate * legal to do the bind at this time
11080Sstevel@tonic-gate */
11090Sstevel@tonic-gate static int
llc1_bind(queue_t * q,mblk_t * mp)11100Sstevel@tonic-gate llc1_bind(queue_t *q, mblk_t *mp)
11110Sstevel@tonic-gate {
11120Sstevel@tonic-gate int sap;
11130Sstevel@tonic-gate dl_bind_req_t *dlp;
11140Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr;
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate ASSERT(lld);
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate #ifdef LLC1_DEBUG
11190Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
11200Sstevel@tonic-gate printf("llc1_bind(%x %x)\n", q, mp);
11210Sstevel@tonic-gate #endif
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate dlp = (dl_bind_req_t *)mp->b_rptr;
11240Sstevel@tonic-gate sap = dlp->dl_sap;
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate #ifdef LLC1_DEBUG
11270Sstevel@tonic-gate if (llc1_debug & LLCPROT)
11280Sstevel@tonic-gate printf("llc1_bind: lsap=%x\n", sap);
11290Sstevel@tonic-gate #endif
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate if (lld->llc_mac_info == NULL)
11320Sstevel@tonic-gate return (DL_OUTSTATE);
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate if (lld->llc_qptr && lld->llc_state != DL_UNBOUND) {
11350Sstevel@tonic-gate #ifdef LLC1_DEBUG
11360Sstevel@tonic-gate if (llc1_debug & LLCERRS)
11370Sstevel@tonic-gate printf("llc1_bind: stream bound/not attached (%d)\n",
1138*7656SSherry.Moore@Sun.COM lld->llc_state);
11390Sstevel@tonic-gate #endif
11400Sstevel@tonic-gate return (DL_OUTSTATE);
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate if (dlp->dl_service_mode != DL_CLDLS || dlp->dl_max_conind != 0) {
11440Sstevel@tonic-gate return (DL_UNSUPPORTED);
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate * prohibit group saps. An exception is the broadcast sap which is,
11480Sstevel@tonic-gate * unfortunately, used by SUNSelect to indicate Novell Netware in
11490Sstevel@tonic-gate * 802.3 mode. Really should use a very non-802.2 SAP like 0xFFFF
11500Sstevel@tonic-gate * or -2.
11510Sstevel@tonic-gate */
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate if (sap == 0 || (sap <= 0xFF && (sap & 1 && sap != 0xFF)) ||
11540Sstevel@tonic-gate sap > 0xFFFF) {
11550Sstevel@tonic-gate return (DL_BADSAP);
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate lld->llc_state = DL_BIND_PENDING;
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate /* if we fall through, then the SAP is legal */
11600Sstevel@tonic-gate if (sap == 0xFF) {
11610Sstevel@tonic-gate if (lld->llc_mac_info->llcp_type == DL_CSMACD)
11620Sstevel@tonic-gate sap = LLC_NOVELL_SAP;
11630Sstevel@tonic-gate else
11640Sstevel@tonic-gate return (DL_BADSAP);
11650Sstevel@tonic-gate }
11660Sstevel@tonic-gate lld->llc_sap = sap;
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate if (sap > 0xFF) {
11690Sstevel@tonic-gate ushort_t snapsap = htons(sap);
11700Sstevel@tonic-gate /* this is SNAP, so set things up */
11710Sstevel@tonic-gate lld->llc_snap[3] = ((uchar_t *)&snapsap)[0];
11720Sstevel@tonic-gate lld->llc_snap[4] = ((uchar_t *)&snapsap)[1];
11730Sstevel@tonic-gate /* mark as SNAP but allow OID to be added later */
11740Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP;
11750Sstevel@tonic-gate lld->llc_sap = LLC_SNAP_SAP;
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate #ifdef LLC1_DEBUG
11790Sstevel@tonic-gate if (llc1_debug & LLCPROT)
11800Sstevel@tonic-gate printf("llc1_bind: ok - type = %d\n", lld->llc_type);
11810Sstevel@tonic-gate #endif
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate if (dlp->dl_xidtest_flg & DL_AUTO_XID)
11840Sstevel@tonic-gate lld->llc_flags |= LLC1_AUTO_XID;
11850Sstevel@tonic-gate if (dlp->dl_xidtest_flg & DL_AUTO_TEST)
11860Sstevel@tonic-gate lld->llc_flags |= LLC1_AUTO_TEST;
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate /* ACK the BIND, if possible */
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate dlbindack(q, mp, sap, lld->llc_mac_info->llcp_macaddr, 6, 0, 0);
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate lld->llc_state = DL_IDLE; /* bound and ready */
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate return (LLCE_OK);
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate /*
11980Sstevel@tonic-gate * llc1_unbind - perform an unbind of an LSAP or ether type on the stream.
11990Sstevel@tonic-gate * The stream is still open and can be re-bound.
12000Sstevel@tonic-gate */
12010Sstevel@tonic-gate static int
llc1_unbind(queue_t * q,mblk_t * mp)12020Sstevel@tonic-gate llc1_unbind(queue_t *q, mblk_t *mp)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate llc1_t *lld;
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate #ifdef LLC1_DEBUG
12070Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
12080Sstevel@tonic-gate printf("llc1_unbind(%x %x)\n", q, mp);
12090Sstevel@tonic-gate #endif
12100Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr;
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate if (lld->llc_mac_info == NULL)
12130Sstevel@tonic-gate return (DL_OUTSTATE);
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if (lld->llc_state != DL_IDLE) {
12160Sstevel@tonic-gate #ifdef LLC1_DEBUG
12170Sstevel@tonic-gate if (llc1_debug & LLCERRS)
12180Sstevel@tonic-gate printf("llc1_unbind: wrong state (%d)\n",
1219*7656SSherry.Moore@Sun.COM lld->llc_state);
12200Sstevel@tonic-gate #endif
12210Sstevel@tonic-gate return (DL_OUTSTATE);
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate lld->llc_state = DL_UNBIND_PENDING;
12240Sstevel@tonic-gate lld->llc_flags &= ~(LLC_SNAP|LLC_SNAP_OID); /* just in case */
12250Sstevel@tonic-gate dlokack(q, mp, DL_UNBIND_REQ);
12260Sstevel@tonic-gate lld->llc_state = DL_UNBOUND;
12270Sstevel@tonic-gate return (LLCE_OK);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate * llc1_inforeq - generate the response to an info request
12320Sstevel@tonic-gate */
12330Sstevel@tonic-gate static int
llc1_inforeq(queue_t * q,mblk_t * mp)12340Sstevel@tonic-gate llc1_inforeq(queue_t *q, mblk_t *mp)
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate llc1_t *lld;
12370Sstevel@tonic-gate mblk_t *nmp;
12380Sstevel@tonic-gate dl_info_ack_t *dlp;
12390Sstevel@tonic-gate int bufsize;
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate #ifdef LLC1_DEBUG
12420Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
12430Sstevel@tonic-gate printf("llc1_inforeq(%x %x)\n", q, mp);
12440Sstevel@tonic-gate #endif
12450Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr;
12460Sstevel@tonic-gate ASSERT(lld);
12470Sstevel@tonic-gate if (lld->llc_mac_info == NULL)
12480Sstevel@tonic-gate bufsize = sizeof (dl_info_ack_t) + ETHERADDRL;
12490Sstevel@tonic-gate else
12500Sstevel@tonic-gate bufsize = sizeof (dl_info_ack_t) +
1251*7656SSherry.Moore@Sun.COM 2 * lld->llc_mac_info->llcp_addrlen + 2;
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate nmp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK);
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate if (nmp) {
12560Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_info_ack_t);
12570Sstevel@tonic-gate dlp = (dl_info_ack_t *)nmp->b_rptr;
12580Sstevel@tonic-gate bzero(dlp, DL_INFO_ACK_SIZE);
12590Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK;
12600Sstevel@tonic-gate if (lld->llc_mac_info)
12610Sstevel@tonic-gate dlp->dl_max_sdu = lld->llc_mac_info->llcp_maxpkt;
12620Sstevel@tonic-gate dlp->dl_min_sdu = 0;
12630Sstevel@tonic-gate dlp->dl_mac_type = lld->llc_type;
12640Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS;
12650Sstevel@tonic-gate dlp->dl_current_state = lld->llc_state;
12660Sstevel@tonic-gate dlp->dl_provider_style =
1267*7656SSherry.Moore@Sun.COM (lld->llc_style == 0) ? lld->llc_style : DL_STYLE2;
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate /* now append physical address */
12700Sstevel@tonic-gate if (lld->llc_mac_info) {
12710Sstevel@tonic-gate dlp->dl_addr_length = lld->llc_mac_info->llcp_addrlen;
12720Sstevel@tonic-gate dlp->dl_addr_offset = DL_INFO_ACK_SIZE;
12730Sstevel@tonic-gate nmp->b_wptr += dlp->dl_addr_length + 1;
12740Sstevel@tonic-gate bcopy(lld->llc_mac_info->llcp_macaddr,
1275*7656SSherry.Moore@Sun.COM ((caddr_t)dlp) + dlp->dl_addr_offset,
1276*7656SSherry.Moore@Sun.COM lld->llc_mac_info->llcp_addrlen);
12770Sstevel@tonic-gate if (lld->llc_state == DL_IDLE) {
12780Sstevel@tonic-gate dlp->dl_sap_length = -1; /* 1 byte on end */
12790Sstevel@tonic-gate *(((caddr_t)dlp) + dlp->dl_addr_offset +
1280*7656SSherry.Moore@Sun.COM dlp->dl_addr_length) = lld->llc_sap;
12810Sstevel@tonic-gate dlp->dl_addr_length += 1;
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate /* and the broadcast address */
12840Sstevel@tonic-gate dlp->dl_brdcst_addr_length =
1285*7656SSherry.Moore@Sun.COM lld->llc_mac_info->llcp_addrlen;
12860Sstevel@tonic-gate dlp->dl_brdcst_addr_offset =
1287*7656SSherry.Moore@Sun.COM dlp->dl_addr_offset + dlp->dl_addr_length;
12880Sstevel@tonic-gate nmp->b_wptr += dlp->dl_brdcst_addr_length;
12890Sstevel@tonic-gate bcopy(lld->llc_mac_info->llcp_broadcast,
12900Sstevel@tonic-gate ((caddr_t)dlp) + dlp->dl_brdcst_addr_offset,
12910Sstevel@tonic-gate lld->llc_mac_info->llcp_addrlen);
12920Sstevel@tonic-gate } else {
12930Sstevel@tonic-gate dlp->dl_addr_length = 0; /* not attached yet */
12940Sstevel@tonic-gate dlp->dl_addr_offset = NULL;
12950Sstevel@tonic-gate dlp->dl_sap_length = 0; /* 1 bytes on end */
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate dlp->dl_version = DL_VERSION_2;
12980Sstevel@tonic-gate qreply(q, nmp);
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate return (LLCE_OK);
13010Sstevel@tonic-gate }
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate /*
13040Sstevel@tonic-gate * llc1_unitdata
13050Sstevel@tonic-gate * send a datagram. Destination address/lsap is in M_PROTO
13060Sstevel@tonic-gate * message (first mblock), data is in remainder of message.
13070Sstevel@tonic-gate *
13080Sstevel@tonic-gate * NOTE: We are reusing the DL_unitdata_req mblock; if llc header gets any
13090Sstevel@tonic-gate * bigger, recheck to make sure it still fits! We assume that we have a
13100Sstevel@tonic-gate * 64-byte dblock for this, since a DL_unitdata_req is 20 bytes and the next
13110Sstevel@tonic-gate * larger dblock size is 64.
13120Sstevel@tonic-gate */
13130Sstevel@tonic-gate static int
llc1_unitdata(queue_t * q,mblk_t * mp)13140Sstevel@tonic-gate llc1_unitdata(queue_t *q, mblk_t *mp)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr;
13170Sstevel@tonic-gate dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
13180Sstevel@tonic-gate struct ether_header *hdr;
13190Sstevel@tonic-gate struct llcaddr *llcp;
13200Sstevel@tonic-gate mblk_t *nmp;
13210Sstevel@tonic-gate long msglen;
13220Sstevel@tonic-gate struct llchdr *llchdr;
13230Sstevel@tonic-gate llc_mac_info_t *macinfo;
13240Sstevel@tonic-gate int xmt_type = 0;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate #ifdef LLC1_DEBUG
13270Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
13280Sstevel@tonic-gate printf("llc1_unitdata(%x %x)\n", q, mp);
13290Sstevel@tonic-gate #endif
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate if ((macinfo = lld->llc_mac_info) == NULL)
13320Sstevel@tonic-gate return (DL_OUTSTATE);
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate if (lld->llc_state != DL_IDLE) {
13350Sstevel@tonic-gate #ifdef LLC1_DEBUG
13360Sstevel@tonic-gate if (llc1_debug & LLCERRS)
13370Sstevel@tonic-gate printf("llc1_unitdata: wrong state (%d)\n",
1338*7656SSherry.Moore@Sun.COM lld->llc_state);
13390Sstevel@tonic-gate #endif
13400Sstevel@tonic-gate return (DL_OUTSTATE);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate /* need the destination address in all cases */
13440Sstevel@tonic-gate llcp = (struct llcaddr *)((caddr_t)dlp + dlp->dl_dest_addr_offset);
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) {
13470Sstevel@tonic-gate /*
13480Sstevel@tonic-gate * make a valid header for transmission
13490Sstevel@tonic-gate */
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate /* need a buffer big enough for the headers */
1352*7656SSherry.Moore@Sun.COM nmp = allocb(macinfo->llcp_addrlen * 2 + 2 + 8, BPRI_MED);
1353*7656SSherry.Moore@Sun.COM hdr = (struct ether_header *)nmp->b_rptr;
1354*7656SSherry.Moore@Sun.COM msglen = msgdsize(mp);
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate /* fill in type dependent fields */
1357*7656SSherry.Moore@Sun.COM switch (lld->llc_type) {
1358*7656SSherry.Moore@Sun.COM case DL_CSMACD: /* 802.3 CSMA/CD */
13590Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + LLC1_CSMACD_HDR_SIZE;
13600Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_wptr;
13610Sstevel@tonic-gate bcopy(llcp->llca_addr,
13620Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet,
13630Sstevel@tonic-gate ETHERADDRL);
13640Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr,
13650Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet,
13660Sstevel@tonic-gate ETHERADDRL);
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate if (lld->llc_sap != LLC_NOVELL_SAP) {
13690Sstevel@tonic-gate /* set length with llc header size */
13700Sstevel@tonic-gate hdr->ether_type = ntohs(msglen +
1371*7656SSherry.Moore@Sun.COM sizeof (struct llchdr));
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate /* need an LLC header, otherwise is Novell */
13740Sstevel@tonic-gate /* bound sap is always source */
13750Sstevel@tonic-gate llchdr->llc_ssap = lld->llc_sap;
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate /* destination sap */
13780Sstevel@tonic-gate llchdr->llc_dsap = llcp->llca_sap;
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /* always Unnumbered Information */
13810Sstevel@tonic-gate llchdr->llc_ctl = LLC_UI;
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr);
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) {
13860Sstevel@tonic-gate bcopy(lld->llc_snap, nmp->b_wptr, 5);
13870Sstevel@tonic-gate llchdr->llc_dsap = LLC_SNAP_SAP;
13880Sstevel@tonic-gate nmp->b_wptr += 5;
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate } else {
13910Sstevel@tonic-gate /* set length without llc header size */
13920Sstevel@tonic-gate hdr->ether_type = ntohs(msglen);
13930Sstevel@tonic-gate
13940Sstevel@tonic-gate /* we don't do anything else for Netware */
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate if (ismulticast(hdr->ether_dhost.ether_addr_octet)) {
13980Sstevel@tonic-gate if (bcmp(hdr->ether_dhost.ether_addr_octet,
13990Sstevel@tonic-gate macinfo->llcp_broadcast, ETHERADDRL) == 0)
14000Sstevel@tonic-gate xmt_type = 2;
14010Sstevel@tonic-gate else
14020Sstevel@tonic-gate xmt_type = 1;
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate break;
14060Sstevel@tonic-gate
1407*7656SSherry.Moore@Sun.COM default: /* either RAW or unknown, send as is */
14080Sstevel@tonic-gate break;
1409*7656SSherry.Moore@Sun.COM }
1410*7656SSherry.Moore@Sun.COM DB_TYPE(nmp) = M_DATA; /* ether/llc header is data */
1411*7656SSherry.Moore@Sun.COM nmp->b_cont = mp->b_cont; /* use the data given */
1412*7656SSherry.Moore@Sun.COM freeb(mp);
1413*7656SSherry.Moore@Sun.COM mp = nmp;
14140Sstevel@tonic-gate } else {
14150Sstevel@tonic-gate /* need to format a DL_UNITDATA_REQ with LLC1 header inserted */
1416*7656SSherry.Moore@Sun.COM nmp = allocb(sizeof (struct llchdr)+sizeof (struct snaphdr),
1417*7656SSherry.Moore@Sun.COM BPRI_MED);
1418*7656SSherry.Moore@Sun.COM if (nmp == NULL)
14190Sstevel@tonic-gate return (DL_UNDELIVERABLE);
1420*7656SSherry.Moore@Sun.COM llchdr = (struct llchdr *)(nmp->b_rptr);
1421*7656SSherry.Moore@Sun.COM nmp->b_wptr += sizeof (struct llchdr);
1422*7656SSherry.Moore@Sun.COM llchdr->llc_dsap = llcp->llca_sap;
1423*7656SSherry.Moore@Sun.COM llchdr->llc_ssap = lld->llc_sap;
1424*7656SSherry.Moore@Sun.COM llchdr->llc_ctl = LLC_UI;
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate /*
14270Sstevel@tonic-gate * if we are using SNAP, insert the header here
14280Sstevel@tonic-gate */
1429*7656SSherry.Moore@Sun.COM if (lld->llc_flags & LLC_SNAP) {
1430*7656SSherry.Moore@Sun.COM bcopy(lld->llc_snap, nmp->b_wptr, 5);
1431*7656SSherry.Moore@Sun.COM nmp->b_wptr += 5;
1432*7656SSherry.Moore@Sun.COM }
1433*7656SSherry.Moore@Sun.COM nmp->b_cont = mp->b_cont;
1434*7656SSherry.Moore@Sun.COM mp->b_cont = nmp;
1435*7656SSherry.Moore@Sun.COM nmp = mp;
1436*7656SSherry.Moore@Sun.COM if (ismulticast(llcp->llca_addr)) {
1437*7656SSherry.Moore@Sun.COM if (bcmp(llcp->llca_addr,
1438*7656SSherry.Moore@Sun.COM macinfo->llcp_broadcast, ETHERADDRL) == 0)
1439*7656SSherry.Moore@Sun.COM xmt_type = 2;
1440*7656SSherry.Moore@Sun.COM else
1441*7656SSherry.Moore@Sun.COM xmt_type = 1;
1442*7656SSherry.Moore@Sun.COM }
14430Sstevel@tonic-gate }
14440Sstevel@tonic-gate if (canput(macinfo->llcp_queue)) {
14450Sstevel@tonic-gate lld->llc_stats->llcs_bytexmt += msgdsize(mp);
14460Sstevel@tonic-gate lld->llc_stats->llcs_pktxmt++;
14470Sstevel@tonic-gate switch (xmt_type) {
14480Sstevel@tonic-gate case 1:
14490Sstevel@tonic-gate macinfo->llcp_stats.llcs_multixmt++;
14500Sstevel@tonic-gate break;
14510Sstevel@tonic-gate case 2:
14520Sstevel@tonic-gate macinfo->llcp_stats.llcs_brdcstxmt++;
14530Sstevel@tonic-gate break;
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp);
14570Sstevel@tonic-gate return (LLCE_OK); /* this is almost correct, the result */
14580Sstevel@tonic-gate } else {
14590Sstevel@tonic-gate lld->llc_stats->llcs_nobuffer++;
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate if (nmp != NULL)
14620Sstevel@tonic-gate freemsg(nmp); /* free on failure */
14630Sstevel@tonic-gate return (LLCE_OK);
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate
14660Sstevel@tonic-gate /*
14670Sstevel@tonic-gate * llc1_recv(macinfo, mp)
14680Sstevel@tonic-gate * called with an ethernet packet in a mblock; must decide
14690Sstevel@tonic-gate * whether packet is for us and which streams to queue it to. This routine is
14700Sstevel@tonic-gate * called with locally originated packets for loopback.
14710Sstevel@tonic-gate */
14720Sstevel@tonic-gate static void
llc1_recv(llc_mac_info_t * macinfo,mblk_t * mp)14730Sstevel@tonic-gate llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate struct ether_addr *addr;
14760Sstevel@tonic-gate llc1_t *lld;
14770Sstevel@tonic-gate mblk_t *nmp, *udmp;
14780Sstevel@tonic-gate int i, nmcast = 0, statcnt_normal = 0, statcnt_brdcst = 0;
14790Sstevel@tonic-gate int valid, msgsap;
14800Sstevel@tonic-gate struct llchdr *llchdr;
14810Sstevel@tonic-gate
14820Sstevel@tonic-gate #ifdef LLC1_DEBUG
14830Sstevel@tonic-gate if (llc1_debug & LLCTRACE)
14840Sstevel@tonic-gate printf("llc1_recv(%x, %x)\n", mp, macinfo);
14850Sstevel@tonic-gate #endif
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) {
14880Sstevel@tonic-gate dl_unitdata_ind_t *udata;
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate /* check to see if really LLC1 XXX */
14910Sstevel@tonic-gate /* also need to make sure to keep address info */
14920Sstevel@tonic-gate nmp = mp;
14930Sstevel@tonic-gate udata = (dl_unitdata_ind_t *)(nmp->b_rptr);
14940Sstevel@tonic-gate addr = (struct ether_addr *)(nmp->b_rptr +
1495*7656SSherry.Moore@Sun.COM udata->dl_dest_addr_offset);
14960Sstevel@tonic-gate llchdr = (struct llchdr *)(nmp->b_cont->b_rptr);
14970Sstevel@tonic-gate if (macinfo->llcp_type == DL_CSMACD) {
14980Sstevel@tonic-gate i = ((struct llcsaddr *)addr)->llca_ssap;
14990Sstevel@tonic-gate if (i < 60) {
15000Sstevel@tonic-gate valid = adjmsg(mp->b_cont, i - msgdsize(mp));
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate } else {
15040Sstevel@tonic-gate struct ether_header *hdr;
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate /* Note that raw mode currently assumes Ethernet */
15070Sstevel@tonic-gate nmp = NULL;
15080Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr;
15090Sstevel@tonic-gate addr = &hdr->ether_dhost;
15100Sstevel@tonic-gate llchdr = (struct llchdr *)(mp->b_rptr +
1511*7656SSherry.Moore@Sun.COM sizeof (struct ether_header));
15120Sstevel@tonic-gate i = (ushort_t)ntohs(hdr->ether_type);
15130Sstevel@tonic-gate if (i < 60) {
15140Sstevel@tonic-gate (void) adjmsg(mp, i + sizeof (struct ether_header) -
1515*7656SSherry.Moore@Sun.COM msgdsize(mp));
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate }
15180Sstevel@tonic-gate udmp = NULL;
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate msgsap = llchdr->llc_dsap;
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate #ifdef LLC1_DEBUG
15230Sstevel@tonic-gate if (llc1_debug & LLCRECV) {
15240Sstevel@tonic-gate printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr));
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate #endif
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate if (llc1_broadcast(addr, macinfo)) {
15290Sstevel@tonic-gate valid = 2; /* 2 means valid but multicast */
15300Sstevel@tonic-gate statcnt_brdcst = 1;
15310Sstevel@tonic-gate } else {
15320Sstevel@tonic-gate valid = llc1_local(addr, macinfo);
15330Sstevel@tonic-gate statcnt_normal = msgdsize(mp);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate /*
15370Sstevel@tonic-gate * Note that the NULL SAP is a special case. It is associated with
15380Sstevel@tonic-gate * the MAC layer and not the LLC layer so should be handled
15390Sstevel@tonic-gate * independently of any STREAM.
15400Sstevel@tonic-gate */
15410Sstevel@tonic-gate if (msgsap == LLC_NULL_SAP) {
15420Sstevel@tonic-gate /* only XID and TEST ever processed, UI is dropped */
15430Sstevel@tonic-gate if ((llchdr->llc_ctl & ~LLC_P) == LLC_XID)
15440Sstevel@tonic-gate mp = llc1_xid_reply(macinfo, mp, 0);
15450Sstevel@tonic-gate else if ((llchdr->llc_ctl & ~LLC_P) == LLC_TEST)
15460Sstevel@tonic-gate mp = llc1_test_reply(macinfo, mp, 0);
15470Sstevel@tonic-gate } else
15480Sstevel@tonic-gate for (lld = llc1_device_list.llc1_str_next;
1549*7656SSherry.Moore@Sun.COM lld != (llc1_t *)&llc1_device_list.llc1_str_next;
1550*7656SSherry.Moore@Sun.COM lld = lld->llc_next) {
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * is this a potentially usable SAP on the
15540Sstevel@tonic-gate * right MAC layer?
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate if (lld->llc_qptr == NULL ||
1557*7656SSherry.Moore@Sun.COM lld->llc_state != DL_IDLE ||
1558*7656SSherry.Moore@Sun.COM lld->llc_mac_info != macinfo) {
15590Sstevel@tonic-gate continue;
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate #ifdef LLC1_DEBUG
15620Sstevel@tonic-gate if (llc1_debug & LLCRECV)
15630Sstevel@tonic-gate printf(
15640Sstevel@tonic-gate "llc1_recv: type=%d, sap=%x, pkt-dsap=%x\n",
1565*7656SSherry.Moore@Sun.COM lld->llc_type, lld->llc_sap,
1566*7656SSherry.Moore@Sun.COM msgsap);
15670Sstevel@tonic-gate #endif
15680Sstevel@tonic-gate if (!valid && ismulticast(addr->ether_addr_octet) &&
1569*7656SSherry.Moore@Sun.COM lld->llc_multicnt > 0 &&
1570*7656SSherry.Moore@Sun.COM llc1_multicast(addr, lld)) {
15710Sstevel@tonic-gate valid |= 4;
15720Sstevel@tonic-gate } else if (lld->llc_flags & LLC_PROM)
15730Sstevel@tonic-gate /* promiscuous mode */
15740Sstevel@tonic-gate valid = 1;
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate if ((lld->llc_flags & LLC_PROM) ||
15770Sstevel@tonic-gate /* promiscuous streams */
1578*7656SSherry.Moore@Sun.COM (valid &&
1579*7656SSherry.Moore@Sun.COM (lld->llc_sap == msgsap ||
1580*7656SSherry.Moore@Sun.COM msgsap == LLC_GLOBAL_SAP))) {
15810Sstevel@tonic-gate /* sap matches */
15820Sstevel@tonic-gate if (msgsap == LLC_SNAP_SAP &&
15830Sstevel@tonic-gate (lld->llc_flags & (LLC_SNAP|LLC_PROM)) ==
1584*7656SSherry.Moore@Sun.COM LLC_SNAP) {
15850Sstevel@tonic-gate if (!llc1_snap_match(lld,
1586*7656SSherry.Moore@Sun.COM (struct snaphdr *)(llchdr+1)))
15870Sstevel@tonic-gate continue;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate if (!canputnext(RD(lld->llc_qptr))) {
15900Sstevel@tonic-gate #ifdef LLC1_DEBUG
15910Sstevel@tonic-gate if (llc1_debug & LLCRECV)
15920Sstevel@tonic-gate printf(
15930Sstevel@tonic-gate "llc1_recv: canput failed\n");
15940Sstevel@tonic-gate #endif
15950Sstevel@tonic-gate lld->llc_stats->llcs_blocked++;
15960Sstevel@tonic-gate continue;
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate /* check for Novell special handling */
15990Sstevel@tonic-gate if (msgsap == LLC_GLOBAL_SAP &&
16000Sstevel@tonic-gate lld->llc_sap == LLC_NOVELL_SAP &&
16010Sstevel@tonic-gate llchdr->llc_ssap == LLC_GLOBAL_SAP) {
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate /* A Novell packet */
16040Sstevel@tonic-gate nmp = llc1_form_udata(lld, macinfo, mp);
16050Sstevel@tonic-gate continue;
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate switch (llchdr->llc_ctl) {
16080Sstevel@tonic-gate case LLC_UI:
16090Sstevel@tonic-gate /*
16100Sstevel@tonic-gate * this is an Unnumbered Information
16110Sstevel@tonic-gate * packet so form a DL_UNITDATA_IND and
16120Sstevel@tonic-gate * send to user
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate nmp = llc1_form_udata(lld, macinfo, mp);
16150Sstevel@tonic-gate break;
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate case LLC_XID:
16180Sstevel@tonic-gate case LLC_XID | LLC_P:
16190Sstevel@tonic-gate /*
16200Sstevel@tonic-gate * this is either an XID request or
16210Sstevel@tonic-gate * response. We either handle directly
16220Sstevel@tonic-gate * (if user hasn't requested to handle
16230Sstevel@tonic-gate * itself) or send to user. We also
16240Sstevel@tonic-gate * must check if a response if user
16250Sstevel@tonic-gate * handled so that we can send correct
16260Sstevel@tonic-gate * message form
16270Sstevel@tonic-gate */
16280Sstevel@tonic-gate if (lld->llc_flags & LLC1_AUTO_XID) {
16290Sstevel@tonic-gate nmp = llc1_xid_reply(macinfo,
1630*7656SSherry.Moore@Sun.COM mp, lld->llc_sap);
16310Sstevel@tonic-gate } else {
16320Sstevel@tonic-gate /*
16330Sstevel@tonic-gate * hand to the user for
16340Sstevel@tonic-gate * handling. if this is a
16350Sstevel@tonic-gate * "request", generate a
16360Sstevel@tonic-gate * DL_XID_IND. If it is a
16370Sstevel@tonic-gate * "response" to one of our
16380Sstevel@tonic-gate * requests, generate a
16390Sstevel@tonic-gate * DL_XID_CON.
16400Sstevel@tonic-gate */
16410Sstevel@tonic-gate nmp = llc1_xid_ind_con(lld,
1642*7656SSherry.Moore@Sun.COM macinfo, mp);
16430Sstevel@tonic-gate }
16440Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidrcv++;
16450Sstevel@tonic-gate break;
16460Sstevel@tonic-gate
16470Sstevel@tonic-gate case LLC_TEST:
16480Sstevel@tonic-gate case LLC_TEST | LLC_P:
16490Sstevel@tonic-gate /*
16500Sstevel@tonic-gate * this is either a TEST request or
16510Sstevel@tonic-gate * response. We either handle
16520Sstevel@tonic-gate * directly (if user hasn't
16530Sstevel@tonic-gate * requested to handle itself)
16540Sstevel@tonic-gate * or send to user. We also
16550Sstevel@tonic-gate * must check if a response if
16560Sstevel@tonic-gate * user handled so that we can
16570Sstevel@tonic-gate * send correct message form
16580Sstevel@tonic-gate */
16590Sstevel@tonic-gate if (lld->llc_flags & LLC1_AUTO_TEST) {
16600Sstevel@tonic-gate nmp = llc1_test_reply(macinfo,
1661*7656SSherry.Moore@Sun.COM mp, lld->llc_sap);
16620Sstevel@tonic-gate } else {
16630Sstevel@tonic-gate /*
16640Sstevel@tonic-gate * hand to the user for
16650Sstevel@tonic-gate * handling. if this is
16660Sstevel@tonic-gate * a "request",
16670Sstevel@tonic-gate * generate a
16680Sstevel@tonic-gate * DL_TEST_IND. If it
16690Sstevel@tonic-gate * is a "response" to
16700Sstevel@tonic-gate * one of our requests,
16710Sstevel@tonic-gate * generate a
16720Sstevel@tonic-gate * DL_TEST_CON.
16730Sstevel@tonic-gate */
16740Sstevel@tonic-gate nmp = llc1_test_ind_con(lld,
1675*7656SSherry.Moore@Sun.COM macinfo, mp);
16760Sstevel@tonic-gate }
16770Sstevel@tonic-gate macinfo->llcp_stats.llcs_testrcv++;
16780Sstevel@tonic-gate break;
16790Sstevel@tonic-gate default:
16800Sstevel@tonic-gate nmp = mp;
16810Sstevel@tonic-gate break;
16820Sstevel@tonic-gate }
16830Sstevel@tonic-gate mp = nmp;
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate if (mp != NULL)
16870Sstevel@tonic-gate freemsg(mp);
16880Sstevel@tonic-gate if (udmp != NULL)
16890Sstevel@tonic-gate freeb(udmp);
16900Sstevel@tonic-gate if (nmcast > 0)
16910Sstevel@tonic-gate macinfo->llcp_stats.llcs_multircv++;
16920Sstevel@tonic-gate if (statcnt_brdcst) {
16930Sstevel@tonic-gate macinfo->llcp_stats.llcs_brdcstrcv++;
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate if (statcnt_normal) {
16960Sstevel@tonic-gate macinfo->llcp_stats.llcs_bytercv += statcnt_normal;
16970Sstevel@tonic-gate macinfo->llcp_stats.llcs_pktrcv++;
16980Sstevel@tonic-gate }
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate /*
17020Sstevel@tonic-gate * llc1_local - check to see if the message is addressed to this system by
17030Sstevel@tonic-gate * comparing with the board's address.
17040Sstevel@tonic-gate */
17050Sstevel@tonic-gate static int
llc1_local(struct ether_addr * addr,llc_mac_info_t * macinfo)17060Sstevel@tonic-gate llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo)
17070Sstevel@tonic-gate {
17080Sstevel@tonic-gate return (bcmp(addr->ether_addr_octet, macinfo->llcp_macaddr,
17090Sstevel@tonic-gate macinfo->llcp_addrlen) == 0);
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate /*
17130Sstevel@tonic-gate * llc1_broadcast - check to see if a broadcast address is the destination of
17140Sstevel@tonic-gate * this received packet
17150Sstevel@tonic-gate */
17160Sstevel@tonic-gate static int
llc1_broadcast(struct ether_addr * addr,llc_mac_info_t * macinfo)17170Sstevel@tonic-gate llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo)
17180Sstevel@tonic-gate {
17190Sstevel@tonic-gate return (bcmp(addr->ether_addr_octet, macinfo->llcp_broadcast,
17200Sstevel@tonic-gate macinfo->llcp_addrlen) == 0);
17210Sstevel@tonic-gate }
17220Sstevel@tonic-gate
17230Sstevel@tonic-gate /*
17240Sstevel@tonic-gate * llc1attach(q, mp) DLPI DL_ATTACH_REQ this attaches the stream to a PPA
17250Sstevel@tonic-gate */
17260Sstevel@tonic-gate static int
llc1attach(queue_t * q,mblk_t * mp)17270Sstevel@tonic-gate llc1attach(queue_t *q, mblk_t *mp)
17280Sstevel@tonic-gate {
17290Sstevel@tonic-gate dl_attach_req_t *at;
17300Sstevel@tonic-gate llc_mac_info_t *mac;
17310Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr;
17320Sstevel@tonic-gate
17330Sstevel@tonic-gate at = (dl_attach_req_t *)mp->b_rptr;
17340Sstevel@tonic-gate
17350Sstevel@tonic-gate if (llc->llc_state != DL_UNATTACHED) {
17360Sstevel@tonic-gate return (DL_OUTSTATE);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate llc->llc_state = DL_ATTACH_PENDING;
17390Sstevel@tonic-gate
17400Sstevel@tonic-gate if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
17410Sstevel@tonic-gate /*
17420Sstevel@tonic-gate * someone else has a lock held. To avoid deadlock,
17430Sstevel@tonic-gate * release the READER lock and block on a WRITER
17440Sstevel@tonic-gate * lock. This will let things continue safely.
17450Sstevel@tonic-gate */
17460Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
17470Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate
17500Sstevel@tonic-gate for (mac = llc1_device_list.llc1_mac_next;
1751*7656SSherry.Moore@Sun.COM mac != (llc_mac_info_t *)(&llc1_device_list.llc1_mac_next);
1752*7656SSherry.Moore@Sun.COM mac = mac->llcp_next) {
17530Sstevel@tonic-gate ASSERT(mac);
17540Sstevel@tonic-gate if (mac->llcp_ppa == at->dl_ppa && mac->llcp_lqtop == q) {
17550Sstevel@tonic-gate /*
17560Sstevel@tonic-gate * We may have found the correct PPA
17570Sstevel@tonic-gate * check to see if linking has finished.
17580Sstevel@tonic-gate * Use explicit flag checks for incorrect
17590Sstevel@tonic-gate * state, and use negative values for "tenative"
17600Sstevel@tonic-gate * llcp_ppas, to avoid erroneous attaches.
17610Sstevel@tonic-gate */
17620Sstevel@tonic-gate if (mac->llcp_flags &
17630Sstevel@tonic-gate (LLC1_LINKED|LLC1_DEF_PPA)) {
17640Sstevel@tonic-gate return (DL_INITFAILED);
17650Sstevel@tonic-gate } else if (!(mac->llcp_flags & LLC1_AVAILABLE)) {
17660Sstevel@tonic-gate return (DL_BADPPA);
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate /* this links us to the PPA */
17700Sstevel@tonic-gate mac->llcp_nstreams++;
17710Sstevel@tonic-gate llc->llc_mac_info = mac;
17720Sstevel@tonic-gate
17730Sstevel@tonic-gate llc->llc_state = DL_UNBOUND; /* now ready for action */
17740Sstevel@tonic-gate llc->llc_stats = &mac->llcp_stats;
17750Sstevel@tonic-gate dlokack(q, mp, DL_ATTACH_REQ);
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate return (LLCE_OK);
17780Sstevel@tonic-gate }
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate llc->llc_state = DL_UNATTACHED;
17810Sstevel@tonic-gate return (DL_BADPPA);
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate /*
17850Sstevel@tonic-gate * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the
17860Sstevel@tonic-gate * stream
17870Sstevel@tonic-gate */
17880Sstevel@tonic-gate static int
llc1unattach(queue_t * q,mblk_t * mp)17890Sstevel@tonic-gate llc1unattach(queue_t *q, mblk_t *mp)
17900Sstevel@tonic-gate {
17910Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr;
17920Sstevel@tonic-gate int state;
17930Sstevel@tonic-gate int i;
17940Sstevel@tonic-gate
17950Sstevel@tonic-gate state = llc->llc_state;
17960Sstevel@tonic-gate if (state != DL_UNBOUND)
17970Sstevel@tonic-gate return (DL_OUTSTATE);
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate /* can now detach from the PPA */
18000Sstevel@tonic-gate llc->llc_state = DL_DETACH_PENDING;
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate * someone else has a lock held. To avoid deadlock,
18050Sstevel@tonic-gate * release the READER lock and block on a WRITER
18060Sstevel@tonic-gate * lock. This will let things continue safely.
18070Sstevel@tonic-gate */
18080Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock);
18090Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate if (llc->llc_mcast) {
18130Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
18140Sstevel@tonic-gate llc_mcast_t *mcast;
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate if ((mcast = llc->llc_mcast[i]) != NULL) {
18170Sstevel@tonic-gate /* disable from stream and possibly lower */
18180Sstevel@tonic-gate llc1_send_disable_multi(llc->llc_mac_info,
1819*7656SSherry.Moore@Sun.COM mcast);
18200Sstevel@tonic-gate llc->llc_mcast[i] = NULL;
18210Sstevel@tonic-gate }
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate kmem_free(llc->llc_mcast,
18240Sstevel@tonic-gate sizeof (llc_mcast_t *) * llc->llc_multicnt);
18250Sstevel@tonic-gate llc->llc_mcast = NULL;
18260Sstevel@tonic-gate }
18270Sstevel@tonic-gate if (llc->llc_mac_info)
18280Sstevel@tonic-gate llc->llc_mac_info->llcp_nstreams--;
18290Sstevel@tonic-gate llc->llc_sap = 0;
18300Sstevel@tonic-gate llc->llc_state = DL_UNATTACHED;
18310Sstevel@tonic-gate if (mp) {
18320Sstevel@tonic-gate dlokack(q, mp, DL_DETACH_REQ);
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate return (LLCE_OK);
18350Sstevel@tonic-gate }
18360Sstevel@tonic-gate
18370Sstevel@tonic-gate /*
18380Sstevel@tonic-gate * llc1_enable_multi enables multicast address on the stream if the mac layer
18390Sstevel@tonic-gate * isn't enabled for this address, enable at that level as well.
18400Sstevel@tonic-gate */
18410Sstevel@tonic-gate static int
llc1_enable_multi(queue_t * q,mblk_t * mp)18420Sstevel@tonic-gate llc1_enable_multi(queue_t *q, mblk_t *mp)
18430Sstevel@tonic-gate {
18440Sstevel@tonic-gate llc1_t *llc;
18450Sstevel@tonic-gate llc_mac_info_t *macinfo;
18460Sstevel@tonic-gate struct ether_addr *maddr;
18470Sstevel@tonic-gate dl_enabmulti_req_t *multi;
18480Sstevel@tonic-gate llc_mcast_t *mcast;
18490Sstevel@tonic-gate int status = DL_BADADDR;
18500Sstevel@tonic-gate int i;
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate #if defined(LLC1_DEBUG)
18530Sstevel@tonic-gate if (llc1_debug & LLCPROT) {
18540Sstevel@tonic-gate printf("llc1_enable_multi(%x, %x)\n", q, mp);
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate #endif
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate llc = (llc1_t *)q->q_ptr;
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate if (llc->llc_state == DL_UNATTACHED)
18610Sstevel@tonic-gate return (DL_OUTSTATE);
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate macinfo = llc->llc_mac_info;
18640Sstevel@tonic-gate multi = (dl_enabmulti_req_t *)mp->b_rptr;
18650Sstevel@tonic-gate maddr = (struct ether_addr *)(mp->b_rptr + multi->dl_addr_offset);
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate /*
18680Sstevel@tonic-gate * check to see if this multicast address is valid if it is, then
18690Sstevel@tonic-gate * check to see if it is already in the per stream table and the per
18700Sstevel@tonic-gate * device table if it is already in the per stream table, if it isn't
18710Sstevel@tonic-gate * in the per device, add it. If it is, just set a pointer. If it
18720Sstevel@tonic-gate * isn't, allocate what's necessary.
18730Sstevel@tonic-gate */
18740Sstevel@tonic-gate
18750Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
18760Sstevel@tonic-gate MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) &&
18770Sstevel@tonic-gate multi->dl_addr_length == macinfo->llcp_addrlen &&
18780Sstevel@tonic-gate ismulticast(maddr->ether_addr_octet)) {
18790Sstevel@tonic-gate /* request appears to be valid */
18800Sstevel@tonic-gate /* does this address appear in current table? */
18810Sstevel@tonic-gate if (llc->llc_mcast == NULL) {
18820Sstevel@tonic-gate /* no mcast addresses -- allocate table */
18830Sstevel@tonic-gate llc->llc_mcast =
1884*7656SSherry.Moore@Sun.COM GETSTRUCT(llc_mcast_t *,
1885*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_multisize);
18860Sstevel@tonic-gate if (llc->llc_mcast == NULL)
18870Sstevel@tonic-gate return (DL_SYSERR);
18880Sstevel@tonic-gate llc->llc_multicnt = llc1_device_list.llc1_multisize;
18890Sstevel@tonic-gate } else {
18900Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
18910Sstevel@tonic-gate if (llc->llc_mcast[i] &&
1892*7656SSherry.Moore@Sun.COM bcmp(llc->llc_mcast[i]->llcm_addr,
18930Sstevel@tonic-gate maddr->ether_addr_octet, ETHERADDRL)) {
18940Sstevel@tonic-gate /* this is a match -- just succeed */
18950Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ);
18960Sstevel@tonic-gate return (LLCE_OK);
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate /*
19010Sstevel@tonic-gate * there wasn't one so check to see if the mac layer has one
19020Sstevel@tonic-gate */
19030Sstevel@tonic-gate if (macinfo->llcp_mcast == NULL) {
19040Sstevel@tonic-gate macinfo->llcp_mcast =
1905*7656SSherry.Moore@Sun.COM GETSTRUCT(llc_mcast_t,
1906*7656SSherry.Moore@Sun.COM llc1_device_list.llc1_multisize);
19070Sstevel@tonic-gate if (macinfo->llcp_mcast == NULL)
19080Sstevel@tonic-gate return (DL_SYSERR);
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate for (mcast = NULL, i = 0;
1911*7656SSherry.Moore@Sun.COM i < llc1_device_list.llc1_multisize; i++) {
19120Sstevel@tonic-gate if (macinfo->llcp_mcast[i].llcm_refcnt &&
19130Sstevel@tonic-gate bcmp(macinfo->llcp_mcast[i].llcm_addr,
1914*7656SSherry.Moore@Sun.COM maddr->ether_addr_octet, ETHERADDRL) == 0) {
19150Sstevel@tonic-gate mcast = &macinfo->llcp_mcast[i];
19160Sstevel@tonic-gate break;
19170Sstevel@tonic-gate }
19180Sstevel@tonic-gate }
19190Sstevel@tonic-gate if (mcast == NULL) {
19200Sstevel@tonic-gate mblk_t *nmp;
19210Sstevel@tonic-gate
19220Sstevel@tonic-gate nmp = dupmsg(mp);
19230Sstevel@tonic-gate if (nmp) {
19240Sstevel@tonic-gate nmp->b_cont = NULL;
19250Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO;
19260Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), nmp);
19270Sstevel@tonic-gate }
19280Sstevel@tonic-gate /* find an empty slot to fill in */
19290Sstevel@tonic-gate for (mcast = macinfo->llcp_mcast, i = 0;
1930*7656SSherry.Moore@Sun.COM i < llc1_device_list.llc1_multisize; i++, mcast++) {
19310Sstevel@tonic-gate if (mcast->llcm_refcnt == 0) {
19320Sstevel@tonic-gate bcopy(maddr->ether_addr_octet,
19330Sstevel@tonic-gate mcast->llcm_addr, ETHERADDRL);
19340Sstevel@tonic-gate break;
19350Sstevel@tonic-gate }
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate if (mcast != NULL) {
19390Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
19400Sstevel@tonic-gate if (llc->llc_mcast[i] == NULL) {
19410Sstevel@tonic-gate llc->llc_mcast[i] = mcast;
19420Sstevel@tonic-gate mcast->llcm_refcnt++;
19430Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ);
19440Sstevel@tonic-gate return (LLCE_OK);
19450Sstevel@tonic-gate }
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate }
19480Sstevel@tonic-gate status = DL_TOOMANY;
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate return (status);
19510Sstevel@tonic-gate }
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate /*
19540Sstevel@tonic-gate * llc1_disable_multi disable the multicast address on the stream if last
19550Sstevel@tonic-gate * reference for the mac layer, disable there as well
19560Sstevel@tonic-gate */
19570Sstevel@tonic-gate static int
llc1_disable_multi(queue_t * q,mblk_t * mp)19580Sstevel@tonic-gate llc1_disable_multi(queue_t *q, mblk_t *mp)
19590Sstevel@tonic-gate {
19600Sstevel@tonic-gate llc1_t *llc;
19610Sstevel@tonic-gate llc_mac_info_t *macinfo;
19620Sstevel@tonic-gate struct ether_addr *maddr;
19630Sstevel@tonic-gate dl_enabmulti_req_t *multi;
19640Sstevel@tonic-gate int status = DL_BADADDR, i;
19650Sstevel@tonic-gate llc_mcast_t *mcast;
19660Sstevel@tonic-gate
19670Sstevel@tonic-gate #if defined(LLC1_DEBUG)
19680Sstevel@tonic-gate if (llc1_debug & LLCPROT) {
19690Sstevel@tonic-gate printf("llc1_enable_multi(%x, %x)\n", q, mp);
19700Sstevel@tonic-gate }
19710Sstevel@tonic-gate #endif
19720Sstevel@tonic-gate
19730Sstevel@tonic-gate llc = (llc1_t *)q->q_ptr;
19740Sstevel@tonic-gate
19750Sstevel@tonic-gate if (llc->llc_state == DL_UNATTACHED)
19760Sstevel@tonic-gate return (DL_OUTSTATE);
19770Sstevel@tonic-gate
19780Sstevel@tonic-gate macinfo = llc->llc_mac_info;
19790Sstevel@tonic-gate multi = (dl_enabmulti_req_t *)mp->b_rptr;
19800Sstevel@tonic-gate maddr = (struct ether_addr *)(multi + 1);
19810Sstevel@tonic-gate
19820Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
19830Sstevel@tonic-gate MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length)) {
19840Sstevel@tonic-gate /* request appears to be valid */
19850Sstevel@tonic-gate /* does this address appear in current table? */
19860Sstevel@tonic-gate if (llc->llc_mcast != NULL) {
19870Sstevel@tonic-gate for (i = 0; i < llc->llc_multicnt; i++)
19880Sstevel@tonic-gate if (((mcast = llc->llc_mcast[i]) != NULL) &&
19890Sstevel@tonic-gate mcast->llcm_refcnt &&
19900Sstevel@tonic-gate bcmp(mcast->llcm_addr,
19910Sstevel@tonic-gate maddr->ether_addr_octet, ETHERADDRL) == 0) {
19920Sstevel@tonic-gate llc1_send_disable_multi(macinfo,
1993*7656SSherry.Moore@Sun.COM mcast);
19940Sstevel@tonic-gate llc->llc_mcast[i] = NULL;
19950Sstevel@tonic-gate dlokack(q, mp, DL_DISABMULTI_REQ);
19960Sstevel@tonic-gate return (LLCE_OK);
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate status = DL_NOTENAB;
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate return (status);
20020Sstevel@tonic-gate }
20030Sstevel@tonic-gate
20040Sstevel@tonic-gate /*
20050Sstevel@tonic-gate * llc1_send_disable_multi(llc, macinfo, mcast) this function is used to
20060Sstevel@tonic-gate * disable a multicast address if the reference count goes to zero. The
20070Sstevel@tonic-gate * disable request will then be forwarded to the lower stream.
20080Sstevel@tonic-gate */
20090Sstevel@tonic-gate static void
llc1_send_disable_multi(llc_mac_info_t * macinfo,llc_mcast_t * mcast)20100Sstevel@tonic-gate llc1_send_disable_multi(llc_mac_info_t *macinfo, llc_mcast_t *mcast)
20110Sstevel@tonic-gate {
20120Sstevel@tonic-gate mblk_t *mp;
20130Sstevel@tonic-gate dl_disabmulti_req_t *dis;
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate if (mcast == NULL) {
20160Sstevel@tonic-gate return;
20170Sstevel@tonic-gate }
20180Sstevel@tonic-gate if (macinfo == NULL || macinfo->llcp_queue == NULL) {
20190Sstevel@tonic-gate return;
20200Sstevel@tonic-gate }
20210Sstevel@tonic-gate if (--mcast->llcm_refcnt > 0)
20220Sstevel@tonic-gate return;
20230Sstevel@tonic-gate
20240Sstevel@tonic-gate mp = allocb(sizeof (dl_disabmulti_req_t) + ETHERADDRL, BPRI_MED);
20250Sstevel@tonic-gate if (mp) {
20260Sstevel@tonic-gate dis = (dl_disabmulti_req_t *)mp->b_rptr;
20270Sstevel@tonic-gate mp->b_wptr =
2028*7656SSherry.Moore@Sun.COM mp->b_rptr + sizeof (dl_disabmulti_req_t) + ETHERADDRL;
20290Sstevel@tonic-gate dis->dl_primitive = DL_DISABMULTI_REQ;
20300Sstevel@tonic-gate dis->dl_addr_offset = sizeof (dl_disabmulti_req_t);
20310Sstevel@tonic-gate dis->dl_addr_length = ETHERADDRL;
20320Sstevel@tonic-gate bcopy(mcast->llcm_addr,
20330Sstevel@tonic-gate (mp->b_rptr + sizeof (dl_disabmulti_req_t)), ETHERADDRL);
20340Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO;
20350Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), mp);
20360Sstevel@tonic-gate }
20370Sstevel@tonic-gate }
20380Sstevel@tonic-gate
20390Sstevel@tonic-gate /*
20400Sstevel@tonic-gate * llc1_findminor(device) searches the per device class list of STREAMS for
20410Sstevel@tonic-gate * the first minor number not used. Note that we currently don't allocate
20420Sstevel@tonic-gate * minor 0.
20430Sstevel@tonic-gate */
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate static minor_t
llc1_findminor(llc1dev_t * device)20460Sstevel@tonic-gate llc1_findminor(llc1dev_t *device)
20470Sstevel@tonic-gate {
20480Sstevel@tonic-gate llc1_t *next;
20490Sstevel@tonic-gate minor_t minor;
20500Sstevel@tonic-gate
20510Sstevel@tonic-gate ASSERT(device != NULL);
20520Sstevel@tonic-gate for (minor = 1; minor <= MAXMIN32; minor++) {
20530Sstevel@tonic-gate for (next = device->llc1_str_next;
20540Sstevel@tonic-gate next != NULL && next != (llc1_t *)&device->llc1_str_next;
20550Sstevel@tonic-gate next = next->llc_next) {
20560Sstevel@tonic-gate if (minor == next->llc_minor)
20570Sstevel@tonic-gate goto nextminor;
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate return (minor);
20600Sstevel@tonic-gate nextminor:
20610Sstevel@tonic-gate /* don't need to do anything */
20620Sstevel@tonic-gate ;
20630Sstevel@tonic-gate }
20640Sstevel@tonic-gate /*NOTREACHED*/
20650Sstevel@tonic-gate return (0);
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate
20680Sstevel@tonic-gate /*
20690Sstevel@tonic-gate * llc1_req_info(q) simply construct a DL_INFO_REQ to be sent to the lower
20700Sstevel@tonic-gate * stream this is used to populate the macinfo structure.
20710Sstevel@tonic-gate */
20720Sstevel@tonic-gate static int
llc1_req_info(queue_t * q)20730Sstevel@tonic-gate llc1_req_info(queue_t *q)
20740Sstevel@tonic-gate {
20750Sstevel@tonic-gate dl_info_req_t *info;
20760Sstevel@tonic-gate mblk_t *mp;
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate mp = allocb(DL_INFO_REQ_SIZE, BPRI_MED);
20790Sstevel@tonic-gate if (mp == NULL)
20800Sstevel@tonic-gate return (-1);
20810Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO;
20820Sstevel@tonic-gate info = (dl_info_req_t *)mp->b_rptr;
20830Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + DL_INFO_REQ_SIZE;
20840Sstevel@tonic-gate info->dl_primitive = DL_INFO_REQ;
20850Sstevel@tonic-gate putnext(q, mp);
20860Sstevel@tonic-gate return (0);
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate /*
20900Sstevel@tonic-gate * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode
20910Sstevel@tonic-gate */
20920Sstevel@tonic-gate static void
llc1_req_raw(llc_mac_info_t * macinfo)20930Sstevel@tonic-gate llc1_req_raw(llc_mac_info_t *macinfo)
20940Sstevel@tonic-gate {
20950Sstevel@tonic-gate mblk_t *mp;
20960Sstevel@tonic-gate
20970Sstevel@tonic-gate mp = mkiocb(DLIOCRAW);
20980Sstevel@tonic-gate if (mp == NULL)
20990Sstevel@tonic-gate return;
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate macinfo->llcp_iocid = ((struct iocblk *)mp->b_rptr)->ioc_id;
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp);
21040Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_RAW_WAIT;
21050Sstevel@tonic-gate }
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate /*
21080Sstevel@tonic-gate * llc1_send_bindreq
21090Sstevel@tonic-gate * if lower stream isn't bound, bind it to something appropriate
21100Sstevel@tonic-gate */
21110Sstevel@tonic-gate static void
llc1_send_bindreq(llc_mac_info_t * macinfo)21120Sstevel@tonic-gate llc1_send_bindreq(llc_mac_info_t *macinfo)
21130Sstevel@tonic-gate {
21140Sstevel@tonic-gate mblk_t *mp;
21150Sstevel@tonic-gate dl_bind_req_t *bind;
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate if (macinfo->llcp_sap >= 0xFF) {
21180Sstevel@tonic-gate /* have to quite sometime if the world is failing */
21190Sstevel@tonic-gate macinfo->llcp_sap &= ~(LLC1_BINDING|LLC1_AVAILABLE);
21200Sstevel@tonic-gate return;
21210Sstevel@tonic-gate }
21220Sstevel@tonic-gate
21230Sstevel@tonic-gate mp = allocb(sizeof (dl_bind_req_t), BPRI_MED);
21240Sstevel@tonic-gate if (mp == NULL)
21250Sstevel@tonic-gate return;
21260Sstevel@tonic-gate
21270Sstevel@tonic-gate bind = (dl_bind_req_t *)mp->b_rptr;
21280Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (dl_bind_req_t);
21290Sstevel@tonic-gate
21300Sstevel@tonic-gate bind->dl_primitive = DL_BIND_REQ;
21310Sstevel@tonic-gate bind->dl_sap = macinfo->llcp_sap += 2; /* starts at 2, inc by 2 */
21320Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_BINDING;
21330Sstevel@tonic-gate bind->dl_max_conind = 0;
21340Sstevel@tonic-gate bind->dl_service_mode = DL_CLDLS;
21350Sstevel@tonic-gate bind->dl_conn_mgmt = 0;
21360Sstevel@tonic-gate bind->dl_xidtest_flg = 0;
21370Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp);
21380Sstevel@tonic-gate }
21390Sstevel@tonic-gate
21400Sstevel@tonic-gate /*
21410Sstevel@tonic-gate * llc1_form_udata(lld, macinfo, mp) format a DL_UNITDATA_IND message to be
21420Sstevel@tonic-gate * sent to the user
21430Sstevel@tonic-gate */
21440Sstevel@tonic-gate static mblk_t *
llc1_form_udata(llc1_t * lld,llc_mac_info_t * macinfo,mblk_t * mp)21450Sstevel@tonic-gate llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
21460Sstevel@tonic-gate {
21470Sstevel@tonic-gate mblk_t *udmp, *nmp;
21480Sstevel@tonic-gate dl_unitdata_ind_t *udata;
21490Sstevel@tonic-gate struct ether_header *hdr;
21500Sstevel@tonic-gate struct llchdr *llchdr;
21510Sstevel@tonic-gate struct snaphdr *snap;
21520Sstevel@tonic-gate
21530Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) {
2154*7656SSherry.Moore@Sun.COM hdr = (struct ether_header *)mp->b_rptr;
2155*7656SSherry.Moore@Sun.COM llchdr = (struct llchdr *)(hdr + 1);
21560Sstevel@tonic-gate
21570Sstevel@tonic-gate /* allocate the DL_UNITDATA_IND M_PROTO header */
2158*7656SSherry.Moore@Sun.COM udmp = allocb(sizeof (dl_unitdata_ind_t) +
2159*7656SSherry.Moore@Sun.COM 2 * (macinfo->llcp_addrlen + 5), BPRI_MED);
2160*7656SSherry.Moore@Sun.COM if (udmp == NULL) {
21610Sstevel@tonic-gate /* might as well discard since we can't go further */
21620Sstevel@tonic-gate freemsg(mp);
21630Sstevel@tonic-gate return (NULL);
2164*7656SSherry.Moore@Sun.COM }
2165*7656SSherry.Moore@Sun.COM udata = (dl_unitdata_ind_t *)udmp->b_rptr;
2166*7656SSherry.Moore@Sun.COM udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2167*7656SSherry.Moore@Sun.COM
2168*7656SSherry.Moore@Sun.COM nmp = dupmsg(mp); /* make a copy for future streams */
2169*7656SSherry.Moore@Sun.COM if (lld->llc_sap != LLC_NOVELL_SAP)
2170*7656SSherry.Moore@Sun.COM mp->b_rptr += sizeof (struct ether_header) +
21710Sstevel@tonic-gate sizeof (struct llchdr);
2172*7656SSherry.Moore@Sun.COM else
2173*7656SSherry.Moore@Sun.COM mp->b_rptr += sizeof (struct ether_header);
2174*7656SSherry.Moore@Sun.COM
2175*7656SSherry.Moore@Sun.COM if (lld->llc_flags & LLC_SNAP) {
2176*7656SSherry.Moore@Sun.COM mp->b_rptr += sizeof (struct snaphdr);
2177*7656SSherry.Moore@Sun.COM snap = (struct snaphdr *)(llchdr + 1);
2178*7656SSherry.Moore@Sun.COM }
21790Sstevel@tonic-gate
21800Sstevel@tonic-gate /*
21810Sstevel@tonic-gate * now setup the DL_UNITDATA_IND header
21820Sstevel@tonic-gate */
2183*7656SSherry.Moore@Sun.COM DB_TYPE(udmp) = M_PROTO;
2184*7656SSherry.Moore@Sun.COM udata->dl_primitive = DL_UNITDATA_IND;
2185*7656SSherry.Moore@Sun.COM udata->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2186*7656SSherry.Moore@Sun.COM bcopy(hdr->ether_dhost.ether_addr_octet,
2187*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_dest_addr_offset)->llca_addr,
2188*7656SSherry.Moore@Sun.COM macinfo->llcp_addrlen);
2189*7656SSherry.Moore@Sun.COM
2190*7656SSherry.Moore@Sun.COM if (lld->llc_flags & LLC_SNAP) {
2191*7656SSherry.Moore@Sun.COM udata->dl_dest_addr_length = macinfo->llcp_addrlen + 2;
2192*7656SSherry.Moore@Sun.COM LLCSADDR(udata, udata->dl_dest_addr_offset)->llca_ssap =
21930Sstevel@tonic-gate ntohs(*(ushort_t *)snap->snap_type);
2194*7656SSherry.Moore@Sun.COM } else {
2195*7656SSherry.Moore@Sun.COM udata->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2196*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
21970Sstevel@tonic-gate llchdr->llc_dsap;
2198*7656SSherry.Moore@Sun.COM }
2199*7656SSherry.Moore@Sun.COM udmp->b_wptr += udata->dl_dest_addr_length;
2200*7656SSherry.Moore@Sun.COM udata->dl_src_addr_offset = udata->dl_dest_addr_length +
2201*7656SSherry.Moore@Sun.COM udata->dl_dest_addr_offset;
2202*7656SSherry.Moore@Sun.COM bcopy(hdr->ether_shost.ether_addr_octet,
2203*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_src_addr_offset)->llca_addr,
2204*7656SSherry.Moore@Sun.COM macinfo->llcp_addrlen);
2205*7656SSherry.Moore@Sun.COM if (lld->llc_flags & LLC_SNAP) {
2206*7656SSherry.Moore@Sun.COM udata->dl_src_addr_length = macinfo->llcp_addrlen + 2;
2207*7656SSherry.Moore@Sun.COM LLCSADDR(udata, udata->dl_src_addr_offset)->llca_ssap =
22080Sstevel@tonic-gate ntohs(*(ushort_t *)snap->snap_type);
2209*7656SSherry.Moore@Sun.COM } else {
2210*7656SSherry.Moore@Sun.COM udata->dl_src_addr_length = macinfo->llcp_addrlen + 1;
2211*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2212*7656SSherry.Moore@Sun.COM llchdr->llc_ssap;
2213*7656SSherry.Moore@Sun.COM }
2214*7656SSherry.Moore@Sun.COM udata->dl_group_address = hdr->ether_dhost.ether_addr_octet[0] &
2215*7656SSherry.Moore@Sun.COM 0x1;
2216*7656SSherry.Moore@Sun.COM udmp->b_wptr += udata->dl_src_addr_length;
2217*7656SSherry.Moore@Sun.COM udmp->b_cont = mp;
22180Sstevel@tonic-gate } else {
2219*7656SSherry.Moore@Sun.COM dl_unitdata_ind_t *ud2;
2220*7656SSherry.Moore@Sun.COM if (mp->b_cont == NULL) {
22210Sstevel@tonic-gate return (mp); /* we can't do anything */
2222*7656SSherry.Moore@Sun.COM }
22230Sstevel@tonic-gate /* if we end up here, we only want to patch the existing M_PROTO */
2224*7656SSherry.Moore@Sun.COM nmp = dupmsg(mp); /* make a copy for future streams */
2225*7656SSherry.Moore@Sun.COM udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2226*7656SSherry.Moore@Sun.COM udmp = allocb(MBLKL(mp) + 4, BPRI_MED);
2227*7656SSherry.Moore@Sun.COM bcopy(mp->b_rptr, udmp->b_rptr, sizeof (dl_unitdata_ind_t));
2228*7656SSherry.Moore@Sun.COM ud2 = (dl_unitdata_ind_t *)(udmp->b_rptr);
2229*7656SSherry.Moore@Sun.COM udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2230*7656SSherry.Moore@Sun.COM bcopy((caddr_t)mp->b_rptr + udata->dl_dest_addr_offset,
2231*7656SSherry.Moore@Sun.COM udmp->b_wptr, macinfo->llcp_addrlen);
2232*7656SSherry.Moore@Sun.COM ud2->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2233*7656SSherry.Moore@Sun.COM ud2->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2234*7656SSherry.Moore@Sun.COM udmp->b_wptr += ud2->dl_dest_addr_length;
2235*7656SSherry.Moore@Sun.COM bcopy((caddr_t)udmp->b_rptr + udata->dl_src_addr_offset,
2236*7656SSherry.Moore@Sun.COM udmp->b_wptr, macinfo->llcp_addrlen);
2237*7656SSherry.Moore@Sun.COM ud2->dl_src_addr_length = ud2->dl_dest_addr_length;
2238*7656SSherry.Moore@Sun.COM udmp->b_wptr += ud2->dl_src_addr_length;
2239*7656SSherry.Moore@Sun.COM udmp->b_cont = mp->b_cont;
2240*7656SSherry.Moore@Sun.COM if (lld->llc_sap != LLC_NOVELL_SAP)
2241*7656SSherry.Moore@Sun.COM mp->b_cont->b_rptr += sizeof (struct llchdr);
2242*7656SSherry.Moore@Sun.COM freeb(mp);
2243*7656SSherry.Moore@Sun.COM
2244*7656SSherry.Moore@Sun.COM DB_TYPE(udmp) = M_PROTO;
2245*7656SSherry.Moore@Sun.COM udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2246*7656SSherry.Moore@Sun.COM llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
2247*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
2248*7656SSherry.Moore@Sun.COM llchdr->llc_dsap;
2249*7656SSherry.Moore@Sun.COM LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2250*7656SSherry.Moore@Sun.COM llchdr->llc_ssap;
22510Sstevel@tonic-gate }
22520Sstevel@tonic-gate #ifdef LLC1_DEBUG
2253*7656SSherry.Moore@Sun.COM if (llc1_debug & LLCRECV)
22540Sstevel@tonic-gate printf("llc1_recv: queued message to %x (%d)\n",
2255*7656SSherry.Moore@Sun.COM lld->llc_qptr, lld->llc_minor);
22560Sstevel@tonic-gate #endif
22570Sstevel@tonic-gate /* enqueue for the service routine to process */
22580Sstevel@tonic-gate putnext(RD(lld->llc_qptr), udmp);
22590Sstevel@tonic-gate mp = nmp;
22600Sstevel@tonic-gate return (mp);
22610Sstevel@tonic-gate }
22620Sstevel@tonic-gate
22630Sstevel@tonic-gate /*
22640Sstevel@tonic-gate * llc1_xid_reply(macinfo, mp) automatic reply to an XID command
22650Sstevel@tonic-gate */
22660Sstevel@tonic-gate static mblk_t *
llc1_xid_reply(llc_mac_info_t * macinfo,mblk_t * mp,int sap)22670Sstevel@tonic-gate llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
22680Sstevel@tonic-gate {
22690Sstevel@tonic-gate mblk_t *nmp, *rmp;
22700Sstevel@tonic-gate struct ether_header *hdr, *msgether;
22710Sstevel@tonic-gate struct llchdr *llchdr;
22720Sstevel@tonic-gate struct llchdr *msgllc;
22730Sstevel@tonic-gate struct llchdr_xid *xid;
22740Sstevel@tonic-gate
22750Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) {
22760Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr;
22770Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
22780Sstevel@tonic-gate } else {
22790Sstevel@tonic-gate if (mp->b_cont == NULL)
22800Sstevel@tonic-gate return (mp);
22810Sstevel@tonic-gate llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
22820Sstevel@tonic-gate }
22830Sstevel@tonic-gate
22840Sstevel@tonic-gate /* we only want to respond to commands to avoid response loops */
22850Sstevel@tonic-gate if (llchdr->llc_ssap & LLC_RESPONSE)
22860Sstevel@tonic-gate return (mp);
22870Sstevel@tonic-gate
22880Sstevel@tonic-gate nmp = allocb(msgdsize(mp) + LLC_XID_INFO_SIZE, BPRI_MED);
22890Sstevel@tonic-gate if (nmp == NULL) {
22900Sstevel@tonic-gate return (mp);
22910Sstevel@tonic-gate }
22920Sstevel@tonic-gate
22930Sstevel@tonic-gate /*
22940Sstevel@tonic-gate * now construct the XID reply frame
22950Sstevel@tonic-gate */
22960Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) {
22970Sstevel@tonic-gate msgether = (struct ether_header *)nmp->b_rptr;
22980Sstevel@tonic-gate nmp->b_wptr += sizeof (struct ether_header);
22990Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet,
23000Sstevel@tonic-gate msgether->ether_dhost.ether_addr_octet,
23010Sstevel@tonic-gate macinfo->llcp_addrlen);
23020Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr,
23030Sstevel@tonic-gate msgether->ether_shost.ether_addr_octet,
23040Sstevel@tonic-gate macinfo->llcp_addrlen);
23050Sstevel@tonic-gate msgether->ether_type = htons(sizeof (struct llchdr_xid) +
2306*7656SSherry.Moore@Sun.COM sizeof (struct llchdr));
23070Sstevel@tonic-gate rmp = nmp;
23080Sstevel@tonic-gate } else {
23090Sstevel@tonic-gate dl_unitdata_req_t *ud;
23100Sstevel@tonic-gate dl_unitdata_ind_t *rud;
23110Sstevel@tonic-gate rud = (dl_unitdata_ind_t *)mp->b_rptr;
23120Sstevel@tonic-gate
23130Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) +
2314*7656SSherry.Moore@Sun.COM macinfo->llcp_addrlen + 5, BPRI_MED);
23150Sstevel@tonic-gate if (rmp == NULL)
23160Sstevel@tonic-gate return (mp);
23170Sstevel@tonic-gate
23180Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO;
23190Sstevel@tonic-gate bzero(rmp->b_rptr, sizeof (dl_unitdata_req_t));
23200Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr;
23210Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ;
23220Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
23230Sstevel@tonic-gate ud->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
23240Sstevel@tonic-gate
23250Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t);
23260Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, rud->dl_src_addr_offset),
23270Sstevel@tonic-gate LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset),
23280Sstevel@tonic-gate macinfo->llcp_addrlen);
23290Sstevel@tonic-gate LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset)->llca_sap =
2330*7656SSherry.Moore@Sun.COM LLCADDR(mp->b_rptr, rud->dl_src_addr_offset)->llca_sap;
23310Sstevel@tonic-gate rmp->b_wptr += sizeof (struct llcaddr);
23320Sstevel@tonic-gate rmp->b_cont = nmp;
23330Sstevel@tonic-gate }
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate msgllc = (struct llchdr *)nmp->b_wptr;
23360Sstevel@tonic-gate xid = (struct llchdr_xid *)(msgllc + 1);
23370Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr);
23380Sstevel@tonic-gate
23390Sstevel@tonic-gate msgllc->llc_dsap = llchdr->llc_ssap;
23400Sstevel@tonic-gate
23410Sstevel@tonic-gate /* mark it a response */
23420Sstevel@tonic-gate msgllc->llc_ssap = sap | LLC_RESPONSE;
23430Sstevel@tonic-gate
23440Sstevel@tonic-gate msgllc->llc_ctl = llchdr->llc_ctl;
23450Sstevel@tonic-gate xid->llcx_format = LLC_XID_FMTID;
23460Sstevel@tonic-gate xid->llcx_class = LLC_XID_TYPE_1;
23470Sstevel@tonic-gate xid->llcx_window = 0; /* we don't have connections yet */
23480Sstevel@tonic-gate
23490Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr_xid);
23500Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidxmt++;
23510Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp);
23520Sstevel@tonic-gate return (mp);
23530Sstevel@tonic-gate }
23540Sstevel@tonic-gate
23550Sstevel@tonic-gate /*
23560Sstevel@tonic-gate * llc1_xid_ind_con(lld, macinfo, mp) form a DL_XID_IND or DL_XID_CON message
23570Sstevel@tonic-gate * to send to the user since it was requested that the user process these
23580Sstevel@tonic-gate * messages
23590Sstevel@tonic-gate */
23600Sstevel@tonic-gate static mblk_t *
llc1_xid_ind_con(llc1_t * lld,llc_mac_info_t * macinfo,mblk_t * mp)23610Sstevel@tonic-gate llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
23620Sstevel@tonic-gate {
23630Sstevel@tonic-gate mblk_t *nmp;
23640Sstevel@tonic-gate dl_xid_ind_t *xid;
23650Sstevel@tonic-gate struct ether_header *hdr;
23660Sstevel@tonic-gate struct llchdr *llchdr;
23670Sstevel@tonic-gate int raw;
23680Sstevel@tonic-gate
23690Sstevel@tonic-gate nmp = allocb(sizeof (dl_xid_ind_t) + 2 * (macinfo->llcp_addrlen + 1),
2370*7656SSherry.Moore@Sun.COM BPRI_MED);
23710Sstevel@tonic-gate if (nmp == NULL)
23720Sstevel@tonic-gate return (mp);
23730Sstevel@tonic-gate
23740Sstevel@tonic-gate if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
23750Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr;
23760Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
23770Sstevel@tonic-gate } else {
23780Sstevel@tonic-gate if (mp->b_rptr == NULL)
23790Sstevel@tonic-gate return (mp);
23800Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr;
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate
23830Sstevel@tonic-gate xid = (dl_xid_ind_t *)nmp->b_rptr;
23840Sstevel@tonic-gate xid->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
23850Sstevel@tonic-gate xid->dl_dest_addr_offset = sizeof (dl_xid_ind_t);
23860Sstevel@tonic-gate xid->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate if (raw) {
23890Sstevel@tonic-gate bcopy(hdr->ether_dhost.ether_addr_octet,
23900Sstevel@tonic-gate (nmp->b_rptr + xid->dl_dest_addr_offset),
23910Sstevel@tonic-gate xid->dl_dest_addr_length);
23920Sstevel@tonic-gate } else {
23930Sstevel@tonic-gate dl_unitdata_ind_t *ind;
23940Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr;
23950Sstevel@tonic-gate bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
23960Sstevel@tonic-gate (nmp->b_rptr + xid->dl_dest_addr_offset),
23970Sstevel@tonic-gate xid->dl_dest_addr_length);
23980Sstevel@tonic-gate }
23990Sstevel@tonic-gate
24000Sstevel@tonic-gate LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap =
2401*7656SSherry.Moore@Sun.COM llchdr->llc_dsap;
24020Sstevel@tonic-gate
24030Sstevel@tonic-gate xid->dl_src_addr_offset =
2404*7656SSherry.Moore@Sun.COM xid->dl_dest_addr_offset + xid->dl_dest_addr_length;
24050Sstevel@tonic-gate xid->dl_src_addr_length = xid->dl_dest_addr_length;
24060Sstevel@tonic-gate
24070Sstevel@tonic-gate if (raw) {
24080Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet,
24090Sstevel@tonic-gate (nmp->b_rptr + xid->dl_src_addr_offset),
24100Sstevel@tonic-gate xid->dl_src_addr_length);
24110Sstevel@tonic-gate } else {
24120Sstevel@tonic-gate dl_unitdata_ind_t *ind;
24130Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr;
24140Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
24150Sstevel@tonic-gate (nmp->b_rptr + xid->dl_src_addr_offset),
24160Sstevel@tonic-gate ind->dl_src_addr_length);
24170Sstevel@tonic-gate }
24180Sstevel@tonic-gate LLCADDR(nmp->b_rptr, xid->dl_src_addr_offset)->llca_sap =
2419*7656SSherry.Moore@Sun.COM llchdr->llc_ssap & ~LLC_RESPONSE;
24200Sstevel@tonic-gate
24210Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_xid_ind_t) +
2422*7656SSherry.Moore@Sun.COM 2 * xid->dl_dest_addr_length;
24230Sstevel@tonic-gate
24240Sstevel@tonic-gate if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
24250Sstevel@tonic-gate xid->dl_primitive = DL_XID_IND;
24260Sstevel@tonic-gate } else {
24270Sstevel@tonic-gate xid->dl_primitive = DL_XID_CON;
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO;
24310Sstevel@tonic-gate if (raw) {
24320Sstevel@tonic-gate if (MBLKL(mp) >
24330Sstevel@tonic-gate (sizeof (struct ether_header) + sizeof (struct llchdr))) {
24340Sstevel@tonic-gate nmp->b_cont = dupmsg(mp);
24350Sstevel@tonic-gate if (nmp->b_cont) {
24360Sstevel@tonic-gate nmp->b_cont->b_rptr +=
24370Sstevel@tonic-gate sizeof (struct ether_header) +
24380Sstevel@tonic-gate sizeof (struct llchdr);
24390Sstevel@tonic-gate }
24400Sstevel@tonic-gate }
24410Sstevel@tonic-gate } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
24420Sstevel@tonic-gate sizeof (struct llchdr)) {
24430Sstevel@tonic-gate nmp->b_cont = dupmsg(mp->b_cont);
24440Sstevel@tonic-gate (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate putnext(RD(lld->llc_qptr), nmp);
24470Sstevel@tonic-gate return (mp);
24480Sstevel@tonic-gate }
24490Sstevel@tonic-gate
24500Sstevel@tonic-gate /*
24510Sstevel@tonic-gate * llc1_xid_req_res(q, mp, req_or_res) the user wants to send an XID message
24520Sstevel@tonic-gate * or response construct a proper message and put on the net
24530Sstevel@tonic-gate */
24540Sstevel@tonic-gate static int
llc1_xid_req_res(queue_t * q,mblk_t * mp,int req_or_res)24550Sstevel@tonic-gate llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res)
24560Sstevel@tonic-gate {
24570Sstevel@tonic-gate dl_xid_req_t *xid = (dl_xid_req_t *)mp->b_rptr;
24580Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr;
24590Sstevel@tonic-gate llc_mac_info_t *macinfo;
24600Sstevel@tonic-gate mblk_t *nmp, *rmp;
24610Sstevel@tonic-gate struct ether_header *hdr;
24620Sstevel@tonic-gate struct llchdr *llchdr;
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate if (llc == NULL || llc->llc_state == DL_UNATTACHED)
24650Sstevel@tonic-gate return (DL_OUTSTATE);
24660Sstevel@tonic-gate
24670Sstevel@tonic-gate if (llc->llc_sap == LLC_NOVELL_SAP)
24680Sstevel@tonic-gate return (DL_NOTSUPPORTED);
24690Sstevel@tonic-gate
24700Sstevel@tonic-gate if (llc->llc_flags & DL_AUTO_XID)
24710Sstevel@tonic-gate return (DL_XIDAUTO);
24720Sstevel@tonic-gate
24730Sstevel@tonic-gate macinfo = llc->llc_mac_info;
24740Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_xid_req_t) ||
24750Sstevel@tonic-gate !MBLKIN(mp, xid->dl_dest_addr_offset, xid->dl_dest_addr_length)) {
24760Sstevel@tonic-gate return (DL_BADPRIM);
24770Sstevel@tonic-gate }
24780Sstevel@tonic-gate
24790Sstevel@tonic-gate nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr) +
2480*7656SSherry.Moore@Sun.COM sizeof (struct llchdr_xid), BPRI_MED);
24810Sstevel@tonic-gate
24820Sstevel@tonic-gate if (nmp == NULL)
24830Sstevel@tonic-gate return (LLCE_NOBUFFER);
24840Sstevel@tonic-gate
24850Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) {
24860Sstevel@tonic-gate hdr = (struct ether_header *)nmp->b_rptr;
24870Sstevel@tonic-gate bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
24880Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
24890Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr,
24900Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet, ETHERADDRL);
24910Sstevel@tonic-gate hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
24920Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr +
2493*7656SSherry.Moore@Sun.COM sizeof (struct ether_header) + sizeof (struct llchdr);
24940Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
24950Sstevel@tonic-gate rmp = nmp;
24960Sstevel@tonic-gate } else {
24970Sstevel@tonic-gate dl_unitdata_req_t *ud;
24980Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) +
2499*7656SSherry.Moore@Sun.COM (macinfo->llcp_addrlen + 2), BPRI_MED);
25000Sstevel@tonic-gate if (rmp == NULL) {
25010Sstevel@tonic-gate freemsg(nmp);
25020Sstevel@tonic-gate return (LLCE_NOBUFFER);
25030Sstevel@tonic-gate }
25040Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr;
25050Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO;
25060Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ;
25070Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
25080Sstevel@tonic-gate ud->dl_dest_addr_length = xid->dl_dest_addr_length;
25090Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t);
25100Sstevel@tonic-gate bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
25110Sstevel@tonic-gate LLCADDR(ud, ud->dl_dest_addr_offset),
25120Sstevel@tonic-gate xid->dl_dest_addr_length);
25130Sstevel@tonic-gate LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2514*7656SSherry.Moore@Sun.COM msgdsize(mp);
25150Sstevel@tonic-gate rmp->b_wptr += xid->dl_dest_addr_length;
25160Sstevel@tonic-gate rmp->b_cont = nmp;
25170Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_rptr;
25180Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr);
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate
25210Sstevel@tonic-gate llchdr->llc_dsap = LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap;
25220Sstevel@tonic-gate llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
25230Sstevel@tonic-gate llchdr->llc_ctl =
2524*7656SSherry.Moore@Sun.COM LLC_XID | ((xid->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate nmp->b_cont = mp->b_cont;
25270Sstevel@tonic-gate mp->b_cont = NULL;
25280Sstevel@tonic-gate freeb(mp);
25290Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidxmt++;
25300Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp);
25310Sstevel@tonic-gate return (LLCE_OK);
25320Sstevel@tonic-gate }
25330Sstevel@tonic-gate
25340Sstevel@tonic-gate /*
25350Sstevel@tonic-gate * llc1_test_reply(macinfo, mp)
25360Sstevel@tonic-gate * automatic reply to a TEST message
25370Sstevel@tonic-gate */
25380Sstevel@tonic-gate static mblk_t *
llc1_test_reply(llc_mac_info_t * macinfo,mblk_t * mp,int sap)25390Sstevel@tonic-gate llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
25400Sstevel@tonic-gate {
25410Sstevel@tonic-gate mblk_t *nmp;
25420Sstevel@tonic-gate struct ether_header *hdr, *msgether;
25430Sstevel@tonic-gate struct llchdr *llchdr;
25440Sstevel@tonic-gate struct llchdr *msgllc;
25450Sstevel@tonic-gate int poll_final;
25460Sstevel@tonic-gate
25470Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) {
25480Sstevel@tonic-gate if (mp->b_cont == NULL)
25490Sstevel@tonic-gate return (mp);
25500Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr;
25510Sstevel@tonic-gate hdr = NULL;
25520Sstevel@tonic-gate } else {
25530Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr;
25540Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate
25570Sstevel@tonic-gate /* we only want to respond to commands to avoid response loops */
25580Sstevel@tonic-gate if (llchdr->llc_ssap & LLC_RESPONSE)
25590Sstevel@tonic-gate return (mp);
25600Sstevel@tonic-gate
25610Sstevel@tonic-gate nmp = copymsg(mp); /* so info field is duplicated */
25620Sstevel@tonic-gate if (nmp == NULL) {
25630Sstevel@tonic-gate nmp = mp;
25640Sstevel@tonic-gate mp = NULL;
25650Sstevel@tonic-gate }
25660Sstevel@tonic-gate /*
25670Sstevel@tonic-gate * now construct the TEST reply frame
25680Sstevel@tonic-gate */
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate poll_final = llchdr->llc_ctl & LLC_P;
25720Sstevel@tonic-gate
25730Sstevel@tonic-gate if (DB_TYPE(nmp) == M_PROTO) {
25740Sstevel@tonic-gate dl_unitdata_req_t *udr = (dl_unitdata_req_t *)nmp->b_rptr;
25750Sstevel@tonic-gate dl_unitdata_ind_t *udi = (dl_unitdata_ind_t *)nmp->b_rptr;
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate /* make into a request */
25780Sstevel@tonic-gate udr->dl_primitive = DL_UNITDATA_REQ;
25790Sstevel@tonic-gate udr->dl_dest_addr_offset = udi->dl_src_addr_offset;
25800Sstevel@tonic-gate udr->dl_dest_addr_length = udi->dl_src_addr_length;
25810Sstevel@tonic-gate udr->dl_priority.dl_min = udr->dl_priority.dl_max = 0;
25820Sstevel@tonic-gate msgllc = (struct llchdr *)nmp->b_cont->b_rptr;
25830Sstevel@tonic-gate } else {
25840Sstevel@tonic-gate msgether = (struct ether_header *)nmp->b_rptr;
25850Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet,
25860Sstevel@tonic-gate msgether->ether_dhost.ether_addr_octet,
25870Sstevel@tonic-gate macinfo->llcp_addrlen);
25880Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr,
25890Sstevel@tonic-gate msgether->ether_shost.ether_addr_octet,
25900Sstevel@tonic-gate macinfo->llcp_addrlen);
25910Sstevel@tonic-gate msgllc = (struct llchdr *)(msgether+1);
25920Sstevel@tonic-gate }
25930Sstevel@tonic-gate
25940Sstevel@tonic-gate msgllc->llc_dsap = llchdr->llc_ssap;
25950Sstevel@tonic-gate
25960Sstevel@tonic-gate /* mark it as a response */
25970Sstevel@tonic-gate msgllc->llc_ssap = sap | LLC_RESPONSE;
25980Sstevel@tonic-gate msgllc->llc_ctl = LLC_TEST | poll_final;
25990Sstevel@tonic-gate
26000Sstevel@tonic-gate macinfo->llcp_stats.llcs_testxmt++;
26010Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), nmp);
26020Sstevel@tonic-gate return (mp);
26030Sstevel@tonic-gate }
26040Sstevel@tonic-gate
26050Sstevel@tonic-gate /*
26060Sstevel@tonic-gate * llc1_test_ind_con(lld, macinfo, mp) form a DL_TEST_IND or DL_TEST_CON
26070Sstevel@tonic-gate * message to send to the user since it was requested that the user process
26080Sstevel@tonic-gate * these messages
26090Sstevel@tonic-gate */
26100Sstevel@tonic-gate static mblk_t *
llc1_test_ind_con(llc1_t * lld,llc_mac_info_t * macinfo,mblk_t * mp)26110Sstevel@tonic-gate llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
26120Sstevel@tonic-gate {
26130Sstevel@tonic-gate mblk_t *nmp;
26140Sstevel@tonic-gate dl_test_ind_t *test;
26150Sstevel@tonic-gate struct ether_header *hdr;
26160Sstevel@tonic-gate struct llchdr *llchdr;
26170Sstevel@tonic-gate int raw;
26180Sstevel@tonic-gate
26190Sstevel@tonic-gate nmp = allocb(sizeof (dl_test_ind_t) + 2 * (ETHERADDRL + 1), BPRI_MED);
26200Sstevel@tonic-gate if (nmp == NULL)
26210Sstevel@tonic-gate return (NULL);
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
26240Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr;
26250Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
26260Sstevel@tonic-gate } else {
26270Sstevel@tonic-gate if (mp->b_rptr == NULL)
26280Sstevel@tonic-gate return (mp);
26290Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr;
26300Sstevel@tonic-gate }
26310Sstevel@tonic-gate
26320Sstevel@tonic-gate test = (dl_test_ind_t *)nmp->b_rptr;
26330Sstevel@tonic-gate test->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
26340Sstevel@tonic-gate test->dl_dest_addr_offset = sizeof (dl_test_ind_t);
26350Sstevel@tonic-gate test->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
26360Sstevel@tonic-gate
26370Sstevel@tonic-gate if (raw) {
26380Sstevel@tonic-gate bcopy(hdr->ether_dhost.ether_addr_octet,
26390Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_dest_addr_offset)->llca_addr,
26400Sstevel@tonic-gate test->dl_dest_addr_length);
26410Sstevel@tonic-gate } else {
26420Sstevel@tonic-gate dl_unitdata_ind_t *ind;
26430Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr;
26440Sstevel@tonic-gate bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
26450Sstevel@tonic-gate (nmp->b_rptr + test->dl_dest_addr_offset),
26460Sstevel@tonic-gate test->dl_dest_addr_length);
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate
26490Sstevel@tonic-gate LLCADDR(test, test->dl_dest_addr_offset)->llca_sap =
2650*7656SSherry.Moore@Sun.COM llchdr->llc_dsap;
26510Sstevel@tonic-gate
26520Sstevel@tonic-gate test->dl_src_addr_offset = test->dl_dest_addr_offset +
2653*7656SSherry.Moore@Sun.COM test->dl_dest_addr_length;
26540Sstevel@tonic-gate test->dl_src_addr_length = test->dl_dest_addr_length;
26550Sstevel@tonic-gate
26560Sstevel@tonic-gate if (raw) {
26570Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet,
26580Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_addr,
26590Sstevel@tonic-gate test->dl_src_addr_length);
26600Sstevel@tonic-gate } else {
26610Sstevel@tonic-gate dl_unitdata_ind_t *ind;
26620Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr;
26630Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
26640Sstevel@tonic-gate (nmp->b_rptr + test->dl_src_addr_offset),
26650Sstevel@tonic-gate ind->dl_src_addr_length);
26660Sstevel@tonic-gate }
26670Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_sap =
2668*7656SSherry.Moore@Sun.COM llchdr->llc_ssap & ~LLC_RESPONSE;
26690Sstevel@tonic-gate
26700Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_test_ind_t) +
2671*7656SSherry.Moore@Sun.COM 2 * test->dl_dest_addr_length;
26720Sstevel@tonic-gate
26730Sstevel@tonic-gate if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
26740Sstevel@tonic-gate test->dl_primitive = DL_TEST_IND;
26750Sstevel@tonic-gate } else {
26760Sstevel@tonic-gate test->dl_primitive = DL_TEST_CON;
26770Sstevel@tonic-gate }
26780Sstevel@tonic-gate
26790Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO;
26800Sstevel@tonic-gate if (raw) {
26810Sstevel@tonic-gate if (MBLKL(mp) >
26820Sstevel@tonic-gate (sizeof (struct ether_header) + sizeof (struct llchdr))) {
26830Sstevel@tonic-gate nmp->b_cont = dupmsg(mp);
26840Sstevel@tonic-gate if (nmp->b_cont) {
26850Sstevel@tonic-gate nmp->b_cont->b_rptr +=
26860Sstevel@tonic-gate sizeof (struct ether_header) +
26870Sstevel@tonic-gate sizeof (struct llchdr);
26880Sstevel@tonic-gate }
26890Sstevel@tonic-gate }
26900Sstevel@tonic-gate } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
26910Sstevel@tonic-gate sizeof (struct llchdr)) {
26920Sstevel@tonic-gate nmp->b_cont = dupmsg(mp->b_cont);
26930Sstevel@tonic-gate (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
26940Sstevel@tonic-gate }
26950Sstevel@tonic-gate putnext(RD(lld->llc_qptr), nmp);
26960Sstevel@tonic-gate return (mp);
26970Sstevel@tonic-gate }
26980Sstevel@tonic-gate
26990Sstevel@tonic-gate /*
27000Sstevel@tonic-gate * llc1_test_req_res(q, mp, req_or_res) the user wants to send a TEST
27010Sstevel@tonic-gate * message or response construct a proper message and put on the net
27020Sstevel@tonic-gate */
27030Sstevel@tonic-gate static int
llc1_test_req_res(queue_t * q,mblk_t * mp,int req_or_res)27040Sstevel@tonic-gate llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res)
27050Sstevel@tonic-gate {
27060Sstevel@tonic-gate dl_test_req_t *test = (dl_test_req_t *)mp->b_rptr;
27070Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr;
27080Sstevel@tonic-gate llc_mac_info_t *macinfo;
27090Sstevel@tonic-gate mblk_t *nmp, *rmp;
27100Sstevel@tonic-gate struct ether_header *hdr;
27110Sstevel@tonic-gate struct llchdr *llchdr;
27120Sstevel@tonic-gate
27130Sstevel@tonic-gate if (llc == NULL || llc->llc_state == DL_UNATTACHED)
27140Sstevel@tonic-gate return (DL_OUTSTATE);
27150Sstevel@tonic-gate
27160Sstevel@tonic-gate if (llc->llc_sap == LLC_NOVELL_SAP)
27170Sstevel@tonic-gate return (DL_NOTSUPPORTED);
27180Sstevel@tonic-gate
27190Sstevel@tonic-gate if (llc->llc_flags & DL_AUTO_TEST)
27200Sstevel@tonic-gate return (DL_TESTAUTO);
27210Sstevel@tonic-gate
27220Sstevel@tonic-gate macinfo = llc->llc_mac_info;
27230Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_test_req_t) ||
27240Sstevel@tonic-gate !MBLKIN(mp, test->dl_dest_addr_offset,
2725*7656SSherry.Moore@Sun.COM test->dl_dest_addr_length)) {
27260Sstevel@tonic-gate return (DL_BADPRIM);
27270Sstevel@tonic-gate }
27280Sstevel@tonic-gate
27290Sstevel@tonic-gate nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr),
2730*7656SSherry.Moore@Sun.COM BPRI_MED);
27310Sstevel@tonic-gate
27320Sstevel@tonic-gate if (nmp == NULL)
27330Sstevel@tonic-gate return (LLCE_NOBUFFER);
27340Sstevel@tonic-gate
27350Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) {
27360Sstevel@tonic-gate hdr = (struct ether_header *)nmp->b_rptr;
27370Sstevel@tonic-gate bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
27380Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
27390Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr,
27400Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet, ETHERADDRL);
27410Sstevel@tonic-gate hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
27420Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr +
2743*7656SSherry.Moore@Sun.COM sizeof (struct ether_header) + sizeof (struct llchdr);
27440Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1);
27450Sstevel@tonic-gate rmp = nmp;
27460Sstevel@tonic-gate } else {
27470Sstevel@tonic-gate dl_unitdata_req_t *ud;
27480Sstevel@tonic-gate
27490Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) +
2750*7656SSherry.Moore@Sun.COM (macinfo->llcp_addrlen + 2), BPRI_MED);
27510Sstevel@tonic-gate if (rmp == NULL) {
27520Sstevel@tonic-gate freemsg(nmp);
27530Sstevel@tonic-gate return (LLCE_NOBUFFER);
27540Sstevel@tonic-gate
27550Sstevel@tonic-gate }
27560Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr;
27570Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO;
27580Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ;
27590Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
27600Sstevel@tonic-gate ud->dl_dest_addr_length = test->dl_dest_addr_length;
27610Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t);
27620Sstevel@tonic-gate bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
27630Sstevel@tonic-gate LLCADDR(ud, ud->dl_dest_addr_offset),
27640Sstevel@tonic-gate test->dl_dest_addr_length);
27650Sstevel@tonic-gate LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2766*7656SSherry.Moore@Sun.COM msgdsize(mp);
27670Sstevel@tonic-gate rmp->b_wptr += test->dl_dest_addr_length;
27680Sstevel@tonic-gate rmp->b_cont = nmp;
27690Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_rptr;
27700Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr);
27710Sstevel@tonic-gate }
27720Sstevel@tonic-gate
27730Sstevel@tonic-gate llchdr->llc_dsap = LLCADDR(test, test->dl_dest_addr_offset)->llca_sap;
27740Sstevel@tonic-gate llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
27750Sstevel@tonic-gate llchdr->llc_ctl =
2776*7656SSherry.Moore@Sun.COM LLC_TEST | ((test->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
27770Sstevel@tonic-gate
27780Sstevel@tonic-gate nmp->b_cont = mp->b_cont;
27790Sstevel@tonic-gate mp->b_cont = NULL;
27800Sstevel@tonic-gate freeb(mp);
27810Sstevel@tonic-gate macinfo->llcp_stats.llcs_testxmt++;
27820Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp);
27830Sstevel@tonic-gate return (LLCE_OK);
27840Sstevel@tonic-gate }
27850Sstevel@tonic-gate
27860Sstevel@tonic-gate /*
27870Sstevel@tonic-gate * llc1_find_waiting(macinfo, mp, prim) look for a stream waiting for a
27880Sstevel@tonic-gate * response to a message identified by prim and send it to the user.
27890Sstevel@tonic-gate */
27900Sstevel@tonic-gate static void
llc1_find_waiting(llc_mac_info_t * macinfo,mblk_t * mp,long prim)27910Sstevel@tonic-gate llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim)
27920Sstevel@tonic-gate {
27930Sstevel@tonic-gate llc1_t *llc;
27940Sstevel@tonic-gate
27950Sstevel@tonic-gate for (llc = llc1_device_list.llc1_str_next;
2796*7656SSherry.Moore@Sun.COM llc != (llc1_t *)&llc1_device_list.llc1_str_next;
2797*7656SSherry.Moore@Sun.COM llc = llc->llc_next)
27980Sstevel@tonic-gate if (llc->llc_mac_info == macinfo &&
27990Sstevel@tonic-gate prim == llc->llc_waiting_for) {
28000Sstevel@tonic-gate putnext(RD(llc->llc_qptr), mp);
28010Sstevel@tonic-gate llc->llc_waiting_for = -1;
28020Sstevel@tonic-gate return;
28030Sstevel@tonic-gate }
28040Sstevel@tonic-gate freemsg(mp);
28050Sstevel@tonic-gate }
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate static void
llc1insque(void * elem,void * pred)28080Sstevel@tonic-gate llc1insque(void *elem, void *pred)
28090Sstevel@tonic-gate {
28100Sstevel@tonic-gate struct qelem *pelem = elem;
28110Sstevel@tonic-gate struct qelem *ppred = pred;
28120Sstevel@tonic-gate struct qelem *pnext = ppred->q_forw;
28130Sstevel@tonic-gate
28140Sstevel@tonic-gate pelem->q_forw = pnext;
28150Sstevel@tonic-gate pelem->q_back = ppred;
28160Sstevel@tonic-gate ppred->q_forw = pelem;
28170Sstevel@tonic-gate pnext->q_back = pelem;
28180Sstevel@tonic-gate }
28190Sstevel@tonic-gate
28200Sstevel@tonic-gate static void
llc1remque(void * arg)28210Sstevel@tonic-gate llc1remque(void *arg)
28220Sstevel@tonic-gate {
28230Sstevel@tonic-gate struct qelem *pelem = arg;
28240Sstevel@tonic-gate struct qelem *elem = arg;
28250Sstevel@tonic-gate
28260Sstevel@tonic-gate ASSERT(pelem->q_forw != NULL);
28270Sstevel@tonic-gate pelem->q_forw->q_back = pelem->q_back;
28280Sstevel@tonic-gate pelem->q_back->q_forw = pelem->q_forw;
28290Sstevel@tonic-gate elem->q_back = elem->q_forw = NULL;
28300Sstevel@tonic-gate }
28310Sstevel@tonic-gate
28320Sstevel@tonic-gate /* VARARGS */
28330Sstevel@tonic-gate static void
llc1error(dip,fmt,a1,a2,a3,a4,a5,a6)28340Sstevel@tonic-gate llc1error(dip, fmt, a1, a2, a3, a4, a5, a6)
28350Sstevel@tonic-gate dev_info_t *dip;
28360Sstevel@tonic-gate char *fmt, *a1, *a2, *a3, *a4, *a5, *a6;
28370Sstevel@tonic-gate {
28380Sstevel@tonic-gate static long last;
28390Sstevel@tonic-gate static char *lastfmt;
28400Sstevel@tonic-gate time_t now;
28410Sstevel@tonic-gate
28420Sstevel@tonic-gate /*
28430Sstevel@tonic-gate * Don't print same error message too often.
28440Sstevel@tonic-gate */
28450Sstevel@tonic-gate now = gethrestime_sec();
28460Sstevel@tonic-gate if ((last == (now & ~1)) && (lastfmt == fmt))
28470Sstevel@tonic-gate return;
28480Sstevel@tonic-gate last = now & ~1;
28490Sstevel@tonic-gate lastfmt = fmt;
28500Sstevel@tonic-gate
28510Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: ",
28520Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip));
28530Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5, a6);
28540Sstevel@tonic-gate cmn_err(CE_CONT, "\n");
28550Sstevel@tonic-gate }
28560Sstevel@tonic-gate
28570Sstevel@tonic-gate /*ARGSUSED1*/
28580Sstevel@tonic-gate static int
llc1_update_kstat(kstat_t * ksp,int rw)28590Sstevel@tonic-gate llc1_update_kstat(kstat_t *ksp, int rw)
28600Sstevel@tonic-gate {
28610Sstevel@tonic-gate llc_mac_info_t *macinfo;
28620Sstevel@tonic-gate kstat_named_t *kstat;
28630Sstevel@tonic-gate struct llc_stats *stats;
28640Sstevel@tonic-gate
28650Sstevel@tonic-gate if (ksp == NULL)
28660Sstevel@tonic-gate return (0);
28670Sstevel@tonic-gate
28680Sstevel@tonic-gate kstat = (kstat_named_t *)(ksp->ks_data);
28690Sstevel@tonic-gate macinfo = (llc_mac_info_t *)(ksp->ks_private);
28700Sstevel@tonic-gate stats = &macinfo->llcp_stats;
28710Sstevel@tonic-gate
28720Sstevel@tonic-gate kstat[LLCS_NOBUFFER].value.ul = stats->llcs_nobuffer;
28730Sstevel@tonic-gate kstat[LLCS_MULTIXMT].value.ul = stats->llcs_multixmt;
28740Sstevel@tonic-gate kstat[LLCS_MULTIRCV].value.ul = stats->llcs_multircv;
28750Sstevel@tonic-gate kstat[LLCS_BRDCSTXMT].value.ul = stats->llcs_brdcstxmt;
28760Sstevel@tonic-gate kstat[LLCS_BRDCSTRCV].value.ul = stats->llcs_brdcstrcv;
28770Sstevel@tonic-gate kstat[LLCS_BLOCKED].value.ul = stats->llcs_blocked;
28780Sstevel@tonic-gate kstat[LLCS_PKTXMT].value.ul = stats->llcs_pktxmt;
28790Sstevel@tonic-gate kstat[LLCS_PKTRCV].value.ul = stats->llcs_pktrcv;
28800Sstevel@tonic-gate kstat[LLCS_BYTEXMT].value.ul = stats->llcs_bytexmt;
28810Sstevel@tonic-gate kstat[LLCS_BYTERCV].value.ul = stats->llcs_bytercv;
28820Sstevel@tonic-gate kstat[LLCS_XIDXMT].value.ul = stats->llcs_xidxmt;
28830Sstevel@tonic-gate kstat[LLCS_XIDRCV].value.ul = stats->llcs_xidrcv;
28840Sstevel@tonic-gate kstat[LLCS_TESTXMT].value.ul = stats->llcs_testxmt;
28850Sstevel@tonic-gate kstat[LLCS_TESTRCV].value.ul = stats->llcs_testrcv;
28860Sstevel@tonic-gate kstat[LLCS_IERRORS].value.ul = stats->llcs_ierrors;
28870Sstevel@tonic-gate kstat[LLCS_OERRORS].value.ul = stats->llcs_oerrors;
28880Sstevel@tonic-gate return (0);
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate
28910Sstevel@tonic-gate static void
llc1_init_kstat(llc_mac_info_t * macinfo)28920Sstevel@tonic-gate llc1_init_kstat(llc_mac_info_t *macinfo)
28930Sstevel@tonic-gate {
28940Sstevel@tonic-gate kstat_named_t *ksp;
28950Sstevel@tonic-gate
28960Sstevel@tonic-gate /*
28970Sstevel@tonic-gate * Note that the temporary macinfo->llcp_ppa number is negative.
28980Sstevel@tonic-gate */
28990Sstevel@tonic-gate macinfo->llcp_kstatp = kstat_create("llc", (-macinfo->llcp_ppa - 1),
2900*7656SSherry.Moore@Sun.COM NULL, "net", KSTAT_TYPE_NAMED,
2901*7656SSherry.Moore@Sun.COM sizeof (struct llc_stats) / sizeof (long), 0);
29020Sstevel@tonic-gate if (macinfo->llcp_kstatp == NULL)
29030Sstevel@tonic-gate return;
29040Sstevel@tonic-gate
29050Sstevel@tonic-gate macinfo->llcp_kstatp->ks_update = llc1_update_kstat;
29060Sstevel@tonic-gate macinfo->llcp_kstatp->ks_private = (void *)macinfo;
29070Sstevel@tonic-gate
29080Sstevel@tonic-gate ksp = (kstat_named_t *)(macinfo->llcp_kstatp->ks_data);
29090Sstevel@tonic-gate
29100Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_NOBUFFER], "nobuffer", KSTAT_DATA_ULONG);
29110Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_MULTIXMT], "multixmt", KSTAT_DATA_ULONG);
29120Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_MULTIRCV], "multircv", KSTAT_DATA_ULONG);
29130Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BRDCSTXMT], "brdcstxmt", KSTAT_DATA_ULONG);
29140Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BRDCSTRCV], "brdcstrcv", KSTAT_DATA_ULONG);
29150Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BLOCKED], "blocked", KSTAT_DATA_ULONG);
29160Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_PKTXMT], "pktxmt", KSTAT_DATA_ULONG);
29170Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_PKTRCV], "pktrcv", KSTAT_DATA_ULONG);
29180Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BYTEXMT], "bytexmt", KSTAT_DATA_ULONG);
29190Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BYTERCV], "bytercv", KSTAT_DATA_ULONG);
29200Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_XIDXMT], "xidxmt", KSTAT_DATA_ULONG);
29210Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_XIDRCV], "xidrcv", KSTAT_DATA_ULONG);
29220Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_TESTXMT], "testxmt", KSTAT_DATA_ULONG);
29230Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_TESTRCV], "testrcv", KSTAT_DATA_ULONG);
29240Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_IERRORS], "ierrors", KSTAT_DATA_ULONG);
29250Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_OERRORS], "oerrors", KSTAT_DATA_ULONG);
29260Sstevel@tonic-gate kstat_install(macinfo->llcp_kstatp);
29270Sstevel@tonic-gate }
29280Sstevel@tonic-gate
29290Sstevel@tonic-gate static void
llc1_uninit_kstat(llc_mac_info_t * macinfo)29300Sstevel@tonic-gate llc1_uninit_kstat(llc_mac_info_t *macinfo)
29310Sstevel@tonic-gate {
29320Sstevel@tonic-gate if (macinfo->llcp_kstatp) {
29330Sstevel@tonic-gate kstat_delete(macinfo->llcp_kstatp);
29340Sstevel@tonic-gate macinfo->llcp_kstatp = NULL;
29350Sstevel@tonic-gate }
29360Sstevel@tonic-gate }
29370Sstevel@tonic-gate
29380Sstevel@tonic-gate /*
29390Sstevel@tonic-gate * llc1_subs_bind(q, mp)
29400Sstevel@tonic-gate * implements the DL_SUBS_BIND_REQ primitive
29410Sstevel@tonic-gate * this only works for a STREAM bound to LLC_SNAP_SAP
29420Sstevel@tonic-gate * or one bound to the automatic SNAP mode.
29430Sstevel@tonic-gate * If bound to LLC_SNAP_SAP, the subs bind can be:
29440Sstevel@tonic-gate * - 2 octets treated as a native byte order short (ethertype)
29450Sstevel@tonic-gate * - 3 octets treated as a network order byte string (OID part)
29460Sstevel@tonic-gate * - 5 octets treated as a network order byte string (full SNAP header)
29470Sstevel@tonic-gate * If bound to an automatic SNAP mode sap, then only the 3 octet
29480Sstevel@tonic-gate * form is allowed
29490Sstevel@tonic-gate */
29500Sstevel@tonic-gate static int
llc1_subs_bind(queue_t * q,mblk_t * mp)29510Sstevel@tonic-gate llc1_subs_bind(queue_t *q, mblk_t *mp)
29520Sstevel@tonic-gate {
29530Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr;
29540Sstevel@tonic-gate dl_subs_bind_req_t *subs = (dl_subs_bind_req_t *)mp->b_rptr;
29550Sstevel@tonic-gate ushort_t subssap;
29560Sstevel@tonic-gate uchar_t *sapstr;
29570Sstevel@tonic-gate int result;
29580Sstevel@tonic-gate
29590Sstevel@tonic-gate
29600Sstevel@tonic-gate #if defined(LLC1_DEBUG)
29610Sstevel@tonic-gate if (llc1_debug & (LLCTRACE|LLCPROT)) {
29620Sstevel@tonic-gate printf("llc1_subs_bind (%x, %x)\n", q, mp);
29630Sstevel@tonic-gate }
29640Sstevel@tonic-gate #endif
29650Sstevel@tonic-gate
29660Sstevel@tonic-gate if (lld == NULL || lld->llc_state != DL_IDLE) {
29670Sstevel@tonic-gate result = DL_OUTSTATE;
29680Sstevel@tonic-gate } else if (lld->llc_sap != LLC_SNAP_SAP ||
2969*7656SSherry.Moore@Sun.COM subs->dl_subs_bind_class != DL_HIERARCHICAL_BIND) {
29700Sstevel@tonic-gate /* we only want to support this for SNAP at present */
29710Sstevel@tonic-gate result = DL_UNSUPPORTED;
29720Sstevel@tonic-gate } else {
29730Sstevel@tonic-gate
29740Sstevel@tonic-gate lld->llc_state = DL_SUBS_BIND_PND;
29750Sstevel@tonic-gate
29760Sstevel@tonic-gate sapstr = (uchar_t *)(mp->b_rptr + subs->dl_subs_sap_offset);
29770Sstevel@tonic-gate
29780Sstevel@tonic-gate result = LLCE_OK;
29790Sstevel@tonic-gate switch (subs->dl_subs_sap_length) {
29800Sstevel@tonic-gate case 2: /* just the ethertype part */
29810Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) {
29820Sstevel@tonic-gate result = DL_BADADDR;
29830Sstevel@tonic-gate break;
29840Sstevel@tonic-gate }
29850Sstevel@tonic-gate ((uchar_t *)&subssap)[0] = sapstr[0];
29860Sstevel@tonic-gate ((uchar_t *)&subssap)[1] = sapstr[1];
29870Sstevel@tonic-gate subssap = htons(subssap);
29880Sstevel@tonic-gate lld->llc_snap[3] = ((uchar_t *)&subssap)[0];
29890Sstevel@tonic-gate lld->llc_snap[4] = ((uchar_t *)&subssap)[1];
29900Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP;
29910Sstevel@tonic-gate break;
29920Sstevel@tonic-gate
29930Sstevel@tonic-gate case 3: /* just the OID part */
29940Sstevel@tonic-gate if ((lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) ==
29950Sstevel@tonic-gate (LLC_SNAP|LLC_SNAP_OID)) {
29960Sstevel@tonic-gate result = DL_BADADDR;
29970Sstevel@tonic-gate break;
29980Sstevel@tonic-gate }
29990Sstevel@tonic-gate bcopy(sapstr, lld->llc_snap, 3);
30000Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP_OID;
30010Sstevel@tonic-gate break;
30020Sstevel@tonic-gate
30030Sstevel@tonic-gate case 5: /* full SNAP header */
30040Sstevel@tonic-gate if (lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) {
30050Sstevel@tonic-gate result = DL_BADADDR;
30060Sstevel@tonic-gate break;
30070Sstevel@tonic-gate }
30080Sstevel@tonic-gate bcopy(sapstr, lld->llc_snap, 5);
30090Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP|LLC_SNAP_OID;
30100Sstevel@tonic-gate break;
30110Sstevel@tonic-gate }
30120Sstevel@tonic-gate /* if successful, acknowledge and enter the proper state */
30130Sstevel@tonic-gate if (result == LLCE_OK) {
30140Sstevel@tonic-gate mblk_t *nmp = mp;
30150Sstevel@tonic-gate dl_subs_bind_ack_t *ack;
30160Sstevel@tonic-gate
30170Sstevel@tonic-gate if (DB_REF(mp) != 1 ||
30180Sstevel@tonic-gate MBLKL(mp) < (sizeof (dl_subs_bind_ack_t) + 5)) {
30190Sstevel@tonic-gate freemsg(mp);
30200Sstevel@tonic-gate nmp = allocb(sizeof (dl_subs_bind_ack_t) + 5,
3021*7656SSherry.Moore@Sun.COM BPRI_MED);
30220Sstevel@tonic-gate }
30230Sstevel@tonic-gate ack = (dl_subs_bind_ack_t *)nmp->b_rptr;
30240Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr +
3025*7656SSherry.Moore@Sun.COM sizeof (dl_subs_bind_ack_t) + 5;
30260Sstevel@tonic-gate ack->dl_primitive = DL_SUBS_BIND_ACK;
30270Sstevel@tonic-gate ack->dl_subs_sap_offset = sizeof (dl_subs_bind_ack_t);
30280Sstevel@tonic-gate ack->dl_subs_sap_length = 5;
30290Sstevel@tonic-gate bcopy(lld->llc_snap,
30300Sstevel@tonic-gate (caddr_t)nmp->b_rptr + ack->dl_subs_sap_offset + 5,
30310Sstevel@tonic-gate 5);
30320Sstevel@tonic-gate DB_TYPE(nmp) = M_PCPROTO;
30330Sstevel@tonic-gate qreply(q, nmp);
30340Sstevel@tonic-gate
30350Sstevel@tonic-gate }
30360Sstevel@tonic-gate lld->llc_state = DL_IDLE;
30370Sstevel@tonic-gate }
30380Sstevel@tonic-gate return (result);
30390Sstevel@tonic-gate }
30400Sstevel@tonic-gate
30410Sstevel@tonic-gate /*
30420Sstevel@tonic-gate *
30430Sstevel@tonic-gate */
30440Sstevel@tonic-gate static int
llc1_subs_unbind(void)30450Sstevel@tonic-gate llc1_subs_unbind(void)
30460Sstevel@tonic-gate {
30470Sstevel@tonic-gate return (DL_UNSUPPORTED);
30480Sstevel@tonic-gate }
30490Sstevel@tonic-gate
30500Sstevel@tonic-gate char *
snapdmp(uchar_t * bstr)30510Sstevel@tonic-gate snapdmp(uchar_t *bstr)
30520Sstevel@tonic-gate {
30530Sstevel@tonic-gate static char buff[32];
30540Sstevel@tonic-gate
30550Sstevel@tonic-gate (void) sprintf(buff, "%x.%x.%x.%x.%x",
3056*7656SSherry.Moore@Sun.COM bstr[0],
3057*7656SSherry.Moore@Sun.COM bstr[1],
3058*7656SSherry.Moore@Sun.COM bstr[2],
3059*7656SSherry.Moore@Sun.COM bstr[3],
3060*7656SSherry.Moore@Sun.COM bstr[4]);
30610Sstevel@tonic-gate return (buff);
30620Sstevel@tonic-gate }
30630Sstevel@tonic-gate
30640Sstevel@tonic-gate static int
llc1_snap_match(llc1_t * lld,struct snaphdr * snap)30650Sstevel@tonic-gate llc1_snap_match(llc1_t *lld, struct snaphdr *snap)
30660Sstevel@tonic-gate {
30670Sstevel@tonic-gate return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0);
30680Sstevel@tonic-gate }
3069