17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*19397407SSherry Moore * Common Development and Distribution License (the "License"). 6*19397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * llc1 - an LLC Class 1 MUX compatible with SunConnect LLC2 uses DLPI 297c478bd9Sstevel@tonic-gate * interface. Its primary use is to support RPL for network boot but can be 307c478bd9Sstevel@tonic-gate * used by other protocols. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/systm.h> 397c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 407c478bd9Sstevel@tonic-gate #include <sys/stream.h> 417c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 427c478bd9Sstevel@tonic-gate #include <sys/conf.h> 437c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 447c478bd9Sstevel@tonic-gate #include <sys/devops.h> 457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 467c478bd9Sstevel@tonic-gate #include <sys/ksynch.h> 477c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 487c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 497c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 507c478bd9Sstevel@tonic-gate #include <sys/stat.h> 517c478bd9Sstevel@tonic-gate #include <netinet/in.h> /* for byteorder macros on machines that define them */ 527c478bd9Sstevel@tonic-gate #include <sys/llc1.h> 537c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 547c478bd9Sstevel@tonic-gate #include <sys/debug.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * function prototypes, etc. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate static int llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, 607c478bd9Sstevel@tonic-gate cred_t *cred); 617c478bd9Sstevel@tonic-gate static int llc1_close(queue_t *q, int flag, cred_t *cred); 627c478bd9Sstevel@tonic-gate static int llc1_uwput(queue_t *q, mblk_t *mp); 637c478bd9Sstevel@tonic-gate static int llc1_uwsrv(queue_t *q); 647c478bd9Sstevel@tonic-gate static int llc1_lrsrv(queue_t *q); 657c478bd9Sstevel@tonic-gate static int llc1_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 667c478bd9Sstevel@tonic-gate static int llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd); 677c478bd9Sstevel@tonic-gate static int llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd); 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static mblk_t *llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, 707c478bd9Sstevel@tonic-gate mblk_t *mp); 717c478bd9Sstevel@tonic-gate static mblk_t *llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap); 727c478bd9Sstevel@tonic-gate static mblk_t *llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, 737c478bd9Sstevel@tonic-gate mblk_t *mp); 747c478bd9Sstevel@tonic-gate static mblk_t *llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap); 757c478bd9Sstevel@tonic-gate static mblk_t *llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, 767c478bd9Sstevel@tonic-gate mblk_t *mp); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static void llc1_ioctl(queue_t *q, mblk_t *mp); 797c478bd9Sstevel@tonic-gate static void llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp); 807c478bd9Sstevel@tonic-gate static void llc1_req_raw(llc_mac_info_t *macinfo); 817c478bd9Sstevel@tonic-gate static void llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static minor_t llc1_findminor(llc1dev_t *device); 847c478bd9Sstevel@tonic-gate static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static void llc1insque(void *elem, void *pred); 877c478bd9Sstevel@tonic-gate static void llc1remque(void *arg); 887c478bd9Sstevel@tonic-gate static void llc1error(); 897c478bd9Sstevel@tonic-gate static int llc1_subs_unbind(void); 907c478bd9Sstevel@tonic-gate static void llc1_init_kstat(llc_mac_info_t *macinfo); 917c478bd9Sstevel@tonic-gate static void llc1_uninit_kstat(llc_mac_info_t *macinfo); 927c478bd9Sstevel@tonic-gate static int llc1_update_kstat(kstat_t *ksp, int rw); 937c478bd9Sstevel@tonic-gate static int llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo); 947c478bd9Sstevel@tonic-gate static int llc1_unbind(queue_t *q, mblk_t *mp); 957c478bd9Sstevel@tonic-gate static int llc1_subs_bind(queue_t *q, mblk_t *mp); 967c478bd9Sstevel@tonic-gate static int llc1_unitdata(queue_t *q, mblk_t *mp); 977c478bd9Sstevel@tonic-gate static int llc1_inforeq(queue_t *q, mblk_t *mp); 987c478bd9Sstevel@tonic-gate static int llc1attach(queue_t *q, mblk_t *mp); 997c478bd9Sstevel@tonic-gate static void llc1_send_bindreq(llc_mac_info_t *macinfo); 1007c478bd9Sstevel@tonic-gate static int llc1_req_info(queue_t *q); 1017c478bd9Sstevel@tonic-gate static int llc1_cmds(queue_t *q, mblk_t *mp); 1027c478bd9Sstevel@tonic-gate static int llc1_setppa(struct ll_snioc *snioc); 1037c478bd9Sstevel@tonic-gate static int llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc); 1047c478bd9Sstevel@tonic-gate static int llc1_bind(queue_t *q, mblk_t *mp); 1057c478bd9Sstevel@tonic-gate static int llc1unattach(queue_t *q, mblk_t *mp); 1067c478bd9Sstevel@tonic-gate static int llc1_enable_multi(queue_t *q, mblk_t *mp); 1077c478bd9Sstevel@tonic-gate static int llc1_disable_multi(queue_t *q, mblk_t *mp); 1087c478bd9Sstevel@tonic-gate static int llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res); 1097c478bd9Sstevel@tonic-gate static int llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res); 1107c478bd9Sstevel@tonic-gate static int llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo); 1117c478bd9Sstevel@tonic-gate static int llc1_snap_match(llc1_t *lld, struct snaphdr *snap); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * the standard streams glue for defining the type of streams entity and the 1157c478bd9Sstevel@tonic-gate * operational parameters. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static struct module_info llc1_minfo = { 1197c478bd9Sstevel@tonic-gate LLC1IDNUM, 1207c478bd9Sstevel@tonic-gate "llc1", 1217c478bd9Sstevel@tonic-gate 0, 1227c478bd9Sstevel@tonic-gate LLC1_DEFMAX, 1237c478bd9Sstevel@tonic-gate LLC1_HIWATER, /* high water mark */ 1247c478bd9Sstevel@tonic-gate LLC1_LOWATER, /* low water mark */ 1257c478bd9Sstevel@tonic-gate }; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static struct qinit llc1_rint = { 1287c478bd9Sstevel@tonic-gate NULL, 1297c478bd9Sstevel@tonic-gate NULL, 1307c478bd9Sstevel@tonic-gate llc1_open, 1317c478bd9Sstevel@tonic-gate llc1_close, 1327c478bd9Sstevel@tonic-gate NULL, 1337c478bd9Sstevel@tonic-gate &llc1_minfo, 1347c478bd9Sstevel@tonic-gate NULL 1357c478bd9Sstevel@tonic-gate }; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static struct qinit llc1_wint = { 1387c478bd9Sstevel@tonic-gate llc1_uwput, 1397c478bd9Sstevel@tonic-gate llc1_uwsrv, 1407c478bd9Sstevel@tonic-gate NULL, 1417c478bd9Sstevel@tonic-gate NULL, 1427c478bd9Sstevel@tonic-gate NULL, 1437c478bd9Sstevel@tonic-gate &llc1_minfo, 1447c478bd9Sstevel@tonic-gate NULL 1457c478bd9Sstevel@tonic-gate }; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static struct qinit llc1_muxrint = { 1487c478bd9Sstevel@tonic-gate putq, 1497c478bd9Sstevel@tonic-gate llc1_lrsrv, 1507c478bd9Sstevel@tonic-gate NULL, 1517c478bd9Sstevel@tonic-gate NULL, 1527c478bd9Sstevel@tonic-gate NULL, 1537c478bd9Sstevel@tonic-gate &llc1_minfo, 1547c478bd9Sstevel@tonic-gate NULL 1557c478bd9Sstevel@tonic-gate }; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static struct qinit llc1_muxwint = { 1587c478bd9Sstevel@tonic-gate NULL, 1597c478bd9Sstevel@tonic-gate NULL, 1607c478bd9Sstevel@tonic-gate NULL, 1617c478bd9Sstevel@tonic-gate NULL, 1627c478bd9Sstevel@tonic-gate NULL, 1637c478bd9Sstevel@tonic-gate &llc1_minfo, 1647c478bd9Sstevel@tonic-gate NULL 1657c478bd9Sstevel@tonic-gate }; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate struct streamtab llc1_info = { 1687c478bd9Sstevel@tonic-gate &llc1_rint, 1697c478bd9Sstevel@tonic-gate &llc1_wint, 1707c478bd9Sstevel@tonic-gate &llc1_muxrint, 1717c478bd9Sstevel@tonic-gate &llc1_muxwint 1727c478bd9Sstevel@tonic-gate }; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * loadable module/driver wrapper this allows llc1 to be unloaded later 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate #if !defined(BUILD_STATIC) 1797c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* define the "ops" structure for a STREAMS driver */ 1827c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(llc1_ops, nulldev, nulldev, llc1_attach, 183*19397407SSherry Moore llc1_detach, nodev, llc1_getinfo, D_MP | D_MTPERMOD, &llc1_info, 184*19397407SSherry Moore ddi_quiesce_not_supported); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1907c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 191*19397407SSherry Moore "LLC Class 1 Driver", 1927c478bd9Sstevel@tonic-gate &llc1_ops, /* driver ops */ 1937c478bd9Sstevel@tonic-gate }; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1967c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1977c478bd9Sstevel@tonic-gate }; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate int 2007c478bd9Sstevel@tonic-gate _init(void) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate int 2067c478bd9Sstevel@tonic-gate _fini(void) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate int 2127c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate #endif 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 2207c478bd9Sstevel@tonic-gate extern int llc1_debug = 0x0; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate #endif 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Allocate and zero-out "number" structures each of type "structure" in 2267c478bd9Sstevel@tonic-gate * kernel memory. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate #define GETSTRUCT(structure, number) \ 2297c478bd9Sstevel@tonic-gate (kmem_zalloc(sizeof (structure) * (number), KM_NOSLEEP)) 2307c478bd9Sstevel@tonic-gate #define GETBUF(structure, size) \ 2317c478bd9Sstevel@tonic-gate (kmem_zalloc(size, KM_NOSLEEP)) 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate static struct llc1device llc1_device_list; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * llc1_attach - init time attach support When the hardware specific attach 2377c478bd9Sstevel@tonic-gate * is called, it must call this procedure with the device class structure 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static int 2417c478bd9Sstevel@tonic-gate llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * there isn't any hardware but we do need to initialize things 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate if (!(llc1_device_list.llc1_status & LLC1_ATTACHED)) { 2507c478bd9Sstevel@tonic-gate llc1_device_list.llc1_status |= LLC1_ATTACHED; 2517c478bd9Sstevel@tonic-gate rw_init(&llc1_device_list.llc1_rwlock, NULL, RW_DRIVER, NULL); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* make sure minor device lists are initialized */ 2547c478bd9Sstevel@tonic-gate llc1_device_list.llc1_str_next = 2557c478bd9Sstevel@tonic-gate llc1_device_list.llc1_str_prev = 2567c478bd9Sstevel@tonic-gate (llc1_t *)&llc1_device_list.llc1_str_next; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* make sure device list is initialized */ 2597c478bd9Sstevel@tonic-gate llc1_device_list.llc1_mac_next = 2607c478bd9Sstevel@tonic-gate llc1_device_list.llc1_mac_prev = 2617c478bd9Sstevel@tonic-gate (llc_mac_info_t *)&llc1_device_list.llc1_mac_next; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * now do all the DDI stuff necessary 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate ddi_set_driver_private(devinfo, &llc1_device_list); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * create the file system device node 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devinfo, "llc1", S_IFCHR, 2747c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) { 2757c478bd9Sstevel@tonic-gate llc1error(devinfo, "ddi_create_minor_node failed"); 2767c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devinfo, NULL); 2777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate llc1_device_list.llc1_multisize = ddi_getprop(DDI_DEV_T_NONE, 2807c478bd9Sstevel@tonic-gate devinfo, 0, "multisize", 0); 2817c478bd9Sstevel@tonic-gate if (llc1_device_list.llc1_multisize == 0) 2827c478bd9Sstevel@tonic-gate llc1_device_list.llc1_multisize = LLC1_MAX_MULTICAST; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate ddi_report_dev(devinfo); 2857c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * llc1_detach standard kernel interface routine 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate static int 2937c478bd9Sstevel@tonic-gate llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) { 2967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate if (llc1_device_list.llc1_ndevice > 0) 2997c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3007c478bd9Sstevel@tonic-gate /* remove all mutex and locks */ 3017c478bd9Sstevel@tonic-gate rw_destroy(&llc1_device_list.llc1_rwlock); 3027c478bd9Sstevel@tonic-gate llc1_device_list.llc1_status = 0; /* no longer attached */ 3037c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 3047c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * llc1_devinfo(dev, cmd, arg, result) standard kernel devinfo lookup 3097c478bd9Sstevel@tonic-gate * function 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 3127c478bd9Sstevel@tonic-gate static int 3137c478bd9Sstevel@tonic-gate llc1_getinfo(dev_info_t *dev, ddi_info_cmd_t cmd, void *arg, void **result) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate int error; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate switch (cmd) { 3187c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 3197c478bd9Sstevel@tonic-gate if (dev == NULL) { 3207c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 3217c478bd9Sstevel@tonic-gate } else { 3227c478bd9Sstevel@tonic-gate *result = (void *)dev; 3237c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate break; 3267c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 3277c478bd9Sstevel@tonic-gate *result = (void *)0; 3287c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 3297c478bd9Sstevel@tonic-gate break; 3307c478bd9Sstevel@tonic-gate default: 3317c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate return (error); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * llc1_open() 3387c478bd9Sstevel@tonic-gate * LLC1 open routine, called when device is opened by the user 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 3427c478bd9Sstevel@tonic-gate static int 3437c478bd9Sstevel@tonic-gate llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate llc1_t *llc1; 3467c478bd9Sstevel@tonic-gate minor_t minordev; 3477c478bd9Sstevel@tonic-gate int status = 0; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate ASSERT(q); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Stream already open, sucess. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if (q->q_ptr) 3557c478bd9Sstevel@tonic-gate return (0); 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * Serialize access through open/close this will serialize across all 3587c478bd9Sstevel@tonic-gate * llc1 devices, but open and close are not frequent so should not 3597c478bd9Sstevel@tonic-gate * induce much, if any delay. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (sflag == CLONEOPEN) { 3647c478bd9Sstevel@tonic-gate /* need to find a minor dev */ 3657c478bd9Sstevel@tonic-gate minordev = llc1_findminor(&llc1_device_list); 3667c478bd9Sstevel@tonic-gate if (minordev == 0) { 3677c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 3687c478bd9Sstevel@tonic-gate return (ENXIO); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), minordev); 3717c478bd9Sstevel@tonic-gate } else { 3727c478bd9Sstevel@tonic-gate minordev = getminor (*dev); 3737c478bd9Sstevel@tonic-gate if ((minordev > MAXMIN32) || (minordev == 0)) { 3747c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 3757c478bd9Sstevel@tonic-gate return (ENXIO); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * get a per-stream structure and link things together so we 3817c478bd9Sstevel@tonic-gate * can easily find them later. 3827c478bd9Sstevel@tonic-gate */ 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate llc1 = kmem_zalloc(sizeof (llc1_t), KM_SLEEP); 3857c478bd9Sstevel@tonic-gate llc1->llc_qptr = q; 3867c478bd9Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)llc1; 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * fill in the structure and state info 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate llc1->llc_state = DL_UNATTACHED; 3917c478bd9Sstevel@tonic-gate llc1->llc_style = DL_STYLE2; 3927c478bd9Sstevel@tonic-gate llc1->llc_minor = minordev; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate mutex_init(&llc1->llc_lock, NULL, MUTEX_DRIVER, NULL); 3957c478bd9Sstevel@tonic-gate llc1insque(llc1, llc1_device_list.llc1_str_prev); 3967c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 3977c478bd9Sstevel@tonic-gate qprocson(q); /* start the queues running */ 3987c478bd9Sstevel@tonic-gate return (status); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * llc1_close(q) 4037c478bd9Sstevel@tonic-gate * normal stream close call checks current status and cleans up 4047c478bd9Sstevel@tonic-gate * data structures that were dynamically allocated 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 4077c478bd9Sstevel@tonic-gate static int 4087c478bd9Sstevel@tonic-gate llc1_close(queue_t *q, int flag, cred_t *cred) 4097c478bd9Sstevel@tonic-gate { 4107c478bd9Sstevel@tonic-gate llc1_t *llc1; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate ASSERT(q); 4137c478bd9Sstevel@tonic-gate ASSERT(q->q_ptr); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate qprocsoff(q); 4167c478bd9Sstevel@tonic-gate llc1 = (llc1_t *)q->q_ptr; 4177c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 4187c478bd9Sstevel@tonic-gate /* completely disassociate the stream from the device */ 4197c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate (void) llc1remque(llc1); /* remove from active list */ 4227c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate mutex_enter(&llc1->llc_lock); 4257c478bd9Sstevel@tonic-gate if (llc1->llc_state == DL_IDLE || llc1->llc_state == DL_UNBOUND) { 4267c478bd9Sstevel@tonic-gate llc1->llc_state = DL_UNBOUND; /* force the issue */ 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate if (llc1->llc_mcast != NULL) { 4307c478bd9Sstevel@tonic-gate int i; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) { 4337c478bd9Sstevel@tonic-gate llc_mcast_t *mcast; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if ((mcast = llc1->llc_mcast[i]) != NULL) { 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * disable from stream and possibly 4387c478bd9Sstevel@tonic-gate * lower stream 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate if (llc1->llc_mac_info && 4417c478bd9Sstevel@tonic-gate llc1->llc_mac_info->llcp_flags & 4427c478bd9Sstevel@tonic-gate LLC1_AVAILABLE) 4437c478bd9Sstevel@tonic-gate llc1_send_disable_multi( 4447c478bd9Sstevel@tonic-gate llc1->llc_mac_info, 4457c478bd9Sstevel@tonic-gate mcast); 4467c478bd9Sstevel@tonic-gate llc1->llc_mcast[i] = NULL; 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate kmem_free(llc1->llc_mcast, 4507c478bd9Sstevel@tonic-gate sizeof (llc_mcast_t *) * llc1->llc_multicnt); 4517c478bd9Sstevel@tonic-gate llc1->llc_mcast = NULL; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate llc1->llc_state = DL_UNATTACHED; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate mutex_exit(&llc1->llc_lock); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate mutex_destroy(&llc1->llc_lock); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate kmem_free(llc1, sizeof (llc1_t)); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate return (0); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * llc1_uwput() 4667c478bd9Sstevel@tonic-gate * general llc stream write put routine. Receives ioctl's from 4677c478bd9Sstevel@tonic-gate * user level and data from upper modules and processes them immediately. 4687c478bd9Sstevel@tonic-gate * M_PROTO/M_PCPROTO are queued for later processing by the service 4697c478bd9Sstevel@tonic-gate * procedure. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate static int 4737c478bd9Sstevel@tonic-gate llc1_uwput(queue_t *q, mblk_t *mp) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate llc1_t *ld = (llc1_t *)(q->q_ptr); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 4787c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 4797c478bd9Sstevel@tonic-gate printf("llc1_wput(%x %x): type %d\n", q, mp, DB_TYPE(mp)); 4807c478bd9Sstevel@tonic-gate #endif 4817c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate case M_IOCTL: /* no waiting in ioctl's */ 4847c478bd9Sstevel@tonic-gate (void) llc1_ioctl(q, mp); 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate case M_FLUSH: /* canonical flush handling */ 4887c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 4897c478bd9Sstevel@tonic-gate flushq(q, 0); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4927c478bd9Sstevel@tonic-gate flushq(RD(q), 0); 4937c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 4947c478bd9Sstevel@tonic-gate qreply(q, mp); 4957c478bd9Sstevel@tonic-gate } else 4967c478bd9Sstevel@tonic-gate freemsg(mp); 4977c478bd9Sstevel@tonic-gate break; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* for now, we will always queue */ 5007c478bd9Sstevel@tonic-gate case M_PROTO: 5017c478bd9Sstevel@tonic-gate case M_PCPROTO: 5027c478bd9Sstevel@tonic-gate (void) putq(q, mp); 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate case M_DATA: 5067c478bd9Sstevel@tonic-gate /* fast data / raw support */ 5077c478bd9Sstevel@tonic-gate if ((ld->llc_flags & (LLC_RAW | LLC_FAST)) == 0 || 5087c478bd9Sstevel@tonic-gate ld->llc_state != DL_IDLE) { 5097c478bd9Sstevel@tonic-gate (void) merror(q, mp, EPROTO); 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate /* need to do further checking */ 5137c478bd9Sstevel@tonic-gate (void) putq(q, mp); 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate default: 5177c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 5187c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 5197c478bd9Sstevel@tonic-gate printf("llc1: Unexpected packet type from queue: %d\n", 5207c478bd9Sstevel@tonic-gate mp->b_datap->db_type); 5217c478bd9Sstevel@tonic-gate #endif 5227c478bd9Sstevel@tonic-gate freemsg(mp); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate return (0); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* 5287c478bd9Sstevel@tonic-gate * llc1_lrsrv() 5297c478bd9Sstevel@tonic-gate * called when data is put into the service queue from below. 5307c478bd9Sstevel@tonic-gate * Determines additional processing that might be needed and sends the data 5317c478bd9Sstevel@tonic-gate * upstream in the form of a Data Indication packet. 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate static int 5347c478bd9Sstevel@tonic-gate llc1_lrsrv(queue_t *q) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate mblk_t *mp; 5377c478bd9Sstevel@tonic-gate union DL_primitives *prim; 5387c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo = (llc_mac_info_t *)q->q_ptr; 5397c478bd9Sstevel@tonic-gate struct iocblk *iocp; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 5427c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 5437c478bd9Sstevel@tonic-gate printf("llc1_rsrv(%x)\n", q); 5447c478bd9Sstevel@tonic-gate if (llc1_debug & LLCRECV) { 5457c478bd9Sstevel@tonic-gate printf("llc1_lrsrv: q=%x macinfo=%x", q, macinfo); 5467c478bd9Sstevel@tonic-gate if (macinfo == NULL) { 5477c478bd9Sstevel@tonic-gate printf("NULL macinfo"); 5487c478bd9Sstevel@tonic-gate panic("null macinfo in lrsrv"); 5497c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate printf("\n"); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate #endif 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate /* 5567c478bd9Sstevel@tonic-gate * determine where message goes, then call the proper handler 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 5607c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 5617c478bd9Sstevel@tonic-gate case M_PROTO: 5627c478bd9Sstevel@tonic-gate case M_PCPROTO: 5637c478bd9Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr; 5647c478bd9Sstevel@tonic-gate /* only some primitives ever get passed through */ 5657c478bd9Sstevel@tonic-gate switch (prim->dl_primitive) { 5667c478bd9Sstevel@tonic-gate case DL_INFO_ACK: 5677c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_LINKED) { 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * we are in the midst of completing 5707c478bd9Sstevel@tonic-gate * the I_LINK/I_PLINK and needed this 5717c478bd9Sstevel@tonic-gate * info 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_LINKED; 5747c478bd9Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_AVAILABLE; 5757c478bd9Sstevel@tonic-gate macinfo->llcp_maxpkt = 5767c478bd9Sstevel@tonic-gate prim->info_ack.dl_max_sdu; 5777c478bd9Sstevel@tonic-gate macinfo->llcp_minpkt = 5787c478bd9Sstevel@tonic-gate prim->info_ack.dl_min_sdu; 5797c478bd9Sstevel@tonic-gate macinfo->llcp_type = 5807c478bd9Sstevel@tonic-gate prim->info_ack.dl_mac_type; 5817c478bd9Sstevel@tonic-gate if (macinfo->llcp_type == DL_ETHER) { 5827c478bd9Sstevel@tonic-gate macinfo->llcp_type = DL_CSMACD; 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * size of max header 5857c478bd9Sstevel@tonic-gate * (including SNAP) 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate macinfo->llcp_maxpkt -= 8; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen = 5907c478bd9Sstevel@tonic-gate prim->info_ack.dl_addr_length - 5917c478bd9Sstevel@tonic-gate ABS(prim->info_ack.dl_sap_length); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + 5947c478bd9Sstevel@tonic-gate prim->info_ack.dl_addr_offset, 5957c478bd9Sstevel@tonic-gate macinfo->llcp_macaddr, 5967c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 5977c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + 598*19397407SSherry Moore prim->info_ack. 599*19397407SSherry Moore dl_brdcst_addr_offset, 6007c478bd9Sstevel@tonic-gate macinfo->llcp_broadcast, 601*19397407SSherry Moore prim->info_ack. 602*19397407SSherry Moore dl_brdcst_addr_length); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (prim->info_ack.dl_current_state == 6057c478bd9Sstevel@tonic-gate DL_UNBOUND) 6067c478bd9Sstevel@tonic-gate llc1_send_bindreq(macinfo); 6077c478bd9Sstevel@tonic-gate freemsg(mp); 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * need to put the lower stream into 6107c478bd9Sstevel@tonic-gate * DLRAW mode. Currently only DL_ETHER 6117c478bd9Sstevel@tonic-gate * or DL_CSMACD 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate switch (macinfo->llcp_type) { 6147c478bd9Sstevel@tonic-gate case DL_ETHER: 6157c478bd9Sstevel@tonic-gate case DL_CSMACD: 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * raw mode is optimal so ask 6187c478bd9Sstevel@tonic-gate * for it * we might not get 6197c478bd9Sstevel@tonic-gate * it but that's OK 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate llc1_req_raw(macinfo); 6227c478bd9Sstevel@tonic-gate break; 6237c478bd9Sstevel@tonic-gate default: 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * don't want raw mode so don't 6267c478bd9Sstevel@tonic-gate * ask for it 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate break; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate } else { 6317c478bd9Sstevel@tonic-gate if (prim->info_ack.dl_current_state == 6327c478bd9Sstevel@tonic-gate DL_IDLE) 6337c478bd9Sstevel@tonic-gate /* address was wrong before */ 6347c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + 6357c478bd9Sstevel@tonic-gate prim->info_ack.dl_addr_offset, 6367c478bd9Sstevel@tonic-gate macinfo->llcp_macaddr, 6377c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 6387c478bd9Sstevel@tonic-gate freemsg(mp); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate case DL_BIND_ACK: 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * if we had to bind, the macaddr is wrong 6447c478bd9Sstevel@tonic-gate * so get it again 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate freemsg(mp); 6477c478bd9Sstevel@tonic-gate (void) llc1_req_info(q); 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate case DL_UNITDATA_IND: 6507c478bd9Sstevel@tonic-gate /* when not using raw mode we get these */ 6517c478bd9Sstevel@tonic-gate (void) llc1_recv(macinfo, mp); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate case DL_ERROR_ACK: 6547c478bd9Sstevel@tonic-gate /* binding is a special case */ 6557c478bd9Sstevel@tonic-gate if (prim->error_ack.dl_error_primitive == 6567c478bd9Sstevel@tonic-gate DL_BIND_REQ) { 6577c478bd9Sstevel@tonic-gate freemsg(mp); 6587c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_BINDING) 6597c478bd9Sstevel@tonic-gate llc1_send_bindreq(macinfo); 6607c478bd9Sstevel@tonic-gate } else 6617c478bd9Sstevel@tonic-gate llc1_find_waiting(macinfo, mp, 6627c478bd9Sstevel@tonic-gate prim->error_ack.dl_error_primitive); 6637c478bd9Sstevel@tonic-gate break; 6647c478bd9Sstevel@tonic-gate case DL_PHYS_ADDR_ACK: 6657c478bd9Sstevel@tonic-gate llc1_find_waiting(macinfo, mp, 6667c478bd9Sstevel@tonic-gate DL_PHYS_ADDR_REQ); 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate case DL_OK_ACK: 6697c478bd9Sstevel@tonic-gate if (prim->ok_ack.dl_correct_primitive == 6707c478bd9Sstevel@tonic-gate DL_BIND_REQ) 6717c478bd9Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_BINDING; 6727c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 6737c478bd9Sstevel@tonic-gate default: 6747c478bd9Sstevel@tonic-gate freemsg(mp); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate break; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate case M_IOCACK: 6797c478bd9Sstevel@tonic-gate /* probably our DLIOCRAW completing */ 6807c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6817c478bd9Sstevel@tonic-gate if ((macinfo->llcp_flags & LLC1_RAW_WAIT) && 6827c478bd9Sstevel@tonic-gate macinfo->llcp_iocid == iocp->ioc_id) { 6837c478bd9Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_RAW_WAIT; 6847c478bd9Sstevel@tonic-gate /* we can use this form */ 6857c478bd9Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_USING_RAW; 6867c478bd9Sstevel@tonic-gate freemsg(mp); 6877c478bd9Sstevel@tonic-gate break; 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate /* need to find the correct queue */ 6907c478bd9Sstevel@tonic-gate freemsg(mp); 6917c478bd9Sstevel@tonic-gate break; 6927c478bd9Sstevel@tonic-gate case M_IOCNAK: 6937c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6947c478bd9Sstevel@tonic-gate if ((macinfo->llcp_flags & LLC1_RAW_WAIT) && 6957c478bd9Sstevel@tonic-gate macinfo->llcp_iocid == iocp->ioc_id) { 6967c478bd9Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_RAW_WAIT; 6977c478bd9Sstevel@tonic-gate freemsg(mp); 6987c478bd9Sstevel@tonic-gate break; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate /* need to find the correct queue */ 7017c478bd9Sstevel@tonic-gate freemsg(mp); 7027c478bd9Sstevel@tonic-gate break; 7037c478bd9Sstevel@tonic-gate case M_DATA: 7047c478bd9Sstevel@tonic-gate llc1_recv(macinfo, mp); 7057c478bd9Sstevel@tonic-gate break; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate return (0); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * llc1_uwsrv - Incoming messages are processed according to the DLPI 7137c478bd9Sstevel@tonic-gate * protocol specification 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate static int 7177c478bd9Sstevel@tonic-gate llc1_uwsrv(queue_t *q) 7187c478bd9Sstevel@tonic-gate { 7197c478bd9Sstevel@tonic-gate mblk_t *mp; 7207c478bd9Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr; 7217c478bd9Sstevel@tonic-gate union DL_primitives *prim; 7227c478bd9Sstevel@tonic-gate int err; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 7257c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 7267c478bd9Sstevel@tonic-gate printf("llc1_wsrv(%x)\n", q); 7277c478bd9Sstevel@tonic-gate #endif 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 7317c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 7327c478bd9Sstevel@tonic-gate case M_PROTO: /* Will be an DLPI message of some type */ 7337c478bd9Sstevel@tonic-gate case M_PCPROTO: 7347c478bd9Sstevel@tonic-gate if ((err = llc1_cmds(q, mp)) != LLCE_OK) { 7357c478bd9Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr; 7367c478bd9Sstevel@tonic-gate if (err == LLCE_NOBUFFER || err == DL_SYSERR) { 7377c478bd9Sstevel@tonic-gate /* quit while we're ahead */ 7387c478bd9Sstevel@tonic-gate lld->llc_stats->llcs_nobuffer++; 7397c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 7407c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 7417c478bd9Sstevel@tonic-gate printf( 7427c478bd9Sstevel@tonic-gate "llc1_cmds: nonfatal err=%d\n", 7437c478bd9Sstevel@tonic-gate err); 7447c478bd9Sstevel@tonic-gate #endif 7457c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 7467c478bd9Sstevel@tonic-gate return (0); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate } else { 7497c478bd9Sstevel@tonic-gate dlerrorack(q, mp, 7507c478bd9Sstevel@tonic-gate prim->dl_primitive, 7517c478bd9Sstevel@tonic-gate err, 0); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate case M_DATA: 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * retry of a previously processed 7587c478bd9Sstevel@tonic-gate * UNITDATA_REQ or is a RAW message from 7597c478bd9Sstevel@tonic-gate * above 7607c478bd9Sstevel@tonic-gate */ 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate mutex_enter(&lld->llc_lock); 7637c478bd9Sstevel@tonic-gate putnext(lld->llc_mac_info->llcp_queue, mp); 7647c478bd9Sstevel@tonic-gate mutex_exit(&lld->llc_lock); 7657c478bd9Sstevel@tonic-gate freemsg(mp); /* free on success */ 7667c478bd9Sstevel@tonic-gate break; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* This should never happen */ 7697c478bd9Sstevel@tonic-gate default: 7707c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 7717c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 7727c478bd9Sstevel@tonic-gate printf("llc1_wsrv: type(%x) not supported\n", 7737c478bd9Sstevel@tonic-gate mp->b_datap->db_type); 7747c478bd9Sstevel@tonic-gate #endif 7757c478bd9Sstevel@tonic-gate freemsg(mp); /* unknown types are discarded */ 7767c478bd9Sstevel@tonic-gate break; 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate return (0); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * llc1_multicast used to determine if the address is a multicast address for 7847c478bd9Sstevel@tonic-gate * this user. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate int 7877c478bd9Sstevel@tonic-gate llc1_multicast(struct ether_addr *addr, llc1_t *lld) 7887c478bd9Sstevel@tonic-gate { 7897c478bd9Sstevel@tonic-gate int i; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (lld->llc_mcast) 7927c478bd9Sstevel@tonic-gate for (i = 0; i < lld->llc_multicnt; i++) 7937c478bd9Sstevel@tonic-gate if (lld->llc_mcast[i] && 7947c478bd9Sstevel@tonic-gate lld->llc_mcast[i]->llcm_refcnt && 7957c478bd9Sstevel@tonic-gate bcmp(lld->llc_mcast[i]->llcm_addr, 7967c478bd9Sstevel@tonic-gate addr->ether_addr_octet, ETHERADDRL) == 0) 7977c478bd9Sstevel@tonic-gate return (1); 7987c478bd9Sstevel@tonic-gate return (0); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * llc1_ioctl handles all ioctl requests passed downstream. This routine is 8037c478bd9Sstevel@tonic-gate * passed a pointer to the message block with the ioctl request in it, and a 8047c478bd9Sstevel@tonic-gate * pointer to the queue so it can respond to the ioctl request with an ack. 8057c478bd9Sstevel@tonic-gate */ 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate int llc1_doreqinfo; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate static void 8107c478bd9Sstevel@tonic-gate llc1_ioctl(queue_t *q, mblk_t *mp) 8117c478bd9Sstevel@tonic-gate { 8127c478bd9Sstevel@tonic-gate struct iocblk *iocp; 8137c478bd9Sstevel@tonic-gate llc1_t *lld; 8147c478bd9Sstevel@tonic-gate struct linkblk *link; 8157c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 8167c478bd9Sstevel@tonic-gate mblk_t *tmp; 8177c478bd9Sstevel@tonic-gate int error; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 8207c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 8217c478bd9Sstevel@tonic-gate printf("llc1_ioctl(%x %x)\n", q, mp); 8227c478bd9Sstevel@tonic-gate #endif 8237c478bd9Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr; 8247c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 8257c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 8267c478bd9Sstevel@tonic-gate /* XXX need to lock the data structures */ 8277c478bd9Sstevel@tonic-gate case I_PLINK: 8287c478bd9Sstevel@tonic-gate case I_LINK: 8297c478bd9Sstevel@tonic-gate link = (struct linkblk *)mp->b_cont->b_rptr; 8307c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (llc_mac_info_t), BPRI_MED); 8317c478bd9Sstevel@tonic-gate if (tmp == NULL) { 8327c478bd9Sstevel@tonic-gate (void) miocnak(q, mp, 0, ENOSR); 8337c478bd9Sstevel@tonic-gate return; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate bzero(tmp->b_rptr, sizeof (llc_mac_info_t)); 8367c478bd9Sstevel@tonic-gate macinfo = (llc_mac_info_t *)tmp->b_rptr; 8377c478bd9Sstevel@tonic-gate macinfo->llcp_mb = tmp; 8387c478bd9Sstevel@tonic-gate macinfo->llcp_next = macinfo->llcp_prev = macinfo; 8397c478bd9Sstevel@tonic-gate macinfo->llcp_queue = link->l_qbot; 8407c478bd9Sstevel@tonic-gate macinfo->llcp_lindex = link->l_index; 8417c478bd9Sstevel@tonic-gate /* tentative */ 8427c478bd9Sstevel@tonic-gate macinfo->llcp_ppa = --llc1_device_list.llc1_nextppa; 8437c478bd9Sstevel@tonic-gate llc1_device_list.llc1_ndevice++; 8447c478bd9Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_LINKED | LLC1_DEF_PPA; 8457c478bd9Sstevel@tonic-gate macinfo->llcp_lqtop = q; 8467c478bd9Sstevel@tonic-gate macinfo->llcp_data = NULL; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* need to do an info_req before an info_req or attach */ 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 8517c478bd9Sstevel@tonic-gate llc1insque(macinfo, llc1_device_list.llc1_mac_prev); 8527c478bd9Sstevel@tonic-gate macinfo->llcp_queue->q_ptr = RD(macinfo->llcp_queue)->q_ptr = 8537c478bd9Sstevel@tonic-gate (caddr_t)macinfo; 8547c478bd9Sstevel@tonic-gate llc1_init_kstat(macinfo); 8557c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* initiate getting the info */ 8587c478bd9Sstevel@tonic-gate (void) llc1_req_info(macinfo->llcp_queue); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 8617c478bd9Sstevel@tonic-gate return; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate case I_PUNLINK: 8647c478bd9Sstevel@tonic-gate case I_UNLINK: 8657c478bd9Sstevel@tonic-gate link = (struct linkblk *)mp->b_cont->b_rptr; 8667c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 8677c478bd9Sstevel@tonic-gate for (macinfo = llc1_device_list.llc1_mac_next; 8687c478bd9Sstevel@tonic-gate macinfo != NULL && 8697c478bd9Sstevel@tonic-gate macinfo != 8707c478bd9Sstevel@tonic-gate (llc_mac_info_t *)&llc1_device_list.llc1_mac_next; 8717c478bd9Sstevel@tonic-gate macinfo = macinfo->llcp_next) { 8727c478bd9Sstevel@tonic-gate if (macinfo->llcp_lindex == link->l_index && 8737c478bd9Sstevel@tonic-gate macinfo->llcp_queue == link->l_qbot) { 8747c478bd9Sstevel@tonic-gate /* found it */ 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate ASSERT(macinfo->llcp_next); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* remove from device list */ 8797c478bd9Sstevel@tonic-gate llc1_device_list.llc1_ndevice--; 8807c478bd9Sstevel@tonic-gate llc1remque(macinfo); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* remove any mcast structs */ 8837c478bd9Sstevel@tonic-gate if (macinfo->llcp_mcast != NULL) { 8847c478bd9Sstevel@tonic-gate kmem_free(macinfo->llcp_mcast, 8857c478bd9Sstevel@tonic-gate sizeof (llc_mcast_t) * 8867c478bd9Sstevel@tonic-gate llc1_device_list.llc1_multisize); 8877c478bd9Sstevel@tonic-gate macinfo->llcp_mcast = NULL; 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* remove any kstat counters */ 8917c478bd9Sstevel@tonic-gate if (macinfo->llcp_kstatp != NULL) 8927c478bd9Sstevel@tonic-gate llc1_uninit_kstat(macinfo); 8937c478bd9Sstevel@tonic-gate if (macinfo->llcp_mb != NULL) 8947c478bd9Sstevel@tonic-gate freeb(macinfo->llcp_mb); 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate lld->llc_mac_info = NULL; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* finish any necessary setup */ 9017c478bd9Sstevel@tonic-gate if (llc1_device_list.llc1_ndevice == 0) 9027c478bd9Sstevel@tonic-gate llc1_device_list.llc1_nextppa = 0; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 9057c478bd9Sstevel@tonic-gate return; 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * what should really be done here -- force errors on all 9117c478bd9Sstevel@tonic-gate * streams? 9127c478bd9Sstevel@tonic-gate */ 9137c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 9147c478bd9Sstevel@tonic-gate return; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate case L_SETPPA: 9177c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ll_snioc)); 9187c478bd9Sstevel@tonic-gate if (error != 0) { 9197c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 9207c478bd9Sstevel@tonic-gate return; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (llc1_setppa((struct ll_snioc *)mp->b_cont->b_rptr) >= 0) { 9247c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 9257c478bd9Sstevel@tonic-gate return; 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 9287c478bd9Sstevel@tonic-gate return; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate case L_GETPPA: 9317c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) { 9327c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (struct ll_snioc), BPRI_MED); 9337c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) { 9347c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR); 9357c478bd9Sstevel@tonic-gate return; 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr = 9387c478bd9Sstevel@tonic-gate mp->b_cont->b_rptr + sizeof (struct ll_snioc); 9397c478bd9Sstevel@tonic-gate } else { 9407c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ll_snioc)); 9417c478bd9Sstevel@tonic-gate if (error != 0) { 9427c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 9437c478bd9Sstevel@tonic-gate return; 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr; 9487c478bd9Sstevel@tonic-gate if (llc1_getppa(lld->llc_mac_info, 9497c478bd9Sstevel@tonic-gate (struct ll_snioc *)mp->b_cont->b_rptr) >= 0) 9507c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0); 9517c478bd9Sstevel@tonic-gate else 9527c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 9537c478bd9Sstevel@tonic-gate return; 9547c478bd9Sstevel@tonic-gate default: 9557c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* 9607c478bd9Sstevel@tonic-gate * llc1_setppa(snioc) this function sets the real PPA number for a previously 9617c478bd9Sstevel@tonic-gate * I_LINKED stream. Be careful to select the macinfo struct associated 9627c478bd9Sstevel@tonic-gate * with our llc struct, to avoid erroneous references. 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate static int 9667c478bd9Sstevel@tonic-gate llc1_setppa(struct ll_snioc *snioc) 9677c478bd9Sstevel@tonic-gate { 9687c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate for (macinfo = llc1_device_list.llc1_mac_next; 9717c478bd9Sstevel@tonic-gate macinfo != (llc_mac_info_t *)&llc1_device_list.llc1_mac_next; 9727c478bd9Sstevel@tonic-gate macinfo = macinfo->llcp_next) 9737c478bd9Sstevel@tonic-gate if (macinfo->llcp_lindex == snioc->lli_index && 9747c478bd9Sstevel@tonic-gate (macinfo->llcp_flags & LLC1_DEF_PPA)) { 9757c478bd9Sstevel@tonic-gate macinfo->llcp_flags &= ~LLC1_DEF_PPA; 9767c478bd9Sstevel@tonic-gate macinfo->llcp_ppa = snioc->lli_ppa; 9777c478bd9Sstevel@tonic-gate return (0); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate return (-1); 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * llc1_getppa(macinfo, snioc) returns the PPA for this stream 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate static int 9867c478bd9Sstevel@tonic-gate llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc) 9877c478bd9Sstevel@tonic-gate { 9887c478bd9Sstevel@tonic-gate if (macinfo == NULL) 9897c478bd9Sstevel@tonic-gate return (-1); 9907c478bd9Sstevel@tonic-gate snioc->lli_ppa = macinfo->llcp_ppa; 9917c478bd9Sstevel@tonic-gate snioc->lli_index = macinfo->llcp_lindex; 9927c478bd9Sstevel@tonic-gate return (0); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* 9967c478bd9Sstevel@tonic-gate * llc1_cmds - process the DL commands as defined in dlpi.h 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate static int 9997c478bd9Sstevel@tonic-gate llc1_cmds(queue_t *q, mblk_t *mp) 10007c478bd9Sstevel@tonic-gate { 10017c478bd9Sstevel@tonic-gate union DL_primitives *dlp; 10027c478bd9Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr; 10037c478bd9Sstevel@tonic-gate int result = 0; 10047c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo = llc->llc_mac_info; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr; 10077c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 10087c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 10097c478bd9Sstevel@tonic-gate printf("llc1_cmds(%x, %x):dlp=%x, dlp->dl_primitive=%d\n", 10107c478bd9Sstevel@tonic-gate q, mp, dlp, dlp->dl_primitive); 10117c478bd9Sstevel@tonic-gate #endif 10127c478bd9Sstevel@tonic-gate mutex_enter(&llc->llc_lock); 10137c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_READER); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate switch (dlp->dl_primitive) { 10167c478bd9Sstevel@tonic-gate case DL_BIND_REQ: 10177c478bd9Sstevel@tonic-gate result = llc1_bind(q, mp); 10187c478bd9Sstevel@tonic-gate break; 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate case DL_UNBIND_REQ: 10217c478bd9Sstevel@tonic-gate result = llc1_unbind(q, mp); 10227c478bd9Sstevel@tonic-gate break; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate case DL_SUBS_BIND_REQ: 10257c478bd9Sstevel@tonic-gate result = llc1_subs_bind(q, mp); 10267c478bd9Sstevel@tonic-gate break; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate case DL_SUBS_UNBIND_REQ: 10297c478bd9Sstevel@tonic-gate result = llc1_subs_unbind(); 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate case DL_UNITDATA_REQ: 10337c478bd9Sstevel@tonic-gate result = llc1_unitdata(q, mp); 10347c478bd9Sstevel@tonic-gate break; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate case DL_INFO_REQ: 10377c478bd9Sstevel@tonic-gate result = llc1_inforeq(q, mp); 10387c478bd9Sstevel@tonic-gate break; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate case DL_ATTACH_REQ: 10417c478bd9Sstevel@tonic-gate result = llc1attach(q, mp); 10427c478bd9Sstevel@tonic-gate break; 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate case DL_DETACH_REQ: 10457c478bd9Sstevel@tonic-gate result = llc1unattach(q, mp); 10467c478bd9Sstevel@tonic-gate break; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate case DL_ENABMULTI_REQ: 10497c478bd9Sstevel@tonic-gate result = llc1_enable_multi(q, mp); 10507c478bd9Sstevel@tonic-gate break; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate case DL_DISABMULTI_REQ: 10537c478bd9Sstevel@tonic-gate result = llc1_disable_multi(q, mp); 10547c478bd9Sstevel@tonic-gate break; 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate case DL_XID_REQ: 10577c478bd9Sstevel@tonic-gate result = llc1_xid_req_res(q, mp, 0); 10587c478bd9Sstevel@tonic-gate break; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate case DL_XID_RES: 10617c478bd9Sstevel@tonic-gate result = llc1_xid_req_res(q, mp, 1); 10627c478bd9Sstevel@tonic-gate break; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate case DL_TEST_REQ: 10657c478bd9Sstevel@tonic-gate result = llc1_test_req_res(q, mp, 0); 10667c478bd9Sstevel@tonic-gate break; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate case DL_TEST_RES: 10697c478bd9Sstevel@tonic-gate result = llc1_test_req_res(q, mp, 1); 10707c478bd9Sstevel@tonic-gate break; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate case DL_SET_PHYS_ADDR_REQ: 10737c478bd9Sstevel@tonic-gate result = DL_NOTSUPPORTED; 10747c478bd9Sstevel@tonic-gate break; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate case DL_PHYS_ADDR_REQ: 10777c478bd9Sstevel@tonic-gate if (llc->llc_state != DL_UNATTACHED && macinfo) { 10787c478bd9Sstevel@tonic-gate llc->llc_waiting_for = dlp->dl_primitive; 10797c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), mp); 10807c478bd9Sstevel@tonic-gate result = LLCE_OK; 10817c478bd9Sstevel@tonic-gate } else { 10827c478bd9Sstevel@tonic-gate result = DL_OUTSTATE; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate break; 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate case DL_PROMISCON_REQ: 10877c478bd9Sstevel@tonic-gate case DL_PROMISCOFF_REQ: 10887c478bd9Sstevel@tonic-gate result = DL_NOTSUPPORTED; 10897c478bd9Sstevel@tonic-gate break; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate default: 10927c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 10937c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 10947c478bd9Sstevel@tonic-gate printf("llc1_cmds: Received unknown primitive: %d\n", 10957c478bd9Sstevel@tonic-gate dlp->dl_primitive); 10967c478bd9Sstevel@tonic-gate #endif 10977c478bd9Sstevel@tonic-gate result = DL_BADPRIM; 10987c478bd9Sstevel@tonic-gate break; 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 11017c478bd9Sstevel@tonic-gate mutex_exit(&llc->llc_lock); 11027c478bd9Sstevel@tonic-gate return (result); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * llc1_bind - determine if a SAP is already allocated and whether it is 11077c478bd9Sstevel@tonic-gate * legal to do the bind at this time 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate static int 11107c478bd9Sstevel@tonic-gate llc1_bind(queue_t *q, mblk_t *mp) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate int sap; 11137c478bd9Sstevel@tonic-gate dl_bind_req_t *dlp; 11147c478bd9Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr; 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate ASSERT(lld); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 11197c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 11207c478bd9Sstevel@tonic-gate printf("llc1_bind(%x %x)\n", q, mp); 11217c478bd9Sstevel@tonic-gate #endif 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate dlp = (dl_bind_req_t *)mp->b_rptr; 11247c478bd9Sstevel@tonic-gate sap = dlp->dl_sap; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 11277c478bd9Sstevel@tonic-gate if (llc1_debug & LLCPROT) 11287c478bd9Sstevel@tonic-gate printf("llc1_bind: lsap=%x\n", sap); 11297c478bd9Sstevel@tonic-gate #endif 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate if (lld->llc_mac_info == NULL) 11327c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate if (lld->llc_qptr && lld->llc_state != DL_UNBOUND) { 11357c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 11367c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 11377c478bd9Sstevel@tonic-gate printf("llc1_bind: stream bound/not attached (%d)\n", 11387c478bd9Sstevel@tonic-gate lld->llc_state); 11397c478bd9Sstevel@tonic-gate #endif 11407c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate if (dlp->dl_service_mode != DL_CLDLS || dlp->dl_max_conind != 0) { 11447c478bd9Sstevel@tonic-gate return (DL_UNSUPPORTED); 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * prohibit group saps. An exception is the broadcast sap which is, 11487c478bd9Sstevel@tonic-gate * unfortunately, used by SUNSelect to indicate Novell Netware in 11497c478bd9Sstevel@tonic-gate * 802.3 mode. Really should use a very non-802.2 SAP like 0xFFFF 11507c478bd9Sstevel@tonic-gate * or -2. 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate if (sap == 0 || (sap <= 0xFF && (sap & 1 && sap != 0xFF)) || 11547c478bd9Sstevel@tonic-gate sap > 0xFFFF) { 11557c478bd9Sstevel@tonic-gate return (DL_BADSAP); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate lld->llc_state = DL_BIND_PENDING; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* if we fall through, then the SAP is legal */ 11607c478bd9Sstevel@tonic-gate if (sap == 0xFF) { 11617c478bd9Sstevel@tonic-gate if (lld->llc_mac_info->llcp_type == DL_CSMACD) 11627c478bd9Sstevel@tonic-gate sap = LLC_NOVELL_SAP; 11637c478bd9Sstevel@tonic-gate else 11647c478bd9Sstevel@tonic-gate return (DL_BADSAP); 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate lld->llc_sap = sap; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate if (sap > 0xFF) { 11697c478bd9Sstevel@tonic-gate ushort_t snapsap = htons(sap); 11707c478bd9Sstevel@tonic-gate /* this is SNAP, so set things up */ 11717c478bd9Sstevel@tonic-gate lld->llc_snap[3] = ((uchar_t *)&snapsap)[0]; 11727c478bd9Sstevel@tonic-gate lld->llc_snap[4] = ((uchar_t *)&snapsap)[1]; 11737c478bd9Sstevel@tonic-gate /* mark as SNAP but allow OID to be added later */ 11747c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP; 11757c478bd9Sstevel@tonic-gate lld->llc_sap = LLC_SNAP_SAP; 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 11797c478bd9Sstevel@tonic-gate if (llc1_debug & LLCPROT) 11807c478bd9Sstevel@tonic-gate printf("llc1_bind: ok - type = %d\n", lld->llc_type); 11817c478bd9Sstevel@tonic-gate #endif 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate if (dlp->dl_xidtest_flg & DL_AUTO_XID) 11847c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC1_AUTO_XID; 11857c478bd9Sstevel@tonic-gate if (dlp->dl_xidtest_flg & DL_AUTO_TEST) 11867c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC1_AUTO_TEST; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* ACK the BIND, if possible */ 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate dlbindack(q, mp, sap, lld->llc_mac_info->llcp_macaddr, 6, 0, 0); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate lld->llc_state = DL_IDLE; /* bound and ready */ 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate return (LLCE_OK); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate /* 11987c478bd9Sstevel@tonic-gate * llc1_unbind - perform an unbind of an LSAP or ether type on the stream. 11997c478bd9Sstevel@tonic-gate * The stream is still open and can be re-bound. 12007c478bd9Sstevel@tonic-gate */ 12017c478bd9Sstevel@tonic-gate static int 12027c478bd9Sstevel@tonic-gate llc1_unbind(queue_t *q, mblk_t *mp) 12037c478bd9Sstevel@tonic-gate { 12047c478bd9Sstevel@tonic-gate llc1_t *lld; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 12077c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 12087c478bd9Sstevel@tonic-gate printf("llc1_unbind(%x %x)\n", q, mp); 12097c478bd9Sstevel@tonic-gate #endif 12107c478bd9Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (lld->llc_mac_info == NULL) 12137c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (lld->llc_state != DL_IDLE) { 12167c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 12177c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 12187c478bd9Sstevel@tonic-gate printf("llc1_unbind: wrong state (%d)\n", 12197c478bd9Sstevel@tonic-gate lld->llc_state); 12207c478bd9Sstevel@tonic-gate #endif 12217c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate lld->llc_state = DL_UNBIND_PENDING; 12247c478bd9Sstevel@tonic-gate lld->llc_flags &= ~(LLC_SNAP|LLC_SNAP_OID); /* just in case */ 12257c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_UNBIND_REQ); 12267c478bd9Sstevel@tonic-gate lld->llc_state = DL_UNBOUND; 12277c478bd9Sstevel@tonic-gate return (LLCE_OK); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * llc1_inforeq - generate the response to an info request 12327c478bd9Sstevel@tonic-gate */ 12337c478bd9Sstevel@tonic-gate static int 12347c478bd9Sstevel@tonic-gate llc1_inforeq(queue_t *q, mblk_t *mp) 12357c478bd9Sstevel@tonic-gate { 12367c478bd9Sstevel@tonic-gate llc1_t *lld; 12377c478bd9Sstevel@tonic-gate mblk_t *nmp; 12387c478bd9Sstevel@tonic-gate dl_info_ack_t *dlp; 12397c478bd9Sstevel@tonic-gate int bufsize; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 12427c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 12437c478bd9Sstevel@tonic-gate printf("llc1_inforeq(%x %x)\n", q, mp); 12447c478bd9Sstevel@tonic-gate #endif 12457c478bd9Sstevel@tonic-gate lld = (llc1_t *)q->q_ptr; 12467c478bd9Sstevel@tonic-gate ASSERT(lld); 12477c478bd9Sstevel@tonic-gate if (lld->llc_mac_info == NULL) 12487c478bd9Sstevel@tonic-gate bufsize = sizeof (dl_info_ack_t) + ETHERADDRL; 12497c478bd9Sstevel@tonic-gate else 12507c478bd9Sstevel@tonic-gate bufsize = sizeof (dl_info_ack_t) + 12517c478bd9Sstevel@tonic-gate 2 * lld->llc_mac_info->llcp_addrlen + 2; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate nmp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK); 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate if (nmp) { 12567c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_info_ack_t); 12577c478bd9Sstevel@tonic-gate dlp = (dl_info_ack_t *)nmp->b_rptr; 12587c478bd9Sstevel@tonic-gate bzero(dlp, DL_INFO_ACK_SIZE); 12597c478bd9Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK; 12607c478bd9Sstevel@tonic-gate if (lld->llc_mac_info) 12617c478bd9Sstevel@tonic-gate dlp->dl_max_sdu = lld->llc_mac_info->llcp_maxpkt; 12627c478bd9Sstevel@tonic-gate dlp->dl_min_sdu = 0; 12637c478bd9Sstevel@tonic-gate dlp->dl_mac_type = lld->llc_type; 12647c478bd9Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS; 12657c478bd9Sstevel@tonic-gate dlp->dl_current_state = lld->llc_state; 12667c478bd9Sstevel@tonic-gate dlp->dl_provider_style = 12677c478bd9Sstevel@tonic-gate (lld->llc_style == 0) ? lld->llc_style : DL_STYLE2; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* now append physical address */ 12707c478bd9Sstevel@tonic-gate if (lld->llc_mac_info) { 12717c478bd9Sstevel@tonic-gate dlp->dl_addr_length = lld->llc_mac_info->llcp_addrlen; 12727c478bd9Sstevel@tonic-gate dlp->dl_addr_offset = DL_INFO_ACK_SIZE; 12737c478bd9Sstevel@tonic-gate nmp->b_wptr += dlp->dl_addr_length + 1; 12747c478bd9Sstevel@tonic-gate bcopy(lld->llc_mac_info->llcp_macaddr, 12757c478bd9Sstevel@tonic-gate ((caddr_t)dlp) + dlp->dl_addr_offset, 12767c478bd9Sstevel@tonic-gate lld->llc_mac_info->llcp_addrlen); 12777c478bd9Sstevel@tonic-gate if (lld->llc_state == DL_IDLE) { 12787c478bd9Sstevel@tonic-gate dlp->dl_sap_length = -1; /* 1 byte on end */ 12797c478bd9Sstevel@tonic-gate *(((caddr_t)dlp) + dlp->dl_addr_offset + 12807c478bd9Sstevel@tonic-gate dlp->dl_addr_length) = lld->llc_sap; 12817c478bd9Sstevel@tonic-gate dlp->dl_addr_length += 1; 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate /* and the broadcast address */ 12847c478bd9Sstevel@tonic-gate dlp->dl_brdcst_addr_length = 12857c478bd9Sstevel@tonic-gate lld->llc_mac_info->llcp_addrlen; 12867c478bd9Sstevel@tonic-gate dlp->dl_brdcst_addr_offset = 12877c478bd9Sstevel@tonic-gate dlp->dl_addr_offset + dlp->dl_addr_length; 12887c478bd9Sstevel@tonic-gate nmp->b_wptr += dlp->dl_brdcst_addr_length; 12897c478bd9Sstevel@tonic-gate bcopy(lld->llc_mac_info->llcp_broadcast, 12907c478bd9Sstevel@tonic-gate ((caddr_t)dlp) + dlp->dl_brdcst_addr_offset, 12917c478bd9Sstevel@tonic-gate lld->llc_mac_info->llcp_addrlen); 12927c478bd9Sstevel@tonic-gate } else { 12937c478bd9Sstevel@tonic-gate dlp->dl_addr_length = 0; /* not attached yet */ 12947c478bd9Sstevel@tonic-gate dlp->dl_addr_offset = NULL; 12957c478bd9Sstevel@tonic-gate dlp->dl_sap_length = 0; /* 1 bytes on end */ 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate dlp->dl_version = DL_VERSION_2; 12987c478bd9Sstevel@tonic-gate qreply(q, nmp); 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate return (LLCE_OK); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * llc1_unitdata 13057c478bd9Sstevel@tonic-gate * send a datagram. Destination address/lsap is in M_PROTO 13067c478bd9Sstevel@tonic-gate * message (first mblock), data is in remainder of message. 13077c478bd9Sstevel@tonic-gate * 13087c478bd9Sstevel@tonic-gate * NOTE: We are reusing the DL_unitdata_req mblock; if llc header gets any 13097c478bd9Sstevel@tonic-gate * bigger, recheck to make sure it still fits! We assume that we have a 13107c478bd9Sstevel@tonic-gate * 64-byte dblock for this, since a DL_unitdata_req is 20 bytes and the next 13117c478bd9Sstevel@tonic-gate * larger dblock size is 64. 13127c478bd9Sstevel@tonic-gate */ 13137c478bd9Sstevel@tonic-gate static int 13147c478bd9Sstevel@tonic-gate llc1_unitdata(queue_t *q, mblk_t *mp) 13157c478bd9Sstevel@tonic-gate { 13167c478bd9Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr; 13177c478bd9Sstevel@tonic-gate dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr; 13187c478bd9Sstevel@tonic-gate struct ether_header *hdr; 13197c478bd9Sstevel@tonic-gate struct llcaddr *llcp; 13207c478bd9Sstevel@tonic-gate mblk_t *nmp; 13217c478bd9Sstevel@tonic-gate long msglen; 13227c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 13237c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 13247c478bd9Sstevel@tonic-gate int xmt_type = 0; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 13277c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 13287c478bd9Sstevel@tonic-gate printf("llc1_unitdata(%x %x)\n", q, mp); 13297c478bd9Sstevel@tonic-gate #endif 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if ((macinfo = lld->llc_mac_info) == NULL) 13327c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate if (lld->llc_state != DL_IDLE) { 13357c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 13367c478bd9Sstevel@tonic-gate if (llc1_debug & LLCERRS) 13377c478bd9Sstevel@tonic-gate printf("llc1_unitdata: wrong state (%d)\n", 13387c478bd9Sstevel@tonic-gate lld->llc_state); 13397c478bd9Sstevel@tonic-gate #endif 13407c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* need the destination address in all cases */ 13447c478bd9Sstevel@tonic-gate llcp = (struct llcaddr *)((caddr_t)dlp + dlp->dl_dest_addr_offset); 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) { 13477c478bd9Sstevel@tonic-gate /* 13487c478bd9Sstevel@tonic-gate * make a valid header for transmission 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* need a buffer big enough for the headers */ 13527c478bd9Sstevel@tonic-gate nmp = allocb(macinfo->llcp_addrlen * 2 + 2 + 8, BPRI_MED); 13537c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)nmp->b_rptr; 13547c478bd9Sstevel@tonic-gate msglen = msgdsize(mp); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* fill in type dependent fields */ 13577c478bd9Sstevel@tonic-gate switch (lld->llc_type) { 13587c478bd9Sstevel@tonic-gate case DL_CSMACD: /* 802.3 CSMA/CD */ 13597c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + LLC1_CSMACD_HDR_SIZE; 13607c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_wptr; 13617c478bd9Sstevel@tonic-gate bcopy(llcp->llca_addr, 13627c478bd9Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet, 13637c478bd9Sstevel@tonic-gate ETHERADDRL); 13647c478bd9Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr, 13657c478bd9Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet, 13667c478bd9Sstevel@tonic-gate ETHERADDRL); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (lld->llc_sap != LLC_NOVELL_SAP) { 13697c478bd9Sstevel@tonic-gate /* set length with llc header size */ 13707c478bd9Sstevel@tonic-gate hdr->ether_type = ntohs(msglen + 13717c478bd9Sstevel@tonic-gate sizeof (struct llchdr)); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* need an LLC header, otherwise is Novell */ 13747c478bd9Sstevel@tonic-gate /* bound sap is always source */ 13757c478bd9Sstevel@tonic-gate llchdr->llc_ssap = lld->llc_sap; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* destination sap */ 13787c478bd9Sstevel@tonic-gate llchdr->llc_dsap = llcp->llca_sap; 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* always Unnumbered Information */ 13817c478bd9Sstevel@tonic-gate llchdr->llc_ctl = LLC_UI; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 13867c478bd9Sstevel@tonic-gate bcopy(lld->llc_snap, nmp->b_wptr, 5); 13877c478bd9Sstevel@tonic-gate llchdr->llc_dsap = LLC_SNAP_SAP; 13887c478bd9Sstevel@tonic-gate nmp->b_wptr += 5; 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate } else { 13917c478bd9Sstevel@tonic-gate /* set length without llc header size */ 13927c478bd9Sstevel@tonic-gate hdr->ether_type = ntohs(msglen); 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* we don't do anything else for Netware */ 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate if (ismulticast(hdr->ether_dhost.ether_addr_octet)) { 13987c478bd9Sstevel@tonic-gate if (bcmp(hdr->ether_dhost.ether_addr_octet, 13997c478bd9Sstevel@tonic-gate macinfo->llcp_broadcast, ETHERADDRL) == 0) 14007c478bd9Sstevel@tonic-gate xmt_type = 2; 14017c478bd9Sstevel@tonic-gate else 14027c478bd9Sstevel@tonic-gate xmt_type = 1; 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate break; 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate default: /* either RAW or unknown, send as is */ 14087c478bd9Sstevel@tonic-gate break; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate DB_TYPE(nmp) = M_DATA; /* ether/llc header is data */ 14117c478bd9Sstevel@tonic-gate nmp->b_cont = mp->b_cont; /* use the data given */ 14127c478bd9Sstevel@tonic-gate freeb(mp); 14137c478bd9Sstevel@tonic-gate mp = nmp; 14147c478bd9Sstevel@tonic-gate } else { 14157c478bd9Sstevel@tonic-gate /* need to format a DL_UNITDATA_REQ with LLC1 header inserted */ 14167c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (struct llchdr)+sizeof (struct snaphdr), 14177c478bd9Sstevel@tonic-gate BPRI_MED); 14187c478bd9Sstevel@tonic-gate if (nmp == NULL) 14197c478bd9Sstevel@tonic-gate return (DL_UNDELIVERABLE); 14207c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(nmp->b_rptr); 14217c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr); 14227c478bd9Sstevel@tonic-gate llchdr->llc_dsap = llcp->llca_sap; 14237c478bd9Sstevel@tonic-gate llchdr->llc_ssap = lld->llc_sap; 14247c478bd9Sstevel@tonic-gate llchdr->llc_ctl = LLC_UI; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * if we are using SNAP, insert the header here 14287c478bd9Sstevel@tonic-gate */ 14297c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 14307c478bd9Sstevel@tonic-gate bcopy(lld->llc_snap, nmp->b_wptr, 5); 14317c478bd9Sstevel@tonic-gate nmp->b_wptr += 5; 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate nmp->b_cont = mp->b_cont; 14347c478bd9Sstevel@tonic-gate mp->b_cont = nmp; 14357c478bd9Sstevel@tonic-gate nmp = mp; 14367c478bd9Sstevel@tonic-gate if (ismulticast(llcp->llca_addr)) { 14377c478bd9Sstevel@tonic-gate if (bcmp(llcp->llca_addr, 14387c478bd9Sstevel@tonic-gate macinfo->llcp_broadcast, ETHERADDRL) == 0) 14397c478bd9Sstevel@tonic-gate xmt_type = 2; 14407c478bd9Sstevel@tonic-gate else 14417c478bd9Sstevel@tonic-gate xmt_type = 1; 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate if (canput(macinfo->llcp_queue)) { 14457c478bd9Sstevel@tonic-gate lld->llc_stats->llcs_bytexmt += msgdsize(mp); 14467c478bd9Sstevel@tonic-gate lld->llc_stats->llcs_pktxmt++; 14477c478bd9Sstevel@tonic-gate switch (xmt_type) { 14487c478bd9Sstevel@tonic-gate case 1: 14497c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_multixmt++; 14507c478bd9Sstevel@tonic-gate break; 14517c478bd9Sstevel@tonic-gate case 2: 14527c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_brdcstxmt++; 14537c478bd9Sstevel@tonic-gate break; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp); 14577c478bd9Sstevel@tonic-gate return (LLCE_OK); /* this is almost correct, the result */ 14587c478bd9Sstevel@tonic-gate } else { 14597c478bd9Sstevel@tonic-gate lld->llc_stats->llcs_nobuffer++; 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate if (nmp != NULL) 14627c478bd9Sstevel@tonic-gate freemsg(nmp); /* free on failure */ 14637c478bd9Sstevel@tonic-gate return (LLCE_OK); 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * llc1_recv(macinfo, mp) 14687c478bd9Sstevel@tonic-gate * called with an ethernet packet in a mblock; must decide 14697c478bd9Sstevel@tonic-gate * whether packet is for us and which streams to queue it to. This routine is 14707c478bd9Sstevel@tonic-gate * called with locally originated packets for loopback. 14717c478bd9Sstevel@tonic-gate */ 14727c478bd9Sstevel@tonic-gate static void 14737c478bd9Sstevel@tonic-gate llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp) 14747c478bd9Sstevel@tonic-gate { 14757c478bd9Sstevel@tonic-gate struct ether_addr *addr; 14767c478bd9Sstevel@tonic-gate llc1_t *lld; 14777c478bd9Sstevel@tonic-gate mblk_t *nmp, *udmp; 14787c478bd9Sstevel@tonic-gate int i, nmcast = 0, statcnt_normal = 0, statcnt_brdcst = 0; 14797c478bd9Sstevel@tonic-gate int valid, msgsap; 14807c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 14837c478bd9Sstevel@tonic-gate if (llc1_debug & LLCTRACE) 14847c478bd9Sstevel@tonic-gate printf("llc1_recv(%x, %x)\n", mp, macinfo); 14857c478bd9Sstevel@tonic-gate #endif 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) { 14887c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *udata; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate /* check to see if really LLC1 XXX */ 14917c478bd9Sstevel@tonic-gate /* also need to make sure to keep address info */ 14927c478bd9Sstevel@tonic-gate nmp = mp; 14937c478bd9Sstevel@tonic-gate udata = (dl_unitdata_ind_t *)(nmp->b_rptr); 14947c478bd9Sstevel@tonic-gate addr = (struct ether_addr *)(nmp->b_rptr + 14957c478bd9Sstevel@tonic-gate udata->dl_dest_addr_offset); 14967c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(nmp->b_cont->b_rptr); 14977c478bd9Sstevel@tonic-gate if (macinfo->llcp_type == DL_CSMACD) { 14987c478bd9Sstevel@tonic-gate i = ((struct llcsaddr *)addr)->llca_ssap; 14997c478bd9Sstevel@tonic-gate if (i < 60) { 15007c478bd9Sstevel@tonic-gate valid = adjmsg(mp->b_cont, i - msgdsize(mp)); 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate } else { 15047c478bd9Sstevel@tonic-gate struct ether_header *hdr; 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate /* Note that raw mode currently assumes Ethernet */ 15077c478bd9Sstevel@tonic-gate nmp = NULL; 15087c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 15097c478bd9Sstevel@tonic-gate addr = &hdr->ether_dhost; 15107c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(mp->b_rptr + 15117c478bd9Sstevel@tonic-gate sizeof (struct ether_header)); 15127c478bd9Sstevel@tonic-gate i = (ushort_t)ntohs(hdr->ether_type); 15137c478bd9Sstevel@tonic-gate if (i < 60) { 15147c478bd9Sstevel@tonic-gate (void) adjmsg(mp, i + sizeof (struct ether_header) - 15157c478bd9Sstevel@tonic-gate msgdsize(mp)); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate udmp = NULL; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate msgsap = llchdr->llc_dsap; 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 15237c478bd9Sstevel@tonic-gate if (llc1_debug & LLCRECV) { 15247c478bd9Sstevel@tonic-gate printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr)); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate #endif 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate if (llc1_broadcast(addr, macinfo)) { 15297c478bd9Sstevel@tonic-gate valid = 2; /* 2 means valid but multicast */ 15307c478bd9Sstevel@tonic-gate statcnt_brdcst = 1; 15317c478bd9Sstevel@tonic-gate } else { 15327c478bd9Sstevel@tonic-gate valid = llc1_local(addr, macinfo); 15337c478bd9Sstevel@tonic-gate statcnt_normal = msgdsize(mp); 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* 15377c478bd9Sstevel@tonic-gate * Note that the NULL SAP is a special case. It is associated with 15387c478bd9Sstevel@tonic-gate * the MAC layer and not the LLC layer so should be handled 15397c478bd9Sstevel@tonic-gate * independently of any STREAM. 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate if (msgsap == LLC_NULL_SAP) { 15427c478bd9Sstevel@tonic-gate /* only XID and TEST ever processed, UI is dropped */ 15437c478bd9Sstevel@tonic-gate if ((llchdr->llc_ctl & ~LLC_P) == LLC_XID) 15447c478bd9Sstevel@tonic-gate mp = llc1_xid_reply(macinfo, mp, 0); 15457c478bd9Sstevel@tonic-gate else if ((llchdr->llc_ctl & ~LLC_P) == LLC_TEST) 15467c478bd9Sstevel@tonic-gate mp = llc1_test_reply(macinfo, mp, 0); 15477c478bd9Sstevel@tonic-gate } else 15487c478bd9Sstevel@tonic-gate for (lld = llc1_device_list.llc1_str_next; 15497c478bd9Sstevel@tonic-gate lld != (llc1_t *)&llc1_device_list.llc1_str_next; 15507c478bd9Sstevel@tonic-gate lld = lld->llc_next) { 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * is this a potentially usable SAP on the 15547c478bd9Sstevel@tonic-gate * right MAC layer? 15557c478bd9Sstevel@tonic-gate */ 15567c478bd9Sstevel@tonic-gate if (lld->llc_qptr == NULL || 15577c478bd9Sstevel@tonic-gate lld->llc_state != DL_IDLE || 15587c478bd9Sstevel@tonic-gate lld->llc_mac_info != macinfo) { 15597c478bd9Sstevel@tonic-gate continue; 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 15627c478bd9Sstevel@tonic-gate if (llc1_debug & LLCRECV) 15637c478bd9Sstevel@tonic-gate printf( 15647c478bd9Sstevel@tonic-gate "llc1_recv: type=%d, sap=%x, pkt-dsap=%x\n", 15657c478bd9Sstevel@tonic-gate lld->llc_type, lld->llc_sap, 15667c478bd9Sstevel@tonic-gate msgsap); 15677c478bd9Sstevel@tonic-gate #endif 15687c478bd9Sstevel@tonic-gate if (!valid && ismulticast(addr->ether_addr_octet) && 15697c478bd9Sstevel@tonic-gate lld->llc_multicnt > 0 && 15707c478bd9Sstevel@tonic-gate llc1_multicast(addr, lld)) { 15717c478bd9Sstevel@tonic-gate valid |= 4; 15727c478bd9Sstevel@tonic-gate } else if (lld->llc_flags & LLC_PROM) 15737c478bd9Sstevel@tonic-gate /* promiscuous mode */ 15747c478bd9Sstevel@tonic-gate valid = 1; 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate if ((lld->llc_flags & LLC_PROM) || 15777c478bd9Sstevel@tonic-gate /* promiscuous streams */ 15787c478bd9Sstevel@tonic-gate (valid && 15797c478bd9Sstevel@tonic-gate (lld->llc_sap == msgsap || 15807c478bd9Sstevel@tonic-gate msgsap == LLC_GLOBAL_SAP))) { 15817c478bd9Sstevel@tonic-gate /* sap matches */ 15827c478bd9Sstevel@tonic-gate if (msgsap == LLC_SNAP_SAP && 15837c478bd9Sstevel@tonic-gate (lld->llc_flags & (LLC_SNAP|LLC_PROM)) == 15847c478bd9Sstevel@tonic-gate LLC_SNAP) { 15857c478bd9Sstevel@tonic-gate if (!llc1_snap_match(lld, 15867c478bd9Sstevel@tonic-gate (struct snaphdr *)(llchdr+1))) 15877c478bd9Sstevel@tonic-gate continue; 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate if (!canputnext(RD(lld->llc_qptr))) { 15907c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 15917c478bd9Sstevel@tonic-gate if (llc1_debug & LLCRECV) 15927c478bd9Sstevel@tonic-gate printf( 15937c478bd9Sstevel@tonic-gate "llc1_recv: canput failed\n"); 15947c478bd9Sstevel@tonic-gate #endif 15957c478bd9Sstevel@tonic-gate lld->llc_stats->llcs_blocked++; 15967c478bd9Sstevel@tonic-gate continue; 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate /* check for Novell special handling */ 15997c478bd9Sstevel@tonic-gate if (msgsap == LLC_GLOBAL_SAP && 16007c478bd9Sstevel@tonic-gate lld->llc_sap == LLC_NOVELL_SAP && 16017c478bd9Sstevel@tonic-gate llchdr->llc_ssap == LLC_GLOBAL_SAP) { 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate /* A Novell packet */ 16047c478bd9Sstevel@tonic-gate nmp = llc1_form_udata(lld, macinfo, mp); 16057c478bd9Sstevel@tonic-gate continue; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate switch (llchdr->llc_ctl) { 16087c478bd9Sstevel@tonic-gate case LLC_UI: 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * this is an Unnumbered Information 16117c478bd9Sstevel@tonic-gate * packet so form a DL_UNITDATA_IND and 16127c478bd9Sstevel@tonic-gate * send to user 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate nmp = llc1_form_udata(lld, macinfo, mp); 16157c478bd9Sstevel@tonic-gate break; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate case LLC_XID: 16187c478bd9Sstevel@tonic-gate case LLC_XID | LLC_P: 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate * this is either an XID request or 16217c478bd9Sstevel@tonic-gate * response. We either handle directly 16227c478bd9Sstevel@tonic-gate * (if user hasn't requested to handle 16237c478bd9Sstevel@tonic-gate * itself) or send to user. We also 16247c478bd9Sstevel@tonic-gate * must check if a response if user 16257c478bd9Sstevel@tonic-gate * handled so that we can send correct 16267c478bd9Sstevel@tonic-gate * message form 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC1_AUTO_XID) { 16297c478bd9Sstevel@tonic-gate nmp = llc1_xid_reply(macinfo, 16307c478bd9Sstevel@tonic-gate mp, lld->llc_sap); 16317c478bd9Sstevel@tonic-gate } else { 16327c478bd9Sstevel@tonic-gate /* 16337c478bd9Sstevel@tonic-gate * hand to the user for 16347c478bd9Sstevel@tonic-gate * handling. if this is a 16357c478bd9Sstevel@tonic-gate * "request", generate a 16367c478bd9Sstevel@tonic-gate * DL_XID_IND. If it is a 16377c478bd9Sstevel@tonic-gate * "response" to one of our 16387c478bd9Sstevel@tonic-gate * requests, generate a 16397c478bd9Sstevel@tonic-gate * DL_XID_CON. 16407c478bd9Sstevel@tonic-gate */ 16417c478bd9Sstevel@tonic-gate nmp = llc1_xid_ind_con(lld, 16427c478bd9Sstevel@tonic-gate macinfo, mp); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidrcv++; 16457c478bd9Sstevel@tonic-gate break; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate case LLC_TEST: 16487c478bd9Sstevel@tonic-gate case LLC_TEST | LLC_P: 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * this is either a TEST request or 16517c478bd9Sstevel@tonic-gate * response. We either handle 16527c478bd9Sstevel@tonic-gate * directly (if user hasn't 16537c478bd9Sstevel@tonic-gate * requested to handle itself) 16547c478bd9Sstevel@tonic-gate * or send to user. We also 16557c478bd9Sstevel@tonic-gate * must check if a response if 16567c478bd9Sstevel@tonic-gate * user handled so that we can 16577c478bd9Sstevel@tonic-gate * send correct message form 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC1_AUTO_TEST) { 16607c478bd9Sstevel@tonic-gate nmp = llc1_test_reply(macinfo, 16617c478bd9Sstevel@tonic-gate mp, lld->llc_sap); 16627c478bd9Sstevel@tonic-gate } else { 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * hand to the user for 16657c478bd9Sstevel@tonic-gate * handling. if this is 16667c478bd9Sstevel@tonic-gate * a "request", 16677c478bd9Sstevel@tonic-gate * generate a 16687c478bd9Sstevel@tonic-gate * DL_TEST_IND. If it 16697c478bd9Sstevel@tonic-gate * is a "response" to 16707c478bd9Sstevel@tonic-gate * one of our requests, 16717c478bd9Sstevel@tonic-gate * generate a 16727c478bd9Sstevel@tonic-gate * DL_TEST_CON. 16737c478bd9Sstevel@tonic-gate */ 16747c478bd9Sstevel@tonic-gate nmp = llc1_test_ind_con(lld, 16757c478bd9Sstevel@tonic-gate macinfo, mp); 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_testrcv++; 16787c478bd9Sstevel@tonic-gate break; 16797c478bd9Sstevel@tonic-gate default: 16807c478bd9Sstevel@tonic-gate nmp = mp; 16817c478bd9Sstevel@tonic-gate break; 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate mp = nmp; 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate if (mp != NULL) 16877c478bd9Sstevel@tonic-gate freemsg(mp); 16887c478bd9Sstevel@tonic-gate if (udmp != NULL) 16897c478bd9Sstevel@tonic-gate freeb(udmp); 16907c478bd9Sstevel@tonic-gate if (nmcast > 0) 16917c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_multircv++; 16927c478bd9Sstevel@tonic-gate if (statcnt_brdcst) { 16937c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_brdcstrcv++; 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate if (statcnt_normal) { 16967c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_bytercv += statcnt_normal; 16977c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_pktrcv++; 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate /* 17027c478bd9Sstevel@tonic-gate * llc1_local - check to see if the message is addressed to this system by 17037c478bd9Sstevel@tonic-gate * comparing with the board's address. 17047c478bd9Sstevel@tonic-gate */ 17057c478bd9Sstevel@tonic-gate static int 17067c478bd9Sstevel@tonic-gate llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo) 17077c478bd9Sstevel@tonic-gate { 17087c478bd9Sstevel@tonic-gate return (bcmp(addr->ether_addr_octet, macinfo->llcp_macaddr, 17097c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen) == 0); 17107c478bd9Sstevel@tonic-gate } 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* 17137c478bd9Sstevel@tonic-gate * llc1_broadcast - check to see if a broadcast address is the destination of 17147c478bd9Sstevel@tonic-gate * this received packet 17157c478bd9Sstevel@tonic-gate */ 17167c478bd9Sstevel@tonic-gate static int 17177c478bd9Sstevel@tonic-gate llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo) 17187c478bd9Sstevel@tonic-gate { 17197c478bd9Sstevel@tonic-gate return (bcmp(addr->ether_addr_octet, macinfo->llcp_broadcast, 17207c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen) == 0); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate /* 17247c478bd9Sstevel@tonic-gate * llc1attach(q, mp) DLPI DL_ATTACH_REQ this attaches the stream to a PPA 17257c478bd9Sstevel@tonic-gate */ 17267c478bd9Sstevel@tonic-gate static int 17277c478bd9Sstevel@tonic-gate llc1attach(queue_t *q, mblk_t *mp) 17287c478bd9Sstevel@tonic-gate { 17297c478bd9Sstevel@tonic-gate dl_attach_req_t *at; 17307c478bd9Sstevel@tonic-gate llc_mac_info_t *mac; 17317c478bd9Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr; 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate at = (dl_attach_req_t *)mp->b_rptr; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if (llc->llc_state != DL_UNATTACHED) { 17367c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate llc->llc_state = DL_ATTACH_PENDING; 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) { 17417c478bd9Sstevel@tonic-gate /* 17427c478bd9Sstevel@tonic-gate * someone else has a lock held. To avoid deadlock, 17437c478bd9Sstevel@tonic-gate * release the READER lock and block on a WRITER 17447c478bd9Sstevel@tonic-gate * lock. This will let things continue safely. 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 17477c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate for (mac = llc1_device_list.llc1_mac_next; 17517c478bd9Sstevel@tonic-gate mac != (llc_mac_info_t *)(&llc1_device_list.llc1_mac_next); 17527c478bd9Sstevel@tonic-gate mac = mac->llcp_next) { 17537c478bd9Sstevel@tonic-gate ASSERT(mac); 17547c478bd9Sstevel@tonic-gate if (mac->llcp_ppa == at->dl_ppa && mac->llcp_lqtop == q) { 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * We may have found the correct PPA 17577c478bd9Sstevel@tonic-gate * check to see if linking has finished. 17587c478bd9Sstevel@tonic-gate * Use explicit flag checks for incorrect 17597c478bd9Sstevel@tonic-gate * state, and use negative values for "tenative" 17607c478bd9Sstevel@tonic-gate * llcp_ppas, to avoid erroneous attaches. 17617c478bd9Sstevel@tonic-gate */ 17627c478bd9Sstevel@tonic-gate if (mac->llcp_flags & 17637c478bd9Sstevel@tonic-gate (LLC1_LINKED|LLC1_DEF_PPA)) { 17647c478bd9Sstevel@tonic-gate return (DL_INITFAILED); 17657c478bd9Sstevel@tonic-gate } else if (!(mac->llcp_flags & LLC1_AVAILABLE)) { 17667c478bd9Sstevel@tonic-gate return (DL_BADPPA); 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate /* this links us to the PPA */ 17707c478bd9Sstevel@tonic-gate mac->llcp_nstreams++; 17717c478bd9Sstevel@tonic-gate llc->llc_mac_info = mac; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate llc->llc_state = DL_UNBOUND; /* now ready for action */ 17747c478bd9Sstevel@tonic-gate llc->llc_stats = &mac->llcp_stats; 17757c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_ATTACH_REQ); 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate return (LLCE_OK); 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate llc->llc_state = DL_UNATTACHED; 17817c478bd9Sstevel@tonic-gate return (DL_BADPPA); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate /* 17857c478bd9Sstevel@tonic-gate * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the 17867c478bd9Sstevel@tonic-gate * stream 17877c478bd9Sstevel@tonic-gate */ 17887c478bd9Sstevel@tonic-gate static int 17897c478bd9Sstevel@tonic-gate llc1unattach(queue_t *q, mblk_t *mp) 17907c478bd9Sstevel@tonic-gate { 17917c478bd9Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr; 17927c478bd9Sstevel@tonic-gate int state; 17937c478bd9Sstevel@tonic-gate int i; 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate state = llc->llc_state; 17967c478bd9Sstevel@tonic-gate if (state != DL_UNBOUND) 17977c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate /* can now detach from the PPA */ 18007c478bd9Sstevel@tonic-gate llc->llc_state = DL_DETACH_PENDING; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) { 18037c478bd9Sstevel@tonic-gate /* 18047c478bd9Sstevel@tonic-gate * someone else has a lock held. To avoid deadlock, 18057c478bd9Sstevel@tonic-gate * release the READER lock and block on a WRITER 18067c478bd9Sstevel@tonic-gate * lock. This will let things continue safely. 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate rw_exit(&llc1_device_list.llc1_rwlock); 18097c478bd9Sstevel@tonic-gate rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate if (llc->llc_mcast) { 18137c478bd9Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) { 18147c478bd9Sstevel@tonic-gate llc_mcast_t *mcast; 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate if ((mcast = llc->llc_mcast[i]) != NULL) { 18177c478bd9Sstevel@tonic-gate /* disable from stream and possibly lower */ 18187c478bd9Sstevel@tonic-gate llc1_send_disable_multi(llc->llc_mac_info, 18197c478bd9Sstevel@tonic-gate mcast); 18207c478bd9Sstevel@tonic-gate llc->llc_mcast[i] = NULL; 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate kmem_free(llc->llc_mcast, 18247c478bd9Sstevel@tonic-gate sizeof (llc_mcast_t *) * llc->llc_multicnt); 18257c478bd9Sstevel@tonic-gate llc->llc_mcast = NULL; 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate if (llc->llc_mac_info) 18287c478bd9Sstevel@tonic-gate llc->llc_mac_info->llcp_nstreams--; 18297c478bd9Sstevel@tonic-gate llc->llc_sap = 0; 18307c478bd9Sstevel@tonic-gate llc->llc_state = DL_UNATTACHED; 18317c478bd9Sstevel@tonic-gate if (mp) { 18327c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_DETACH_REQ); 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate return (LLCE_OK); 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate /* 18387c478bd9Sstevel@tonic-gate * llc1_enable_multi enables multicast address on the stream if the mac layer 18397c478bd9Sstevel@tonic-gate * isn't enabled for this address, enable at that level as well. 18407c478bd9Sstevel@tonic-gate */ 18417c478bd9Sstevel@tonic-gate static int 18427c478bd9Sstevel@tonic-gate llc1_enable_multi(queue_t *q, mblk_t *mp) 18437c478bd9Sstevel@tonic-gate { 18447c478bd9Sstevel@tonic-gate llc1_t *llc; 18457c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 18467c478bd9Sstevel@tonic-gate struct ether_addr *maddr; 18477c478bd9Sstevel@tonic-gate dl_enabmulti_req_t *multi; 18487c478bd9Sstevel@tonic-gate llc_mcast_t *mcast; 18497c478bd9Sstevel@tonic-gate int status = DL_BADADDR; 18507c478bd9Sstevel@tonic-gate int i; 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate #if defined(LLC1_DEBUG) 18537c478bd9Sstevel@tonic-gate if (llc1_debug & LLCPROT) { 18547c478bd9Sstevel@tonic-gate printf("llc1_enable_multi(%x, %x)\n", q, mp); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate #endif 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate llc = (llc1_t *)q->q_ptr; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate if (llc->llc_state == DL_UNATTACHED) 18617c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate macinfo = llc->llc_mac_info; 18647c478bd9Sstevel@tonic-gate multi = (dl_enabmulti_req_t *)mp->b_rptr; 18657c478bd9Sstevel@tonic-gate maddr = (struct ether_addr *)(mp->b_rptr + multi->dl_addr_offset); 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate /* 18687c478bd9Sstevel@tonic-gate * check to see if this multicast address is valid if it is, then 18697c478bd9Sstevel@tonic-gate * check to see if it is already in the per stream table and the per 18707c478bd9Sstevel@tonic-gate * device table if it is already in the per stream table, if it isn't 18717c478bd9Sstevel@tonic-gate * in the per device, add it. If it is, just set a pointer. If it 18727c478bd9Sstevel@tonic-gate * isn't, allocate what's necessary. 18737c478bd9Sstevel@tonic-gate */ 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) && 18767c478bd9Sstevel@tonic-gate MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) && 18777c478bd9Sstevel@tonic-gate multi->dl_addr_length == macinfo->llcp_addrlen && 18787c478bd9Sstevel@tonic-gate ismulticast(maddr->ether_addr_octet)) { 18797c478bd9Sstevel@tonic-gate /* request appears to be valid */ 18807c478bd9Sstevel@tonic-gate /* does this address appear in current table? */ 18817c478bd9Sstevel@tonic-gate if (llc->llc_mcast == NULL) { 18827c478bd9Sstevel@tonic-gate /* no mcast addresses -- allocate table */ 18837c478bd9Sstevel@tonic-gate llc->llc_mcast = 18847c478bd9Sstevel@tonic-gate GETSTRUCT(llc_mcast_t *, 18857c478bd9Sstevel@tonic-gate llc1_device_list.llc1_multisize); 18867c478bd9Sstevel@tonic-gate if (llc->llc_mcast == NULL) 18877c478bd9Sstevel@tonic-gate return (DL_SYSERR); 18887c478bd9Sstevel@tonic-gate llc->llc_multicnt = llc1_device_list.llc1_multisize; 18897c478bd9Sstevel@tonic-gate } else { 18907c478bd9Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) { 18917c478bd9Sstevel@tonic-gate if (llc->llc_mcast[i] && 18927c478bd9Sstevel@tonic-gate bcmp(llc->llc_mcast[i]->llcm_addr, 18937c478bd9Sstevel@tonic-gate maddr->ether_addr_octet, ETHERADDRL)) { 18947c478bd9Sstevel@tonic-gate /* this is a match -- just succeed */ 18957c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ); 18967c478bd9Sstevel@tonic-gate return (LLCE_OK); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate /* 19017c478bd9Sstevel@tonic-gate * there wasn't one so check to see if the mac layer has one 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate if (macinfo->llcp_mcast == NULL) { 19047c478bd9Sstevel@tonic-gate macinfo->llcp_mcast = 19057c478bd9Sstevel@tonic-gate GETSTRUCT(llc_mcast_t, 19067c478bd9Sstevel@tonic-gate llc1_device_list.llc1_multisize); 19077c478bd9Sstevel@tonic-gate if (macinfo->llcp_mcast == NULL) 19087c478bd9Sstevel@tonic-gate return (DL_SYSERR); 19097c478bd9Sstevel@tonic-gate } 19107c478bd9Sstevel@tonic-gate for (mcast = NULL, i = 0; 19117c478bd9Sstevel@tonic-gate i < llc1_device_list.llc1_multisize; i++) { 19127c478bd9Sstevel@tonic-gate if (macinfo->llcp_mcast[i].llcm_refcnt && 19137c478bd9Sstevel@tonic-gate bcmp(macinfo->llcp_mcast[i].llcm_addr, 19147c478bd9Sstevel@tonic-gate maddr->ether_addr_octet, ETHERADDRL) == 0) { 19157c478bd9Sstevel@tonic-gate mcast = &macinfo->llcp_mcast[i]; 19167c478bd9Sstevel@tonic-gate break; 19177c478bd9Sstevel@tonic-gate } 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate if (mcast == NULL) { 19207c478bd9Sstevel@tonic-gate mblk_t *nmp; 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); 19237c478bd9Sstevel@tonic-gate if (nmp) { 19247c478bd9Sstevel@tonic-gate nmp->b_cont = NULL; 19257c478bd9Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO; 19267c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), nmp); 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate /* find an empty slot to fill in */ 19297c478bd9Sstevel@tonic-gate for (mcast = macinfo->llcp_mcast, i = 0; 19307c478bd9Sstevel@tonic-gate i < llc1_device_list.llc1_multisize; i++, mcast++) { 19317c478bd9Sstevel@tonic-gate if (mcast->llcm_refcnt == 0) { 19327c478bd9Sstevel@tonic-gate bcopy(maddr->ether_addr_octet, 19337c478bd9Sstevel@tonic-gate mcast->llcm_addr, ETHERADDRL); 19347c478bd9Sstevel@tonic-gate break; 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate if (mcast != NULL) { 19397c478bd9Sstevel@tonic-gate for (i = 0; i < llc1_device_list.llc1_multisize; i++) { 19407c478bd9Sstevel@tonic-gate if (llc->llc_mcast[i] == NULL) { 19417c478bd9Sstevel@tonic-gate llc->llc_mcast[i] = mcast; 19427c478bd9Sstevel@tonic-gate mcast->llcm_refcnt++; 19437c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ); 19447c478bd9Sstevel@tonic-gate return (LLCE_OK); 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate status = DL_TOOMANY; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate return (status); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* 19547c478bd9Sstevel@tonic-gate * llc1_disable_multi disable the multicast address on the stream if last 19557c478bd9Sstevel@tonic-gate * reference for the mac layer, disable there as well 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate static int 19587c478bd9Sstevel@tonic-gate llc1_disable_multi(queue_t *q, mblk_t *mp) 19597c478bd9Sstevel@tonic-gate { 19607c478bd9Sstevel@tonic-gate llc1_t *llc; 19617c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 19627c478bd9Sstevel@tonic-gate struct ether_addr *maddr; 19637c478bd9Sstevel@tonic-gate dl_enabmulti_req_t *multi; 19647c478bd9Sstevel@tonic-gate int status = DL_BADADDR, i; 19657c478bd9Sstevel@tonic-gate llc_mcast_t *mcast; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate #if defined(LLC1_DEBUG) 19687c478bd9Sstevel@tonic-gate if (llc1_debug & LLCPROT) { 19697c478bd9Sstevel@tonic-gate printf("llc1_enable_multi(%x, %x)\n", q, mp); 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate #endif 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate llc = (llc1_t *)q->q_ptr; 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate if (llc->llc_state == DL_UNATTACHED) 19767c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate macinfo = llc->llc_mac_info; 19797c478bd9Sstevel@tonic-gate multi = (dl_enabmulti_req_t *)mp->b_rptr; 19807c478bd9Sstevel@tonic-gate maddr = (struct ether_addr *)(multi + 1); 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) && 19837c478bd9Sstevel@tonic-gate MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length)) { 19847c478bd9Sstevel@tonic-gate /* request appears to be valid */ 19857c478bd9Sstevel@tonic-gate /* does this address appear in current table? */ 19867c478bd9Sstevel@tonic-gate if (llc->llc_mcast != NULL) { 19877c478bd9Sstevel@tonic-gate for (i = 0; i < llc->llc_multicnt; i++) 19887c478bd9Sstevel@tonic-gate if (((mcast = llc->llc_mcast[i]) != NULL) && 19897c478bd9Sstevel@tonic-gate mcast->llcm_refcnt && 19907c478bd9Sstevel@tonic-gate bcmp(mcast->llcm_addr, 19917c478bd9Sstevel@tonic-gate maddr->ether_addr_octet, ETHERADDRL) == 0) { 19927c478bd9Sstevel@tonic-gate llc1_send_disable_multi(macinfo, 19937c478bd9Sstevel@tonic-gate mcast); 19947c478bd9Sstevel@tonic-gate llc->llc_mcast[i] = NULL; 19957c478bd9Sstevel@tonic-gate dlokack(q, mp, DL_DISABMULTI_REQ); 19967c478bd9Sstevel@tonic-gate return (LLCE_OK); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate status = DL_NOTENAB; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate return (status); 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* 20057c478bd9Sstevel@tonic-gate * llc1_send_disable_multi(llc, macinfo, mcast) this function is used to 20067c478bd9Sstevel@tonic-gate * disable a multicast address if the reference count goes to zero. The 20077c478bd9Sstevel@tonic-gate * disable request will then be forwarded to the lower stream. 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate static void 20107c478bd9Sstevel@tonic-gate llc1_send_disable_multi(llc_mac_info_t *macinfo, llc_mcast_t *mcast) 20117c478bd9Sstevel@tonic-gate { 20127c478bd9Sstevel@tonic-gate mblk_t *mp; 20137c478bd9Sstevel@tonic-gate dl_disabmulti_req_t *dis; 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate if (mcast == NULL) { 20167c478bd9Sstevel@tonic-gate return; 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate if (macinfo == NULL || macinfo->llcp_queue == NULL) { 20197c478bd9Sstevel@tonic-gate return; 20207c478bd9Sstevel@tonic-gate } 20217c478bd9Sstevel@tonic-gate if (--mcast->llcm_refcnt > 0) 20227c478bd9Sstevel@tonic-gate return; 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate mp = allocb(sizeof (dl_disabmulti_req_t) + ETHERADDRL, BPRI_MED); 20257c478bd9Sstevel@tonic-gate if (mp) { 20267c478bd9Sstevel@tonic-gate dis = (dl_disabmulti_req_t *)mp->b_rptr; 20277c478bd9Sstevel@tonic-gate mp->b_wptr = 20287c478bd9Sstevel@tonic-gate mp->b_rptr + sizeof (dl_disabmulti_req_t) + ETHERADDRL; 20297c478bd9Sstevel@tonic-gate dis->dl_primitive = DL_DISABMULTI_REQ; 20307c478bd9Sstevel@tonic-gate dis->dl_addr_offset = sizeof (dl_disabmulti_req_t); 20317c478bd9Sstevel@tonic-gate dis->dl_addr_length = ETHERADDRL; 20327c478bd9Sstevel@tonic-gate bcopy(mcast->llcm_addr, 20337c478bd9Sstevel@tonic-gate (mp->b_rptr + sizeof (dl_disabmulti_req_t)), ETHERADDRL); 20347c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 20357c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), mp); 20367c478bd9Sstevel@tonic-gate } 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * llc1_findminor(device) searches the per device class list of STREAMS for 20417c478bd9Sstevel@tonic-gate * the first minor number not used. Note that we currently don't allocate 20427c478bd9Sstevel@tonic-gate * minor 0. 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate static minor_t 20467c478bd9Sstevel@tonic-gate llc1_findminor(llc1dev_t *device) 20477c478bd9Sstevel@tonic-gate { 20487c478bd9Sstevel@tonic-gate llc1_t *next; 20497c478bd9Sstevel@tonic-gate minor_t minor; 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate ASSERT(device != NULL); 20527c478bd9Sstevel@tonic-gate for (minor = 1; minor <= MAXMIN32; minor++) { 20537c478bd9Sstevel@tonic-gate for (next = device->llc1_str_next; 20547c478bd9Sstevel@tonic-gate next != NULL && next != (llc1_t *)&device->llc1_str_next; 20557c478bd9Sstevel@tonic-gate next = next->llc_next) { 20567c478bd9Sstevel@tonic-gate if (minor == next->llc_minor) 20577c478bd9Sstevel@tonic-gate goto nextminor; 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate return (minor); 20607c478bd9Sstevel@tonic-gate nextminor: 20617c478bd9Sstevel@tonic-gate /* don't need to do anything */ 20627c478bd9Sstevel@tonic-gate ; 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 20657c478bd9Sstevel@tonic-gate return (0); 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate /* 20697c478bd9Sstevel@tonic-gate * llc1_req_info(q) simply construct a DL_INFO_REQ to be sent to the lower 20707c478bd9Sstevel@tonic-gate * stream this is used to populate the macinfo structure. 20717c478bd9Sstevel@tonic-gate */ 20727c478bd9Sstevel@tonic-gate static int 20737c478bd9Sstevel@tonic-gate llc1_req_info(queue_t *q) 20747c478bd9Sstevel@tonic-gate { 20757c478bd9Sstevel@tonic-gate dl_info_req_t *info; 20767c478bd9Sstevel@tonic-gate mblk_t *mp; 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate mp = allocb(DL_INFO_REQ_SIZE, BPRI_MED); 20797c478bd9Sstevel@tonic-gate if (mp == NULL) 20807c478bd9Sstevel@tonic-gate return (-1); 20817c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 20827c478bd9Sstevel@tonic-gate info = (dl_info_req_t *)mp->b_rptr; 20837c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + DL_INFO_REQ_SIZE; 20847c478bd9Sstevel@tonic-gate info->dl_primitive = DL_INFO_REQ; 20857c478bd9Sstevel@tonic-gate putnext(q, mp); 20867c478bd9Sstevel@tonic-gate return (0); 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate /* 20907c478bd9Sstevel@tonic-gate * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode 20917c478bd9Sstevel@tonic-gate */ 20927c478bd9Sstevel@tonic-gate static void 20937c478bd9Sstevel@tonic-gate llc1_req_raw(llc_mac_info_t *macinfo) 20947c478bd9Sstevel@tonic-gate { 20957c478bd9Sstevel@tonic-gate mblk_t *mp; 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate mp = mkiocb(DLIOCRAW); 20987c478bd9Sstevel@tonic-gate if (mp == NULL) 20997c478bd9Sstevel@tonic-gate return; 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate macinfo->llcp_iocid = ((struct iocblk *)mp->b_rptr)->ioc_id; 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp); 21047c478bd9Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_RAW_WAIT; 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate /* 21087c478bd9Sstevel@tonic-gate * llc1_send_bindreq 21097c478bd9Sstevel@tonic-gate * if lower stream isn't bound, bind it to something appropriate 21107c478bd9Sstevel@tonic-gate */ 21117c478bd9Sstevel@tonic-gate static void 21127c478bd9Sstevel@tonic-gate llc1_send_bindreq(llc_mac_info_t *macinfo) 21137c478bd9Sstevel@tonic-gate { 21147c478bd9Sstevel@tonic-gate mblk_t *mp; 21157c478bd9Sstevel@tonic-gate dl_bind_req_t *bind; 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate if (macinfo->llcp_sap >= 0xFF) { 21187c478bd9Sstevel@tonic-gate /* have to quite sometime if the world is failing */ 21197c478bd9Sstevel@tonic-gate macinfo->llcp_sap &= ~(LLC1_BINDING|LLC1_AVAILABLE); 21207c478bd9Sstevel@tonic-gate return; 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate mp = allocb(sizeof (dl_bind_req_t), BPRI_MED); 21247c478bd9Sstevel@tonic-gate if (mp == NULL) 21257c478bd9Sstevel@tonic-gate return; 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate bind = (dl_bind_req_t *)mp->b_rptr; 21287c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (dl_bind_req_t); 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate bind->dl_primitive = DL_BIND_REQ; 21317c478bd9Sstevel@tonic-gate bind->dl_sap = macinfo->llcp_sap += 2; /* starts at 2, inc by 2 */ 21327c478bd9Sstevel@tonic-gate macinfo->llcp_flags |= LLC1_BINDING; 21337c478bd9Sstevel@tonic-gate bind->dl_max_conind = 0; 21347c478bd9Sstevel@tonic-gate bind->dl_service_mode = DL_CLDLS; 21357c478bd9Sstevel@tonic-gate bind->dl_conn_mgmt = 0; 21367c478bd9Sstevel@tonic-gate bind->dl_xidtest_flg = 0; 21377c478bd9Sstevel@tonic-gate putnext(macinfo->llcp_queue, mp); 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate /* 21417c478bd9Sstevel@tonic-gate * llc1_form_udata(lld, macinfo, mp) format a DL_UNITDATA_IND message to be 21427c478bd9Sstevel@tonic-gate * sent to the user 21437c478bd9Sstevel@tonic-gate */ 21447c478bd9Sstevel@tonic-gate static mblk_t * 21457c478bd9Sstevel@tonic-gate llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp) 21467c478bd9Sstevel@tonic-gate { 21477c478bd9Sstevel@tonic-gate mblk_t *udmp, *nmp; 21487c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *udata; 21497c478bd9Sstevel@tonic-gate struct ether_header *hdr; 21507c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 21517c478bd9Sstevel@tonic-gate struct snaphdr *snap; 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) { 21547c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 21557c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate /* allocate the DL_UNITDATA_IND M_PROTO header */ 21587c478bd9Sstevel@tonic-gate udmp = allocb(sizeof (dl_unitdata_ind_t) + 21597c478bd9Sstevel@tonic-gate 2 * (macinfo->llcp_addrlen + 5), BPRI_MED); 21607c478bd9Sstevel@tonic-gate if (udmp == NULL) { 21617c478bd9Sstevel@tonic-gate /* might as well discard since we can't go further */ 21627c478bd9Sstevel@tonic-gate freemsg(mp); 21637c478bd9Sstevel@tonic-gate return (NULL); 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate udata = (dl_unitdata_ind_t *)udmp->b_rptr; 21667c478bd9Sstevel@tonic-gate udmp->b_wptr += sizeof (dl_unitdata_ind_t); 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); /* make a copy for future streams */ 21697c478bd9Sstevel@tonic-gate if (lld->llc_sap != LLC_NOVELL_SAP) 21707c478bd9Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header) + 21717c478bd9Sstevel@tonic-gate sizeof (struct llchdr); 21727c478bd9Sstevel@tonic-gate else 21737c478bd9Sstevel@tonic-gate mp->b_rptr += sizeof (struct ether_header); 21747c478bd9Sstevel@tonic-gate 21757c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 21767c478bd9Sstevel@tonic-gate mp->b_rptr += sizeof (struct snaphdr); 21777c478bd9Sstevel@tonic-gate snap = (struct snaphdr *)(llchdr + 1); 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * now setup the DL_UNITDATA_IND header 21827c478bd9Sstevel@tonic-gate */ 21837c478bd9Sstevel@tonic-gate DB_TYPE(udmp) = M_PROTO; 21847c478bd9Sstevel@tonic-gate udata->dl_primitive = DL_UNITDATA_IND; 21857c478bd9Sstevel@tonic-gate udata->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t); 21867c478bd9Sstevel@tonic-gate bcopy(hdr->ether_dhost.ether_addr_octet, 21877c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_dest_addr_offset)->llca_addr, 21887c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 21917c478bd9Sstevel@tonic-gate udata->dl_dest_addr_length = macinfo->llcp_addrlen + 2; 21927c478bd9Sstevel@tonic-gate LLCSADDR(udata, udata->dl_dest_addr_offset)->llca_ssap = 21937c478bd9Sstevel@tonic-gate ntohs(*(ushort_t *)snap->snap_type); 21947c478bd9Sstevel@tonic-gate } else { 21957c478bd9Sstevel@tonic-gate udata->dl_dest_addr_length = macinfo->llcp_addrlen + 1; 21967c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap = 21977c478bd9Sstevel@tonic-gate llchdr->llc_dsap; 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate udmp->b_wptr += udata->dl_dest_addr_length; 22007c478bd9Sstevel@tonic-gate udata->dl_src_addr_offset = udata->dl_dest_addr_length + 22017c478bd9Sstevel@tonic-gate udata->dl_dest_addr_offset; 22027c478bd9Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet, 22037c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_src_addr_offset)->llca_addr, 22047c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 22057c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 22067c478bd9Sstevel@tonic-gate udata->dl_src_addr_length = macinfo->llcp_addrlen + 2; 22077c478bd9Sstevel@tonic-gate LLCSADDR(udata, udata->dl_src_addr_offset)->llca_ssap = 22087c478bd9Sstevel@tonic-gate ntohs(*(ushort_t *)snap->snap_type); 22097c478bd9Sstevel@tonic-gate } else { 22107c478bd9Sstevel@tonic-gate udata->dl_src_addr_length = macinfo->llcp_addrlen + 1; 22117c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap = 22127c478bd9Sstevel@tonic-gate llchdr->llc_ssap; 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate udata->dl_group_address = hdr->ether_dhost.ether_addr_octet[0] & 22157c478bd9Sstevel@tonic-gate 0x1; 22167c478bd9Sstevel@tonic-gate udmp->b_wptr += udata->dl_src_addr_length; 22177c478bd9Sstevel@tonic-gate udmp->b_cont = mp; 22187c478bd9Sstevel@tonic-gate } else { 22197c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *ud2; 22207c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) { 22217c478bd9Sstevel@tonic-gate return (mp); /* we can't do anything */ 22227c478bd9Sstevel@tonic-gate } 22237c478bd9Sstevel@tonic-gate /* if we end up here, we only want to patch the existing M_PROTO */ 22247c478bd9Sstevel@tonic-gate nmp = dupmsg(mp); /* make a copy for future streams */ 22257c478bd9Sstevel@tonic-gate udata = (dl_unitdata_ind_t *)(mp->b_rptr); 22267c478bd9Sstevel@tonic-gate udmp = allocb(MBLKL(mp) + 4, BPRI_MED); 22277c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, udmp->b_rptr, sizeof (dl_unitdata_ind_t)); 22287c478bd9Sstevel@tonic-gate ud2 = (dl_unitdata_ind_t *)(udmp->b_rptr); 22297c478bd9Sstevel@tonic-gate udmp->b_wptr += sizeof (dl_unitdata_ind_t); 22307c478bd9Sstevel@tonic-gate bcopy((caddr_t)mp->b_rptr + udata->dl_dest_addr_offset, 22317c478bd9Sstevel@tonic-gate udmp->b_wptr, macinfo->llcp_addrlen); 22327c478bd9Sstevel@tonic-gate ud2->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t); 22337c478bd9Sstevel@tonic-gate ud2->dl_dest_addr_length = macinfo->llcp_addrlen + 1; 22347c478bd9Sstevel@tonic-gate udmp->b_wptr += ud2->dl_dest_addr_length; 22357c478bd9Sstevel@tonic-gate bcopy((caddr_t)udmp->b_rptr + udata->dl_src_addr_offset, 22367c478bd9Sstevel@tonic-gate udmp->b_wptr, macinfo->llcp_addrlen); 22377c478bd9Sstevel@tonic-gate ud2->dl_src_addr_length = ud2->dl_dest_addr_length; 22387c478bd9Sstevel@tonic-gate udmp->b_wptr += ud2->dl_src_addr_length; 22397c478bd9Sstevel@tonic-gate udmp->b_cont = mp->b_cont; 22407c478bd9Sstevel@tonic-gate if (lld->llc_sap != LLC_NOVELL_SAP) 22417c478bd9Sstevel@tonic-gate mp->b_cont->b_rptr += sizeof (struct llchdr); 22427c478bd9Sstevel@tonic-gate freeb(mp); 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate DB_TYPE(udmp) = M_PROTO; 22457c478bd9Sstevel@tonic-gate udata = (dl_unitdata_ind_t *)(mp->b_rptr); 22467c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(mp->b_cont->b_rptr); 22477c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap = 22487c478bd9Sstevel@tonic-gate llchdr->llc_dsap; 22497c478bd9Sstevel@tonic-gate LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap = 22507c478bd9Sstevel@tonic-gate llchdr->llc_ssap; 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate #ifdef LLC1_DEBUG 22537c478bd9Sstevel@tonic-gate if (llc1_debug & LLCRECV) 22547c478bd9Sstevel@tonic-gate printf("llc1_recv: queued message to %x (%d)\n", 22557c478bd9Sstevel@tonic-gate lld->llc_qptr, lld->llc_minor); 22567c478bd9Sstevel@tonic-gate #endif 22577c478bd9Sstevel@tonic-gate /* enqueue for the service routine to process */ 22587c478bd9Sstevel@tonic-gate putnext(RD(lld->llc_qptr), udmp); 22597c478bd9Sstevel@tonic-gate mp = nmp; 22607c478bd9Sstevel@tonic-gate return (mp); 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * llc1_xid_reply(macinfo, mp) automatic reply to an XID command 22657c478bd9Sstevel@tonic-gate */ 22667c478bd9Sstevel@tonic-gate static mblk_t * 22677c478bd9Sstevel@tonic-gate llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap) 22687c478bd9Sstevel@tonic-gate { 22697c478bd9Sstevel@tonic-gate mblk_t *nmp, *rmp; 22707c478bd9Sstevel@tonic-gate struct ether_header *hdr, *msgether; 22717c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 22727c478bd9Sstevel@tonic-gate struct llchdr *msgllc; 22737c478bd9Sstevel@tonic-gate struct llchdr_xid *xid; 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) { 22767c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 22777c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 22787c478bd9Sstevel@tonic-gate } else { 22797c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) 22807c478bd9Sstevel@tonic-gate return (mp); 22817c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(mp->b_cont->b_rptr); 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate /* we only want to respond to commands to avoid response loops */ 22857c478bd9Sstevel@tonic-gate if (llchdr->llc_ssap & LLC_RESPONSE) 22867c478bd9Sstevel@tonic-gate return (mp); 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate nmp = allocb(msgdsize(mp) + LLC_XID_INFO_SIZE, BPRI_MED); 22897c478bd9Sstevel@tonic-gate if (nmp == NULL) { 22907c478bd9Sstevel@tonic-gate return (mp); 22917c478bd9Sstevel@tonic-gate } 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* 22947c478bd9Sstevel@tonic-gate * now construct the XID reply frame 22957c478bd9Sstevel@tonic-gate */ 22967c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) { 22977c478bd9Sstevel@tonic-gate msgether = (struct ether_header *)nmp->b_rptr; 22987c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct ether_header); 22997c478bd9Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet, 23007c478bd9Sstevel@tonic-gate msgether->ether_dhost.ether_addr_octet, 23017c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 23027c478bd9Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr, 23037c478bd9Sstevel@tonic-gate msgether->ether_shost.ether_addr_octet, 23047c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 23057c478bd9Sstevel@tonic-gate msgether->ether_type = htons(sizeof (struct llchdr_xid) + 23067c478bd9Sstevel@tonic-gate sizeof (struct llchdr)); 23077c478bd9Sstevel@tonic-gate rmp = nmp; 23087c478bd9Sstevel@tonic-gate } else { 23097c478bd9Sstevel@tonic-gate dl_unitdata_req_t *ud; 23107c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *rud; 23117c478bd9Sstevel@tonic-gate rud = (dl_unitdata_ind_t *)mp->b_rptr; 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) + 23147c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen + 5, BPRI_MED); 23157c478bd9Sstevel@tonic-gate if (rmp == NULL) 23167c478bd9Sstevel@tonic-gate return (mp); 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO; 23197c478bd9Sstevel@tonic-gate bzero(rmp->b_rptr, sizeof (dl_unitdata_req_t)); 23207c478bd9Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr; 23217c478bd9Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ; 23227c478bd9Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t); 23237c478bd9Sstevel@tonic-gate ud->dl_dest_addr_length = macinfo->llcp_addrlen + 1; 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t); 23267c478bd9Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, rud->dl_src_addr_offset), 23277c478bd9Sstevel@tonic-gate LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset), 23287c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 23297c478bd9Sstevel@tonic-gate LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset)->llca_sap = 23307c478bd9Sstevel@tonic-gate LLCADDR(mp->b_rptr, rud->dl_src_addr_offset)->llca_sap; 23317c478bd9Sstevel@tonic-gate rmp->b_wptr += sizeof (struct llcaddr); 23327c478bd9Sstevel@tonic-gate rmp->b_cont = nmp; 23337c478bd9Sstevel@tonic-gate } 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate msgllc = (struct llchdr *)nmp->b_wptr; 23367c478bd9Sstevel@tonic-gate xid = (struct llchdr_xid *)(msgllc + 1); 23377c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr); 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate msgllc->llc_dsap = llchdr->llc_ssap; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate /* mark it a response */ 23427c478bd9Sstevel@tonic-gate msgllc->llc_ssap = sap | LLC_RESPONSE; 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate msgllc->llc_ctl = llchdr->llc_ctl; 23457c478bd9Sstevel@tonic-gate xid->llcx_format = LLC_XID_FMTID; 23467c478bd9Sstevel@tonic-gate xid->llcx_class = LLC_XID_TYPE_1; 23477c478bd9Sstevel@tonic-gate xid->llcx_window = 0; /* we don't have connections yet */ 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr_xid); 23507c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidxmt++; 23517c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp); 23527c478bd9Sstevel@tonic-gate return (mp); 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate /* 23567c478bd9Sstevel@tonic-gate * llc1_xid_ind_con(lld, macinfo, mp) form a DL_XID_IND or DL_XID_CON message 23577c478bd9Sstevel@tonic-gate * to send to the user since it was requested that the user process these 23587c478bd9Sstevel@tonic-gate * messages 23597c478bd9Sstevel@tonic-gate */ 23607c478bd9Sstevel@tonic-gate static mblk_t * 23617c478bd9Sstevel@tonic-gate llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp) 23627c478bd9Sstevel@tonic-gate { 23637c478bd9Sstevel@tonic-gate mblk_t *nmp; 23647c478bd9Sstevel@tonic-gate dl_xid_ind_t *xid; 23657c478bd9Sstevel@tonic-gate struct ether_header *hdr; 23667c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 23677c478bd9Sstevel@tonic-gate int raw; 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (dl_xid_ind_t) + 2 * (macinfo->llcp_addrlen + 1), 23707c478bd9Sstevel@tonic-gate BPRI_MED); 23717c478bd9Sstevel@tonic-gate if (nmp == NULL) 23727c478bd9Sstevel@tonic-gate return (mp); 23737c478bd9Sstevel@tonic-gate 23747c478bd9Sstevel@tonic-gate if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) { 23757c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 23767c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 23777c478bd9Sstevel@tonic-gate } else { 23787c478bd9Sstevel@tonic-gate if (mp->b_rptr == NULL) 23797c478bd9Sstevel@tonic-gate return (mp); 23807c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr; 23817c478bd9Sstevel@tonic-gate } 23827c478bd9Sstevel@tonic-gate 23837c478bd9Sstevel@tonic-gate xid = (dl_xid_ind_t *)nmp->b_rptr; 23847c478bd9Sstevel@tonic-gate xid->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0; 23857c478bd9Sstevel@tonic-gate xid->dl_dest_addr_offset = sizeof (dl_xid_ind_t); 23867c478bd9Sstevel@tonic-gate xid->dl_dest_addr_length = macinfo->llcp_addrlen + 1; 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate if (raw) { 23897c478bd9Sstevel@tonic-gate bcopy(hdr->ether_dhost.ether_addr_octet, 23907c478bd9Sstevel@tonic-gate (nmp->b_rptr + xid->dl_dest_addr_offset), 23917c478bd9Sstevel@tonic-gate xid->dl_dest_addr_length); 23927c478bd9Sstevel@tonic-gate } else { 23937c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *ind; 23947c478bd9Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr; 23957c478bd9Sstevel@tonic-gate bcopy(LLCADDR(ind, ind->dl_dest_addr_offset), 23967c478bd9Sstevel@tonic-gate (nmp->b_rptr + xid->dl_dest_addr_offset), 23977c478bd9Sstevel@tonic-gate xid->dl_dest_addr_length); 23987c478bd9Sstevel@tonic-gate } 23997c478bd9Sstevel@tonic-gate 24007c478bd9Sstevel@tonic-gate LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap = 24017c478bd9Sstevel@tonic-gate llchdr->llc_dsap; 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate xid->dl_src_addr_offset = 24047c478bd9Sstevel@tonic-gate xid->dl_dest_addr_offset + xid->dl_dest_addr_length; 24057c478bd9Sstevel@tonic-gate xid->dl_src_addr_length = xid->dl_dest_addr_length; 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate if (raw) { 24087c478bd9Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet, 24097c478bd9Sstevel@tonic-gate (nmp->b_rptr + xid->dl_src_addr_offset), 24107c478bd9Sstevel@tonic-gate xid->dl_src_addr_length); 24117c478bd9Sstevel@tonic-gate } else { 24127c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *ind; 24137c478bd9Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr; 24147c478bd9Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset), 24157c478bd9Sstevel@tonic-gate (nmp->b_rptr + xid->dl_src_addr_offset), 24167c478bd9Sstevel@tonic-gate ind->dl_src_addr_length); 24177c478bd9Sstevel@tonic-gate } 24187c478bd9Sstevel@tonic-gate LLCADDR(nmp->b_rptr, xid->dl_src_addr_offset)->llca_sap = 24197c478bd9Sstevel@tonic-gate llchdr->llc_ssap & ~LLC_RESPONSE; 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_xid_ind_t) + 24227c478bd9Sstevel@tonic-gate 2 * xid->dl_dest_addr_length; 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate if (!(llchdr->llc_ssap & LLC_RESPONSE)) { 24257c478bd9Sstevel@tonic-gate xid->dl_primitive = DL_XID_IND; 24267c478bd9Sstevel@tonic-gate } else { 24277c478bd9Sstevel@tonic-gate xid->dl_primitive = DL_XID_CON; 24287c478bd9Sstevel@tonic-gate } 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO; 24317c478bd9Sstevel@tonic-gate if (raw) { 24327c478bd9Sstevel@tonic-gate if (MBLKL(mp) > 24337c478bd9Sstevel@tonic-gate (sizeof (struct ether_header) + sizeof (struct llchdr))) { 24347c478bd9Sstevel@tonic-gate nmp->b_cont = dupmsg(mp); 24357c478bd9Sstevel@tonic-gate if (nmp->b_cont) { 24367c478bd9Sstevel@tonic-gate nmp->b_cont->b_rptr += 24377c478bd9Sstevel@tonic-gate sizeof (struct ether_header) + 24387c478bd9Sstevel@tonic-gate sizeof (struct llchdr); 24397c478bd9Sstevel@tonic-gate } 24407c478bd9Sstevel@tonic-gate } 24417c478bd9Sstevel@tonic-gate } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) > 24427c478bd9Sstevel@tonic-gate sizeof (struct llchdr)) { 24437c478bd9Sstevel@tonic-gate nmp->b_cont = dupmsg(mp->b_cont); 24447c478bd9Sstevel@tonic-gate (void) adjmsg(nmp->b_cont, sizeof (struct llchdr)); 24457c478bd9Sstevel@tonic-gate } 24467c478bd9Sstevel@tonic-gate putnext(RD(lld->llc_qptr), nmp); 24477c478bd9Sstevel@tonic-gate return (mp); 24487c478bd9Sstevel@tonic-gate } 24497c478bd9Sstevel@tonic-gate 24507c478bd9Sstevel@tonic-gate /* 24517c478bd9Sstevel@tonic-gate * llc1_xid_req_res(q, mp, req_or_res) the user wants to send an XID message 24527c478bd9Sstevel@tonic-gate * or response construct a proper message and put on the net 24537c478bd9Sstevel@tonic-gate */ 24547c478bd9Sstevel@tonic-gate static int 24557c478bd9Sstevel@tonic-gate llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res) 24567c478bd9Sstevel@tonic-gate { 24577c478bd9Sstevel@tonic-gate dl_xid_req_t *xid = (dl_xid_req_t *)mp->b_rptr; 24587c478bd9Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr; 24597c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 24607c478bd9Sstevel@tonic-gate mblk_t *nmp, *rmp; 24617c478bd9Sstevel@tonic-gate struct ether_header *hdr; 24627c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate if (llc == NULL || llc->llc_state == DL_UNATTACHED) 24657c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate if (llc->llc_sap == LLC_NOVELL_SAP) 24687c478bd9Sstevel@tonic-gate return (DL_NOTSUPPORTED); 24697c478bd9Sstevel@tonic-gate 24707c478bd9Sstevel@tonic-gate if (llc->llc_flags & DL_AUTO_XID) 24717c478bd9Sstevel@tonic-gate return (DL_XIDAUTO); 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate macinfo = llc->llc_mac_info; 24747c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_xid_req_t) || 24757c478bd9Sstevel@tonic-gate !MBLKIN(mp, xid->dl_dest_addr_offset, xid->dl_dest_addr_length)) { 24767c478bd9Sstevel@tonic-gate return (DL_BADPRIM); 24777c478bd9Sstevel@tonic-gate } 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr) + 24807c478bd9Sstevel@tonic-gate sizeof (struct llchdr_xid), BPRI_MED); 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate if (nmp == NULL) 24837c478bd9Sstevel@tonic-gate return (LLCE_NOBUFFER); 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) { 24867c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)nmp->b_rptr; 24877c478bd9Sstevel@tonic-gate bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr, 24887c478bd9Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet, ETHERADDRL); 24897c478bd9Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr, 24907c478bd9Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet, ETHERADDRL); 24917c478bd9Sstevel@tonic-gate hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp)); 24927c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + 24937c478bd9Sstevel@tonic-gate sizeof (struct ether_header) + sizeof (struct llchdr); 24947c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 24957c478bd9Sstevel@tonic-gate rmp = nmp; 24967c478bd9Sstevel@tonic-gate } else { 24977c478bd9Sstevel@tonic-gate dl_unitdata_req_t *ud; 24987c478bd9Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) + 24997c478bd9Sstevel@tonic-gate (macinfo->llcp_addrlen + 2), BPRI_MED); 25007c478bd9Sstevel@tonic-gate if (rmp == NULL) { 25017c478bd9Sstevel@tonic-gate freemsg(nmp); 25027c478bd9Sstevel@tonic-gate return (LLCE_NOBUFFER); 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr; 25057c478bd9Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO; 25067c478bd9Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ; 25077c478bd9Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t); 25087c478bd9Sstevel@tonic-gate ud->dl_dest_addr_length = xid->dl_dest_addr_length; 25097c478bd9Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t); 25107c478bd9Sstevel@tonic-gate bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr, 25117c478bd9Sstevel@tonic-gate LLCADDR(ud, ud->dl_dest_addr_offset), 25127c478bd9Sstevel@tonic-gate xid->dl_dest_addr_length); 25137c478bd9Sstevel@tonic-gate LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap = 25147c478bd9Sstevel@tonic-gate msgdsize(mp); 25157c478bd9Sstevel@tonic-gate rmp->b_wptr += xid->dl_dest_addr_length; 25167c478bd9Sstevel@tonic-gate rmp->b_cont = nmp; 25177c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_rptr; 25187c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr); 25197c478bd9Sstevel@tonic-gate } 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate llchdr->llc_dsap = LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap; 25227c478bd9Sstevel@tonic-gate llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0); 25237c478bd9Sstevel@tonic-gate llchdr->llc_ctl = 25247c478bd9Sstevel@tonic-gate LLC_XID | ((xid->dl_flag & DL_POLL_FINAL) ? LLC_P : 0); 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate nmp->b_cont = mp->b_cont; 25277c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 25287c478bd9Sstevel@tonic-gate freeb(mp); 25297c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_xidxmt++; 25307c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp); 25317c478bd9Sstevel@tonic-gate return (LLCE_OK); 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * llc1_test_reply(macinfo, mp) 25367c478bd9Sstevel@tonic-gate * automatic reply to a TEST message 25377c478bd9Sstevel@tonic-gate */ 25387c478bd9Sstevel@tonic-gate static mblk_t * 25397c478bd9Sstevel@tonic-gate llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap) 25407c478bd9Sstevel@tonic-gate { 25417c478bd9Sstevel@tonic-gate mblk_t *nmp; 25427c478bd9Sstevel@tonic-gate struct ether_header *hdr, *msgether; 25437c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 25447c478bd9Sstevel@tonic-gate struct llchdr *msgllc; 25457c478bd9Sstevel@tonic-gate int poll_final; 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) { 25487c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) 25497c478bd9Sstevel@tonic-gate return (mp); 25507c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr; 25517c478bd9Sstevel@tonic-gate hdr = NULL; 25527c478bd9Sstevel@tonic-gate } else { 25537c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 25547c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 25557c478bd9Sstevel@tonic-gate } 25567c478bd9Sstevel@tonic-gate 25577c478bd9Sstevel@tonic-gate /* we only want to respond to commands to avoid response loops */ 25587c478bd9Sstevel@tonic-gate if (llchdr->llc_ssap & LLC_RESPONSE) 25597c478bd9Sstevel@tonic-gate return (mp); 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate nmp = copymsg(mp); /* so info field is duplicated */ 25627c478bd9Sstevel@tonic-gate if (nmp == NULL) { 25637c478bd9Sstevel@tonic-gate nmp = mp; 25647c478bd9Sstevel@tonic-gate mp = NULL; 25657c478bd9Sstevel@tonic-gate } 25667c478bd9Sstevel@tonic-gate /* 25677c478bd9Sstevel@tonic-gate * now construct the TEST reply frame 25687c478bd9Sstevel@tonic-gate */ 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate poll_final = llchdr->llc_ctl & LLC_P; 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate if (DB_TYPE(nmp) == M_PROTO) { 25747c478bd9Sstevel@tonic-gate dl_unitdata_req_t *udr = (dl_unitdata_req_t *)nmp->b_rptr; 25757c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *udi = (dl_unitdata_ind_t *)nmp->b_rptr; 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate /* make into a request */ 25787c478bd9Sstevel@tonic-gate udr->dl_primitive = DL_UNITDATA_REQ; 25797c478bd9Sstevel@tonic-gate udr->dl_dest_addr_offset = udi->dl_src_addr_offset; 25807c478bd9Sstevel@tonic-gate udr->dl_dest_addr_length = udi->dl_src_addr_length; 25817c478bd9Sstevel@tonic-gate udr->dl_priority.dl_min = udr->dl_priority.dl_max = 0; 25827c478bd9Sstevel@tonic-gate msgllc = (struct llchdr *)nmp->b_cont->b_rptr; 25837c478bd9Sstevel@tonic-gate } else { 25847c478bd9Sstevel@tonic-gate msgether = (struct ether_header *)nmp->b_rptr; 25857c478bd9Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet, 25867c478bd9Sstevel@tonic-gate msgether->ether_dhost.ether_addr_octet, 25877c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 25887c478bd9Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr, 25897c478bd9Sstevel@tonic-gate msgether->ether_shost.ether_addr_octet, 25907c478bd9Sstevel@tonic-gate macinfo->llcp_addrlen); 25917c478bd9Sstevel@tonic-gate msgllc = (struct llchdr *)(msgether+1); 25927c478bd9Sstevel@tonic-gate } 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate msgllc->llc_dsap = llchdr->llc_ssap; 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate /* mark it as a response */ 25977c478bd9Sstevel@tonic-gate msgllc->llc_ssap = sap | LLC_RESPONSE; 25987c478bd9Sstevel@tonic-gate msgllc->llc_ctl = LLC_TEST | poll_final; 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_testxmt++; 26017c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), nmp); 26027c478bd9Sstevel@tonic-gate return (mp); 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate /* 26067c478bd9Sstevel@tonic-gate * llc1_test_ind_con(lld, macinfo, mp) form a DL_TEST_IND or DL_TEST_CON 26077c478bd9Sstevel@tonic-gate * message to send to the user since it was requested that the user process 26087c478bd9Sstevel@tonic-gate * these messages 26097c478bd9Sstevel@tonic-gate */ 26107c478bd9Sstevel@tonic-gate static mblk_t * 26117c478bd9Sstevel@tonic-gate llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp) 26127c478bd9Sstevel@tonic-gate { 26137c478bd9Sstevel@tonic-gate mblk_t *nmp; 26147c478bd9Sstevel@tonic-gate dl_test_ind_t *test; 26157c478bd9Sstevel@tonic-gate struct ether_header *hdr; 26167c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 26177c478bd9Sstevel@tonic-gate int raw; 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (dl_test_ind_t) + 2 * (ETHERADDRL + 1), BPRI_MED); 26207c478bd9Sstevel@tonic-gate if (nmp == NULL) 26217c478bd9Sstevel@tonic-gate return (NULL); 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) { 26247c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)mp->b_rptr; 26257c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 26267c478bd9Sstevel@tonic-gate } else { 26277c478bd9Sstevel@tonic-gate if (mp->b_rptr == NULL) 26287c478bd9Sstevel@tonic-gate return (mp); 26297c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)mp->b_cont->b_rptr; 26307c478bd9Sstevel@tonic-gate } 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate test = (dl_test_ind_t *)nmp->b_rptr; 26337c478bd9Sstevel@tonic-gate test->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0; 26347c478bd9Sstevel@tonic-gate test->dl_dest_addr_offset = sizeof (dl_test_ind_t); 26357c478bd9Sstevel@tonic-gate test->dl_dest_addr_length = macinfo->llcp_addrlen + 1; 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate if (raw) { 26387c478bd9Sstevel@tonic-gate bcopy(hdr->ether_dhost.ether_addr_octet, 26397c478bd9Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_dest_addr_offset)->llca_addr, 26407c478bd9Sstevel@tonic-gate test->dl_dest_addr_length); 26417c478bd9Sstevel@tonic-gate } else { 26427c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *ind; 26437c478bd9Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr; 26447c478bd9Sstevel@tonic-gate bcopy(LLCADDR(ind, ind->dl_dest_addr_offset), 26457c478bd9Sstevel@tonic-gate (nmp->b_rptr + test->dl_dest_addr_offset), 26467c478bd9Sstevel@tonic-gate test->dl_dest_addr_length); 26477c478bd9Sstevel@tonic-gate } 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate LLCADDR(test, test->dl_dest_addr_offset)->llca_sap = 26507c478bd9Sstevel@tonic-gate llchdr->llc_dsap; 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate test->dl_src_addr_offset = test->dl_dest_addr_offset + 26537c478bd9Sstevel@tonic-gate test->dl_dest_addr_length; 26547c478bd9Sstevel@tonic-gate test->dl_src_addr_length = test->dl_dest_addr_length; 26557c478bd9Sstevel@tonic-gate 26567c478bd9Sstevel@tonic-gate if (raw) { 26577c478bd9Sstevel@tonic-gate bcopy(hdr->ether_shost.ether_addr_octet, 26587c478bd9Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_addr, 26597c478bd9Sstevel@tonic-gate test->dl_src_addr_length); 26607c478bd9Sstevel@tonic-gate } else { 26617c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *ind; 26627c478bd9Sstevel@tonic-gate ind = (dl_unitdata_ind_t *)mp->b_rptr; 26637c478bd9Sstevel@tonic-gate bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset), 26647c478bd9Sstevel@tonic-gate (nmp->b_rptr + test->dl_src_addr_offset), 26657c478bd9Sstevel@tonic-gate ind->dl_src_addr_length); 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_sap = 26687c478bd9Sstevel@tonic-gate llchdr->llc_ssap & ~LLC_RESPONSE; 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + sizeof (dl_test_ind_t) + 26717c478bd9Sstevel@tonic-gate 2 * test->dl_dest_addr_length; 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate if (!(llchdr->llc_ssap & LLC_RESPONSE)) { 26747c478bd9Sstevel@tonic-gate test->dl_primitive = DL_TEST_IND; 26757c478bd9Sstevel@tonic-gate } else { 26767c478bd9Sstevel@tonic-gate test->dl_primitive = DL_TEST_CON; 26777c478bd9Sstevel@tonic-gate } 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO; 26807c478bd9Sstevel@tonic-gate if (raw) { 26817c478bd9Sstevel@tonic-gate if (MBLKL(mp) > 26827c478bd9Sstevel@tonic-gate (sizeof (struct ether_header) + sizeof (struct llchdr))) { 26837c478bd9Sstevel@tonic-gate nmp->b_cont = dupmsg(mp); 26847c478bd9Sstevel@tonic-gate if (nmp->b_cont) { 26857c478bd9Sstevel@tonic-gate nmp->b_cont->b_rptr += 26867c478bd9Sstevel@tonic-gate sizeof (struct ether_header) + 26877c478bd9Sstevel@tonic-gate sizeof (struct llchdr); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) > 26917c478bd9Sstevel@tonic-gate sizeof (struct llchdr)) { 26927c478bd9Sstevel@tonic-gate nmp->b_cont = dupmsg(mp->b_cont); 26937c478bd9Sstevel@tonic-gate (void) adjmsg(nmp->b_cont, sizeof (struct llchdr)); 26947c478bd9Sstevel@tonic-gate } 26957c478bd9Sstevel@tonic-gate putnext(RD(lld->llc_qptr), nmp); 26967c478bd9Sstevel@tonic-gate return (mp); 26977c478bd9Sstevel@tonic-gate } 26987c478bd9Sstevel@tonic-gate 26997c478bd9Sstevel@tonic-gate /* 27007c478bd9Sstevel@tonic-gate * llc1_test_req_res(q, mp, req_or_res) the user wants to send a TEST 27017c478bd9Sstevel@tonic-gate * message or response construct a proper message and put on the net 27027c478bd9Sstevel@tonic-gate */ 27037c478bd9Sstevel@tonic-gate static int 27047c478bd9Sstevel@tonic-gate llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res) 27057c478bd9Sstevel@tonic-gate { 27067c478bd9Sstevel@tonic-gate dl_test_req_t *test = (dl_test_req_t *)mp->b_rptr; 27077c478bd9Sstevel@tonic-gate llc1_t *llc = (llc1_t *)q->q_ptr; 27087c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 27097c478bd9Sstevel@tonic-gate mblk_t *nmp, *rmp; 27107c478bd9Sstevel@tonic-gate struct ether_header *hdr; 27117c478bd9Sstevel@tonic-gate struct llchdr *llchdr; 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate if (llc == NULL || llc->llc_state == DL_UNATTACHED) 27147c478bd9Sstevel@tonic-gate return (DL_OUTSTATE); 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate if (llc->llc_sap == LLC_NOVELL_SAP) 27177c478bd9Sstevel@tonic-gate return (DL_NOTSUPPORTED); 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate if (llc->llc_flags & DL_AUTO_TEST) 27207c478bd9Sstevel@tonic-gate return (DL_TESTAUTO); 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate macinfo = llc->llc_mac_info; 27237c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_test_req_t) || 27247c478bd9Sstevel@tonic-gate !MBLKIN(mp, test->dl_dest_addr_offset, 27257c478bd9Sstevel@tonic-gate test->dl_dest_addr_length)) { 27267c478bd9Sstevel@tonic-gate return (DL_BADPRIM); 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr), 27307c478bd9Sstevel@tonic-gate BPRI_MED); 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate if (nmp == NULL) 27337c478bd9Sstevel@tonic-gate return (LLCE_NOBUFFER); 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate if (macinfo->llcp_flags & LLC1_USING_RAW) { 27367c478bd9Sstevel@tonic-gate hdr = (struct ether_header *)nmp->b_rptr; 27377c478bd9Sstevel@tonic-gate bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr, 27387c478bd9Sstevel@tonic-gate hdr->ether_dhost.ether_addr_octet, ETHERADDRL); 27397c478bd9Sstevel@tonic-gate bcopy(macinfo->llcp_macaddr, 27407c478bd9Sstevel@tonic-gate hdr->ether_shost.ether_addr_octet, ETHERADDRL); 27417c478bd9Sstevel@tonic-gate hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp)); 27427c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + 27437c478bd9Sstevel@tonic-gate sizeof (struct ether_header) + sizeof (struct llchdr); 27447c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)(hdr + 1); 27457c478bd9Sstevel@tonic-gate rmp = nmp; 27467c478bd9Sstevel@tonic-gate } else { 27477c478bd9Sstevel@tonic-gate dl_unitdata_req_t *ud; 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate rmp = allocb(sizeof (dl_unitdata_req_t) + 27507c478bd9Sstevel@tonic-gate (macinfo->llcp_addrlen + 2), BPRI_MED); 27517c478bd9Sstevel@tonic-gate if (rmp == NULL) { 27527c478bd9Sstevel@tonic-gate freemsg(nmp); 27537c478bd9Sstevel@tonic-gate return (LLCE_NOBUFFER); 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate ud = (dl_unitdata_req_t *)rmp->b_rptr; 27577c478bd9Sstevel@tonic-gate DB_TYPE(rmp) = M_PROTO; 27587c478bd9Sstevel@tonic-gate ud->dl_primitive = DL_UNITDATA_REQ; 27597c478bd9Sstevel@tonic-gate ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t); 27607c478bd9Sstevel@tonic-gate ud->dl_dest_addr_length = test->dl_dest_addr_length; 27617c478bd9Sstevel@tonic-gate rmp->b_wptr += sizeof (dl_unitdata_req_t); 27627c478bd9Sstevel@tonic-gate bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr, 27637c478bd9Sstevel@tonic-gate LLCADDR(ud, ud->dl_dest_addr_offset), 27647c478bd9Sstevel@tonic-gate test->dl_dest_addr_length); 27657c478bd9Sstevel@tonic-gate LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap = 27667c478bd9Sstevel@tonic-gate msgdsize(mp); 27677c478bd9Sstevel@tonic-gate rmp->b_wptr += test->dl_dest_addr_length; 27687c478bd9Sstevel@tonic-gate rmp->b_cont = nmp; 27697c478bd9Sstevel@tonic-gate llchdr = (struct llchdr *)nmp->b_rptr; 27707c478bd9Sstevel@tonic-gate nmp->b_wptr += sizeof (struct llchdr); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate llchdr->llc_dsap = LLCADDR(test, test->dl_dest_addr_offset)->llca_sap; 27747c478bd9Sstevel@tonic-gate llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0); 27757c478bd9Sstevel@tonic-gate llchdr->llc_ctl = 27767c478bd9Sstevel@tonic-gate LLC_TEST | ((test->dl_flag & DL_POLL_FINAL) ? LLC_P : 0); 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate nmp->b_cont = mp->b_cont; 27797c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 27807c478bd9Sstevel@tonic-gate freeb(mp); 27817c478bd9Sstevel@tonic-gate macinfo->llcp_stats.llcs_testxmt++; 27827c478bd9Sstevel@tonic-gate putnext(WR(macinfo->llcp_queue), rmp); 27837c478bd9Sstevel@tonic-gate return (LLCE_OK); 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate /* 27877c478bd9Sstevel@tonic-gate * llc1_find_waiting(macinfo, mp, prim) look for a stream waiting for a 27887c478bd9Sstevel@tonic-gate * response to a message identified by prim and send it to the user. 27897c478bd9Sstevel@tonic-gate */ 27907c478bd9Sstevel@tonic-gate static void 27917c478bd9Sstevel@tonic-gate llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim) 27927c478bd9Sstevel@tonic-gate { 27937c478bd9Sstevel@tonic-gate llc1_t *llc; 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate for (llc = llc1_device_list.llc1_str_next; 27967c478bd9Sstevel@tonic-gate llc != (llc1_t *)&llc1_device_list.llc1_str_next; 27977c478bd9Sstevel@tonic-gate llc = llc->llc_next) 27987c478bd9Sstevel@tonic-gate if (llc->llc_mac_info == macinfo && 27997c478bd9Sstevel@tonic-gate prim == llc->llc_waiting_for) { 28007c478bd9Sstevel@tonic-gate putnext(RD(llc->llc_qptr), mp); 28017c478bd9Sstevel@tonic-gate llc->llc_waiting_for = -1; 28027c478bd9Sstevel@tonic-gate return; 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate freemsg(mp); 28057c478bd9Sstevel@tonic-gate } 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate static void 28087c478bd9Sstevel@tonic-gate llc1insque(void *elem, void *pred) 28097c478bd9Sstevel@tonic-gate { 28107c478bd9Sstevel@tonic-gate struct qelem *pelem = elem; 28117c478bd9Sstevel@tonic-gate struct qelem *ppred = pred; 28127c478bd9Sstevel@tonic-gate struct qelem *pnext = ppred->q_forw; 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate pelem->q_forw = pnext; 28157c478bd9Sstevel@tonic-gate pelem->q_back = ppred; 28167c478bd9Sstevel@tonic-gate ppred->q_forw = pelem; 28177c478bd9Sstevel@tonic-gate pnext->q_back = pelem; 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate static void 28217c478bd9Sstevel@tonic-gate llc1remque(void *arg) 28227c478bd9Sstevel@tonic-gate { 28237c478bd9Sstevel@tonic-gate struct qelem *pelem = arg; 28247c478bd9Sstevel@tonic-gate struct qelem *elem = arg; 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate ASSERT(pelem->q_forw != NULL); 28277c478bd9Sstevel@tonic-gate pelem->q_forw->q_back = pelem->q_back; 28287c478bd9Sstevel@tonic-gate pelem->q_back->q_forw = pelem->q_forw; 28297c478bd9Sstevel@tonic-gate elem->q_back = elem->q_forw = NULL; 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate /* VARARGS */ 28337c478bd9Sstevel@tonic-gate static void 28347c478bd9Sstevel@tonic-gate llc1error(dip, fmt, a1, a2, a3, a4, a5, a6) 28357c478bd9Sstevel@tonic-gate dev_info_t *dip; 28367c478bd9Sstevel@tonic-gate char *fmt, *a1, *a2, *a3, *a4, *a5, *a6; 28377c478bd9Sstevel@tonic-gate { 28387c478bd9Sstevel@tonic-gate static long last; 28397c478bd9Sstevel@tonic-gate static char *lastfmt; 28407c478bd9Sstevel@tonic-gate time_t now; 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * Don't print same error message too often. 28447c478bd9Sstevel@tonic-gate */ 28457c478bd9Sstevel@tonic-gate now = gethrestime_sec(); 28467c478bd9Sstevel@tonic-gate if ((last == (now & ~1)) && (lastfmt == fmt)) 28477c478bd9Sstevel@tonic-gate return; 28487c478bd9Sstevel@tonic-gate last = now & ~1; 28497c478bd9Sstevel@tonic-gate lastfmt = fmt; 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: ", 28527c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip)); 28537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5, a6); 28547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\n"); 28557c478bd9Sstevel@tonic-gate } 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 28587c478bd9Sstevel@tonic-gate static int 28597c478bd9Sstevel@tonic-gate llc1_update_kstat(kstat_t *ksp, int rw) 28607c478bd9Sstevel@tonic-gate { 28617c478bd9Sstevel@tonic-gate llc_mac_info_t *macinfo; 28627c478bd9Sstevel@tonic-gate kstat_named_t *kstat; 28637c478bd9Sstevel@tonic-gate struct llc_stats *stats; 28647c478bd9Sstevel@tonic-gate 28657c478bd9Sstevel@tonic-gate if (ksp == NULL) 28667c478bd9Sstevel@tonic-gate return (0); 28677c478bd9Sstevel@tonic-gate 28687c478bd9Sstevel@tonic-gate kstat = (kstat_named_t *)(ksp->ks_data); 28697c478bd9Sstevel@tonic-gate macinfo = (llc_mac_info_t *)(ksp->ks_private); 28707c478bd9Sstevel@tonic-gate stats = &macinfo->llcp_stats; 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate kstat[LLCS_NOBUFFER].value.ul = stats->llcs_nobuffer; 28737c478bd9Sstevel@tonic-gate kstat[LLCS_MULTIXMT].value.ul = stats->llcs_multixmt; 28747c478bd9Sstevel@tonic-gate kstat[LLCS_MULTIRCV].value.ul = stats->llcs_multircv; 28757c478bd9Sstevel@tonic-gate kstat[LLCS_BRDCSTXMT].value.ul = stats->llcs_brdcstxmt; 28767c478bd9Sstevel@tonic-gate kstat[LLCS_BRDCSTRCV].value.ul = stats->llcs_brdcstrcv; 28777c478bd9Sstevel@tonic-gate kstat[LLCS_BLOCKED].value.ul = stats->llcs_blocked; 28787c478bd9Sstevel@tonic-gate kstat[LLCS_PKTXMT].value.ul = stats->llcs_pktxmt; 28797c478bd9Sstevel@tonic-gate kstat[LLCS_PKTRCV].value.ul = stats->llcs_pktrcv; 28807c478bd9Sstevel@tonic-gate kstat[LLCS_BYTEXMT].value.ul = stats->llcs_bytexmt; 28817c478bd9Sstevel@tonic-gate kstat[LLCS_BYTERCV].value.ul = stats->llcs_bytercv; 28827c478bd9Sstevel@tonic-gate kstat[LLCS_XIDXMT].value.ul = stats->llcs_xidxmt; 28837c478bd9Sstevel@tonic-gate kstat[LLCS_XIDRCV].value.ul = stats->llcs_xidrcv; 28847c478bd9Sstevel@tonic-gate kstat[LLCS_TESTXMT].value.ul = stats->llcs_testxmt; 28857c478bd9Sstevel@tonic-gate kstat[LLCS_TESTRCV].value.ul = stats->llcs_testrcv; 28867c478bd9Sstevel@tonic-gate kstat[LLCS_IERRORS].value.ul = stats->llcs_ierrors; 28877c478bd9Sstevel@tonic-gate kstat[LLCS_OERRORS].value.ul = stats->llcs_oerrors; 28887c478bd9Sstevel@tonic-gate return (0); 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate static void 28927c478bd9Sstevel@tonic-gate llc1_init_kstat(llc_mac_info_t *macinfo) 28937c478bd9Sstevel@tonic-gate { 28947c478bd9Sstevel@tonic-gate kstat_named_t *ksp; 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * Note that the temporary macinfo->llcp_ppa number is negative. 28987c478bd9Sstevel@tonic-gate */ 28997c478bd9Sstevel@tonic-gate macinfo->llcp_kstatp = kstat_create("llc", (-macinfo->llcp_ppa - 1), 29007c478bd9Sstevel@tonic-gate NULL, "net", KSTAT_TYPE_NAMED, 29017c478bd9Sstevel@tonic-gate sizeof (struct llc_stats) / sizeof (long), 0); 29027c478bd9Sstevel@tonic-gate if (macinfo->llcp_kstatp == NULL) 29037c478bd9Sstevel@tonic-gate return; 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate macinfo->llcp_kstatp->ks_update = llc1_update_kstat; 29067c478bd9Sstevel@tonic-gate macinfo->llcp_kstatp->ks_private = (void *)macinfo; 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate ksp = (kstat_named_t *)(macinfo->llcp_kstatp->ks_data); 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_NOBUFFER], "nobuffer", KSTAT_DATA_ULONG); 29117c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_MULTIXMT], "multixmt", KSTAT_DATA_ULONG); 29127c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_MULTIRCV], "multircv", KSTAT_DATA_ULONG); 29137c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BRDCSTXMT], "brdcstxmt", KSTAT_DATA_ULONG); 29147c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BRDCSTRCV], "brdcstrcv", KSTAT_DATA_ULONG); 29157c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BLOCKED], "blocked", KSTAT_DATA_ULONG); 29167c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_PKTXMT], "pktxmt", KSTAT_DATA_ULONG); 29177c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_PKTRCV], "pktrcv", KSTAT_DATA_ULONG); 29187c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BYTEXMT], "bytexmt", KSTAT_DATA_ULONG); 29197c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_BYTERCV], "bytercv", KSTAT_DATA_ULONG); 29207c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_XIDXMT], "xidxmt", KSTAT_DATA_ULONG); 29217c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_XIDRCV], "xidrcv", KSTAT_DATA_ULONG); 29227c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_TESTXMT], "testxmt", KSTAT_DATA_ULONG); 29237c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_TESTRCV], "testrcv", KSTAT_DATA_ULONG); 29247c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_IERRORS], "ierrors", KSTAT_DATA_ULONG); 29257c478bd9Sstevel@tonic-gate kstat_named_init(&ksp[LLCS_OERRORS], "oerrors", KSTAT_DATA_ULONG); 29267c478bd9Sstevel@tonic-gate kstat_install(macinfo->llcp_kstatp); 29277c478bd9Sstevel@tonic-gate } 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate static void 29307c478bd9Sstevel@tonic-gate llc1_uninit_kstat(llc_mac_info_t *macinfo) 29317c478bd9Sstevel@tonic-gate { 29327c478bd9Sstevel@tonic-gate if (macinfo->llcp_kstatp) { 29337c478bd9Sstevel@tonic-gate kstat_delete(macinfo->llcp_kstatp); 29347c478bd9Sstevel@tonic-gate macinfo->llcp_kstatp = NULL; 29357c478bd9Sstevel@tonic-gate } 29367c478bd9Sstevel@tonic-gate } 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate /* 29397c478bd9Sstevel@tonic-gate * llc1_subs_bind(q, mp) 29407c478bd9Sstevel@tonic-gate * implements the DL_SUBS_BIND_REQ primitive 29417c478bd9Sstevel@tonic-gate * this only works for a STREAM bound to LLC_SNAP_SAP 29427c478bd9Sstevel@tonic-gate * or one bound to the automatic SNAP mode. 29437c478bd9Sstevel@tonic-gate * If bound to LLC_SNAP_SAP, the subs bind can be: 29447c478bd9Sstevel@tonic-gate * - 2 octets treated as a native byte order short (ethertype) 29457c478bd9Sstevel@tonic-gate * - 3 octets treated as a network order byte string (OID part) 29467c478bd9Sstevel@tonic-gate * - 5 octets treated as a network order byte string (full SNAP header) 29477c478bd9Sstevel@tonic-gate * If bound to an automatic SNAP mode sap, then only the 3 octet 29487c478bd9Sstevel@tonic-gate * form is allowed 29497c478bd9Sstevel@tonic-gate */ 29507c478bd9Sstevel@tonic-gate static int 29517c478bd9Sstevel@tonic-gate llc1_subs_bind(queue_t *q, mblk_t *mp) 29527c478bd9Sstevel@tonic-gate { 29537c478bd9Sstevel@tonic-gate llc1_t *lld = (llc1_t *)q->q_ptr; 29547c478bd9Sstevel@tonic-gate dl_subs_bind_req_t *subs = (dl_subs_bind_req_t *)mp->b_rptr; 29557c478bd9Sstevel@tonic-gate ushort_t subssap; 29567c478bd9Sstevel@tonic-gate uchar_t *sapstr; 29577c478bd9Sstevel@tonic-gate int result; 29587c478bd9Sstevel@tonic-gate 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate #if defined(LLC1_DEBUG) 29617c478bd9Sstevel@tonic-gate if (llc1_debug & (LLCTRACE|LLCPROT)) { 29627c478bd9Sstevel@tonic-gate printf("llc1_subs_bind (%x, %x)\n", q, mp); 29637c478bd9Sstevel@tonic-gate } 29647c478bd9Sstevel@tonic-gate #endif 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate if (lld == NULL || lld->llc_state != DL_IDLE) { 29677c478bd9Sstevel@tonic-gate result = DL_OUTSTATE; 29687c478bd9Sstevel@tonic-gate } else if (lld->llc_sap != LLC_SNAP_SAP || 29697c478bd9Sstevel@tonic-gate subs->dl_subs_bind_class != DL_HIERARCHICAL_BIND) { 29707c478bd9Sstevel@tonic-gate /* we only want to support this for SNAP at present */ 29717c478bd9Sstevel@tonic-gate result = DL_UNSUPPORTED; 29727c478bd9Sstevel@tonic-gate } else { 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate lld->llc_state = DL_SUBS_BIND_PND; 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate sapstr = (uchar_t *)(mp->b_rptr + subs->dl_subs_sap_offset); 29777c478bd9Sstevel@tonic-gate 29787c478bd9Sstevel@tonic-gate result = LLCE_OK; 29797c478bd9Sstevel@tonic-gate switch (subs->dl_subs_sap_length) { 29807c478bd9Sstevel@tonic-gate case 2: /* just the ethertype part */ 29817c478bd9Sstevel@tonic-gate if (lld->llc_flags & LLC_SNAP) { 29827c478bd9Sstevel@tonic-gate result = DL_BADADDR; 29837c478bd9Sstevel@tonic-gate break; 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate ((uchar_t *)&subssap)[0] = sapstr[0]; 29867c478bd9Sstevel@tonic-gate ((uchar_t *)&subssap)[1] = sapstr[1]; 29877c478bd9Sstevel@tonic-gate subssap = htons(subssap); 29887c478bd9Sstevel@tonic-gate lld->llc_snap[3] = ((uchar_t *)&subssap)[0]; 29897c478bd9Sstevel@tonic-gate lld->llc_snap[4] = ((uchar_t *)&subssap)[1]; 29907c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP; 29917c478bd9Sstevel@tonic-gate break; 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate case 3: /* just the OID part */ 29947c478bd9Sstevel@tonic-gate if ((lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) == 29957c478bd9Sstevel@tonic-gate (LLC_SNAP|LLC_SNAP_OID)) { 29967c478bd9Sstevel@tonic-gate result = DL_BADADDR; 29977c478bd9Sstevel@tonic-gate break; 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate bcopy(sapstr, lld->llc_snap, 3); 30007c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP_OID; 30017c478bd9Sstevel@tonic-gate break; 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate case 5: /* full SNAP header */ 30047c478bd9Sstevel@tonic-gate if (lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) { 30057c478bd9Sstevel@tonic-gate result = DL_BADADDR; 30067c478bd9Sstevel@tonic-gate break; 30077c478bd9Sstevel@tonic-gate } 30087c478bd9Sstevel@tonic-gate bcopy(sapstr, lld->llc_snap, 5); 30097c478bd9Sstevel@tonic-gate lld->llc_flags |= LLC_SNAP|LLC_SNAP_OID; 30107c478bd9Sstevel@tonic-gate break; 30117c478bd9Sstevel@tonic-gate } 30127c478bd9Sstevel@tonic-gate /* if successful, acknowledge and enter the proper state */ 30137c478bd9Sstevel@tonic-gate if (result == LLCE_OK) { 30147c478bd9Sstevel@tonic-gate mblk_t *nmp = mp; 30157c478bd9Sstevel@tonic-gate dl_subs_bind_ack_t *ack; 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate if (DB_REF(mp) != 1 || 30187c478bd9Sstevel@tonic-gate MBLKL(mp) < (sizeof (dl_subs_bind_ack_t) + 5)) { 30197c478bd9Sstevel@tonic-gate freemsg(mp); 30207c478bd9Sstevel@tonic-gate nmp = allocb(sizeof (dl_subs_bind_ack_t) + 5, 30217c478bd9Sstevel@tonic-gate BPRI_MED); 30227c478bd9Sstevel@tonic-gate } 30237c478bd9Sstevel@tonic-gate ack = (dl_subs_bind_ack_t *)nmp->b_rptr; 30247c478bd9Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + 30257c478bd9Sstevel@tonic-gate sizeof (dl_subs_bind_ack_t) + 5; 30267c478bd9Sstevel@tonic-gate ack->dl_primitive = DL_SUBS_BIND_ACK; 30277c478bd9Sstevel@tonic-gate ack->dl_subs_sap_offset = sizeof (dl_subs_bind_ack_t); 30287c478bd9Sstevel@tonic-gate ack->dl_subs_sap_length = 5; 30297c478bd9Sstevel@tonic-gate bcopy(lld->llc_snap, 30307c478bd9Sstevel@tonic-gate (caddr_t)nmp->b_rptr + ack->dl_subs_sap_offset + 5, 30317c478bd9Sstevel@tonic-gate 5); 30327c478bd9Sstevel@tonic-gate DB_TYPE(nmp) = M_PCPROTO; 30337c478bd9Sstevel@tonic-gate qreply(q, nmp); 30347c478bd9Sstevel@tonic-gate 30357c478bd9Sstevel@tonic-gate } 30367c478bd9Sstevel@tonic-gate lld->llc_state = DL_IDLE; 30377c478bd9Sstevel@tonic-gate } 30387c478bd9Sstevel@tonic-gate return (result); 30397c478bd9Sstevel@tonic-gate } 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate /* 30427c478bd9Sstevel@tonic-gate * 30437c478bd9Sstevel@tonic-gate */ 30447c478bd9Sstevel@tonic-gate static int 30457c478bd9Sstevel@tonic-gate llc1_subs_unbind(void) 30467c478bd9Sstevel@tonic-gate { 30477c478bd9Sstevel@tonic-gate return (DL_UNSUPPORTED); 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate char * 30517c478bd9Sstevel@tonic-gate snapdmp(uchar_t *bstr) 30527c478bd9Sstevel@tonic-gate { 30537c478bd9Sstevel@tonic-gate static char buff[32]; 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%x.%x.%x.%x.%x", 30567c478bd9Sstevel@tonic-gate bstr[0], 30577c478bd9Sstevel@tonic-gate bstr[1], 30587c478bd9Sstevel@tonic-gate bstr[2], 30597c478bd9Sstevel@tonic-gate bstr[3], 30607c478bd9Sstevel@tonic-gate bstr[4]); 30617c478bd9Sstevel@tonic-gate return (buff); 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate static int 30657c478bd9Sstevel@tonic-gate llc1_snap_match(llc1_t *lld, struct snaphdr *snap) 30667c478bd9Sstevel@tonic-gate { 30677c478bd9Sstevel@tonic-gate return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0); 30687c478bd9Sstevel@tonic-gate } 3069