10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Sysevent Driver for GPEC 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/param.h> 330Sstevel@tonic-gate #include <sys/cred.h> 340Sstevel@tonic-gate #include <sys/file.h> 350Sstevel@tonic-gate #include <sys/stat.h> 360Sstevel@tonic-gate #include <sys/conf.h> 370Sstevel@tonic-gate #include <sys/ddi.h> 380Sstevel@tonic-gate #include <sys/sunddi.h> 390Sstevel@tonic-gate #include <sys/modctl.h> 400Sstevel@tonic-gate #include <sys/open.h> /* OTYP_CHR definition */ 410Sstevel@tonic-gate #include <sys/sysmacros.h> /* L_BITSMINOR definition */ 420Sstevel@tonic-gate #include <sys/bitmap.h> 430Sstevel@tonic-gate #include <sys/sysevent.h> 440Sstevel@tonic-gate #include <sys/sysevent_impl.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate static dev_info_t *sysevent_devi; 470Sstevel@tonic-gate 480Sstevel@tonic-gate /* Definitions for binding handle array */ 490Sstevel@tonic-gate static ulong_t sysevent_bitmap_initial = 1; /* index 0 indicates error */ 500Sstevel@tonic-gate static ulong_t *sysevent_minor_bitmap = &sysevent_bitmap_initial; 510Sstevel@tonic-gate static size_t sysevent_minor_bits = BT_NBIPUL; 520Sstevel@tonic-gate static kmutex_t sysevent_minor_mutex; 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * evchan_ctl acts as a container for the binding handle 560Sstevel@tonic-gate */ 570Sstevel@tonic-gate typedef struct evchan_ctl { 580Sstevel@tonic-gate evchan_t *chp; 590Sstevel@tonic-gate } evchan_ctl_t; 600Sstevel@tonic-gate 610Sstevel@tonic-gate static void *evchan_ctlp; 620Sstevel@tonic-gate 630Sstevel@tonic-gate /* 640Sstevel@tonic-gate * Check if it's a null terminated array - to avoid DoS attack 650Sstevel@tonic-gate * It is supposed that string points to an array with 660Sstevel@tonic-gate * a minimum length of len. len must be strlen + 1. 670Sstevel@tonic-gate * Checks for printable characters are already done in library. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate static int 700Sstevel@tonic-gate sysevent_isstrend(char *string, size_t len) 710Sstevel@tonic-gate { 720Sstevel@tonic-gate /* Return 0 if string has length of zero */ 730Sstevel@tonic-gate if (len > 0) { 740Sstevel@tonic-gate return (string[len - 1] == '\0' ? 1 : 0); 750Sstevel@tonic-gate } else { 760Sstevel@tonic-gate return (0); 770Sstevel@tonic-gate } 780Sstevel@tonic-gate } 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Following sysevent_minor_* routines map 820Sstevel@tonic-gate * a binding handle (evchan_t *) to a minor number 830Sstevel@tonic-gate * Has to be called w/ locks held. 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate static ulong_t * 860Sstevel@tonic-gate sysevent_minor_alloc(void) 870Sstevel@tonic-gate { 880Sstevel@tonic-gate ulong_t *bhst = sysevent_minor_bitmap; 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* Increase bitmap by one BT_NBIPUL */ 910Sstevel@tonic-gate if (sysevent_minor_bits + BT_NBIPUL > SYSEVENT_MINOR_MAX) { 920Sstevel@tonic-gate return ((ulong_t *)NULL); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate sysevent_minor_bitmap = kmem_zalloc( 950Sstevel@tonic-gate BT_SIZEOFMAP(sysevent_minor_bits + BT_NBIPUL), KM_SLEEP); 960Sstevel@tonic-gate bcopy(bhst, sysevent_minor_bitmap, BT_SIZEOFMAP(sysevent_minor_bits)); 970Sstevel@tonic-gate if (bhst != &sysevent_bitmap_initial) 980Sstevel@tonic-gate kmem_free(bhst, BT_SIZEOFMAP(sysevent_minor_bits)); 990Sstevel@tonic-gate sysevent_minor_bits += BT_NBIPUL; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate return (sysevent_minor_bitmap); 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate static void 1050Sstevel@tonic-gate sysevent_minor_free(ulong_t *bitmap) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate if (bitmap != &sysevent_bitmap_initial) 1080Sstevel@tonic-gate kmem_free(bitmap, BT_SIZEOFMAP(sysevent_minor_bits)); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate static index_t 1120Sstevel@tonic-gate sysevent_minor_get(void) 1130Sstevel@tonic-gate { 1140Sstevel@tonic-gate index_t idx; 1150Sstevel@tonic-gate ulong_t *bhst; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* Search for an available index */ 1180Sstevel@tonic-gate mutex_enter(&sysevent_minor_mutex); 1190Sstevel@tonic-gate if ((idx = bt_availbit(sysevent_minor_bitmap, 1200Sstevel@tonic-gate sysevent_minor_bits)) == -1) { 1210Sstevel@tonic-gate /* All busy - allocate additional binding handle bitmap space */ 1220Sstevel@tonic-gate if ((bhst = sysevent_minor_alloc()) == NULL) { 1230Sstevel@tonic-gate /* Reached our maximum of id's == SHRT_MAX */ 1240Sstevel@tonic-gate mutex_exit(&sysevent_minor_mutex); 1250Sstevel@tonic-gate return (0); 1260Sstevel@tonic-gate } else { 1270Sstevel@tonic-gate sysevent_minor_bitmap = bhst; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate idx = bt_availbit(sysevent_minor_bitmap, sysevent_minor_bits); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate BT_SET(sysevent_minor_bitmap, idx); 1320Sstevel@tonic-gate mutex_exit(&sysevent_minor_mutex); 1330Sstevel@tonic-gate return (idx); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate static void 1370Sstevel@tonic-gate sysevent_minor_rele(index_t idx) 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate mutex_enter(&sysevent_minor_mutex); 1400Sstevel@tonic-gate ASSERT(BT_TEST(sysevent_minor_bitmap, idx) == 1); 1410Sstevel@tonic-gate BT_CLEAR(sysevent_minor_bitmap, idx); 1420Sstevel@tonic-gate mutex_exit(&sysevent_minor_mutex); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate static void 1460Sstevel@tonic-gate sysevent_minor_init(void) 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate mutex_init(&sysevent_minor_mutex, NULL, MUTEX_DEFAULT, NULL); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* ARGSUSED */ 1520Sstevel@tonic-gate static int 1530Sstevel@tonic-gate sysevent_publish(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate int km_flags; 1560Sstevel@tonic-gate sev_publish_args_t uargs; 1570Sstevel@tonic-gate sysevent_impl_t *ev; 1580Sstevel@tonic-gate evchan_ctl_t *ctl; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); 1610Sstevel@tonic-gate if (ctl == NULL || ctl->chp == NULL) 1620Sstevel@tonic-gate return (ENXIO); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_publish_args_t)) != 0) 1650Sstevel@tonic-gate return (EFAULT); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * This limits the size of an event 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate if (uargs.ev.len > MAX_EV_SIZE_LEN) 1710Sstevel@tonic-gate return (EOVERFLOW); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * Check for valid uargs.flags 1750Sstevel@tonic-gate */ 1760Sstevel@tonic-gate if (uargs.flags & ~(EVCH_NOSLEEP | EVCH_SLEEP | EVCH_QWAIT)) 1770Sstevel@tonic-gate return (EINVAL); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * Check that at least one of EVCH_NOSLEEP or EVCH_SLEEP is 1810Sstevel@tonic-gate * specified 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate km_flags = uargs.flags & (EVCH_NOSLEEP | EVCH_SLEEP); 1840Sstevel@tonic-gate if (km_flags != EVCH_NOSLEEP && km_flags != EVCH_SLEEP) 1850Sstevel@tonic-gate return (EINVAL); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate ev = evch_usrallocev(uargs.ev.len, uargs.flags); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.ev.name, ev, uargs.ev.len) != 0) { 1900Sstevel@tonic-gate evch_usrfreeev(ev); 1910Sstevel@tonic-gate return (EFAULT); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (evch_usrpostevent(ctl->chp, ev, uargs.flags)); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* Event will be freed internally */ 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * sysevent_chan_open - used to open a channel in the GPEC channel layer 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* ARGSUSED */ 2040Sstevel@tonic-gate static int 2050Sstevel@tonic-gate sysevent_chan_open(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate sev_bind_args_t uargs; 2080Sstevel@tonic-gate evchan_ctl_t *ctl; 2090Sstevel@tonic-gate char *chan_name; 2100Sstevel@tonic-gate int ec; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); 2130Sstevel@tonic-gate if (ctl == NULL) { 2140Sstevel@tonic-gate return (ENXIO); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_bind_args_t)) != 0) 2180Sstevel@tonic-gate return (EFAULT); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate if (uargs.chan_name.len > MAX_CHNAME_LEN) 2210Sstevel@tonic-gate return (EINVAL); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate chan_name = kmem_alloc(uargs.chan_name.len, KM_SLEEP); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.chan_name.name, chan_name, 2260Sstevel@tonic-gate uargs.chan_name.len) != 0) { 2270Sstevel@tonic-gate kmem_free(chan_name, uargs.chan_name.len); 2280Sstevel@tonic-gate return (EFAULT); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (!sysevent_isstrend(chan_name, uargs.chan_name.len)) { 2320Sstevel@tonic-gate kmem_free(chan_name, uargs.chan_name.len); 2330Sstevel@tonic-gate return (EINVAL); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * Check of uargs.flags and uargs.perms just to avoid DoS attacks. 2380Sstevel@tonic-gate * libsysevent does this carefully 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate ctl->chp = evch_usrchanopen((const char *)chan_name, 2410Sstevel@tonic-gate uargs.flags & EVCH_B_FLAGS, &ec); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate kmem_free(chan_name, uargs.chan_name.len); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (ec != 0) { 2460Sstevel@tonic-gate return (ec); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate return (0); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* ARGSUSED */ 2530Sstevel@tonic-gate static int 2540Sstevel@tonic-gate sysevent_chan_control(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate sev_control_args_t uargs; 2570Sstevel@tonic-gate evchan_ctl_t *ctl; 2580Sstevel@tonic-gate int rc; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); 2610Sstevel@tonic-gate if (ctl == NULL || ctl->chp == NULL) 2620Sstevel@tonic-gate return (ENXIO); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_control_args_t)) != 0) 2650Sstevel@tonic-gate return (EFAULT); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate switch (uargs.cmd) { 2680Sstevel@tonic-gate case EVCH_GET_CHAN_LEN: 2690Sstevel@tonic-gate case EVCH_GET_CHAN_LEN_MAX: 2700Sstevel@tonic-gate rc = evch_usrcontrol_get(ctl->chp, uargs.cmd, &uargs.value); 2710Sstevel@tonic-gate if (rc == 0) { 2720Sstevel@tonic-gate if (copyout((void *)&uargs, arg, 2730Sstevel@tonic-gate sizeof (sev_control_args_t)) != 0) { 2740Sstevel@tonic-gate rc = EFAULT; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate break; 2780Sstevel@tonic-gate case EVCH_SET_CHAN_LEN: 2790Sstevel@tonic-gate rc = evch_usrcontrol_set(ctl->chp, uargs.cmd, uargs.value); 2800Sstevel@tonic-gate break; 2810Sstevel@tonic-gate default: 2820Sstevel@tonic-gate rc = EINVAL; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate return (rc); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* ARGSUSED */ 2880Sstevel@tonic-gate static int 2890Sstevel@tonic-gate sysevent_subscribe(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate sev_subscribe_args_t uargs; 2920Sstevel@tonic-gate char *sid; 2930Sstevel@tonic-gate char *class_info = NULL; 2940Sstevel@tonic-gate evchan_ctl_t *ctl; 2950Sstevel@tonic-gate int rc; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); 2980Sstevel@tonic-gate if (ctl == NULL || ctl->chp == NULL) 2990Sstevel@tonic-gate return (ENXIO); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_subscribe_args_t)) != 0) 3020Sstevel@tonic-gate return (EFAULT); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate if (uargs.sid.len > MAX_SUBID_LEN || 3050Sstevel@tonic-gate uargs.class_info.len > MAX_CLASS_LEN) 3060Sstevel@tonic-gate return (EINVAL); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate sid = kmem_alloc(uargs.sid.len, KM_SLEEP); 3090Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.sid.name, 3100Sstevel@tonic-gate sid, uargs.sid.len) != 0) { 3110Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3120Sstevel@tonic-gate return (EFAULT); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate if (!sysevent_isstrend(sid, uargs.sid.len)) { 3150Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3160Sstevel@tonic-gate return (EINVAL); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* If class string empty then class EC_ALL is assumed */ 3200Sstevel@tonic-gate if (uargs.class_info.len != 0) { 3210Sstevel@tonic-gate class_info = kmem_alloc(uargs.class_info.len, KM_SLEEP); 3220Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.class_info.name, class_info, 3230Sstevel@tonic-gate uargs.class_info.len) != 0) { 3240Sstevel@tonic-gate kmem_free(class_info, uargs.class_info.len); 3250Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3260Sstevel@tonic-gate return (EFAULT); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate if (!sysevent_isstrend(class_info, uargs.class_info.len)) { 3290Sstevel@tonic-gate kmem_free(class_info, uargs.class_info.len); 3300Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3310Sstevel@tonic-gate return (EINVAL); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Check of uargs.flags just to avoid DoS attacks 3370Sstevel@tonic-gate * libsysevent does this carefully. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate rc = evch_usrsubscribe(ctl->chp, sid, class_info, 3400Sstevel@tonic-gate (int)uargs.door_desc, uargs.flags); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate kmem_free(class_info, uargs.class_info.len); 3430Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate return (rc); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* ARGSUSED */ 3490Sstevel@tonic-gate static int 3500Sstevel@tonic-gate sysevent_unsubscribe(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 3510Sstevel@tonic-gate { 3520Sstevel@tonic-gate sev_unsubscribe_args_t uargs; 3530Sstevel@tonic-gate char *sid; 3540Sstevel@tonic-gate evchan_ctl_t *ctl; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_unsubscribe_args_t)) != 0) 3570Sstevel@tonic-gate return (EFAULT); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev)); 3600Sstevel@tonic-gate if (ctl == NULL || ctl->chp == NULL) 3610Sstevel@tonic-gate return (ENXIO); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate if (uargs.sid.len > MAX_SUBID_LEN) 3640Sstevel@tonic-gate return (EINVAL); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* Unsubscribe for all */ 3670Sstevel@tonic-gate if (uargs.sid.len == 0) { 3680Sstevel@tonic-gate evch_usrunsubscribe(ctl->chp, NULL, 0); 3690Sstevel@tonic-gate return (0); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate sid = kmem_alloc(uargs.sid.len, KM_SLEEP); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.sid.name, 3750Sstevel@tonic-gate sid, uargs.sid.len) != 0) { 3760Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3770Sstevel@tonic-gate return (EFAULT); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate evch_usrunsubscribe(ctl->chp, sid, 0); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate kmem_free(sid, uargs.sid.len); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate return (0); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* ARGSUSED */ 3880Sstevel@tonic-gate static int 3890Sstevel@tonic-gate sysevent_channames(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate sev_chandata_args_t uargs; 3920Sstevel@tonic-gate char *buf; 3930Sstevel@tonic-gate int len; 3940Sstevel@tonic-gate int rc = 0; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_chandata_args_t)) != 0) 3970Sstevel@tonic-gate return (EFAULT); 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if (uargs.out_data.len == 0 || uargs.out_data.len > EVCH_MAX_DATA_SIZE) 4000Sstevel@tonic-gate return (EINVAL); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate buf = kmem_alloc(uargs.out_data.len, KM_SLEEP); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate if ((len = evch_usrgetchnames(buf, uargs.out_data.len)) == -1) { 4050Sstevel@tonic-gate rc = EOVERFLOW; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if (rc == 0) { 4090Sstevel@tonic-gate ASSERT(len <= uargs.out_data.len); 4100Sstevel@tonic-gate if (copyout(buf, 4110Sstevel@tonic-gate (void *)(uintptr_t)uargs.out_data.name, len) != 0) { 4120Sstevel@tonic-gate rc = EFAULT; 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate kmem_free(buf, uargs.out_data.len); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate return (rc); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* ARGSUSED */ 4220Sstevel@tonic-gate static int 4230Sstevel@tonic-gate sysevent_chandata(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr) 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate sev_chandata_args_t uargs; 4260Sstevel@tonic-gate char *channel; 4270Sstevel@tonic-gate char *buf; 4280Sstevel@tonic-gate int len; 4290Sstevel@tonic-gate int rc = 0; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate if (copyin(arg, &uargs, sizeof (sev_chandata_args_t)) != 0) 4320Sstevel@tonic-gate return (EFAULT); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (uargs.in_data.len > MAX_CHNAME_LEN || 4350Sstevel@tonic-gate uargs.out_data.len > EVCH_MAX_DATA_SIZE) 4360Sstevel@tonic-gate return (EINVAL); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate channel = kmem_alloc(uargs.in_data.len, KM_SLEEP); 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate if (copyin((void *)(uintptr_t)uargs.in_data.name, channel, 4410Sstevel@tonic-gate uargs.in_data.len) != 0) { 4420Sstevel@tonic-gate kmem_free(channel, uargs.in_data.len); 4430Sstevel@tonic-gate return (EFAULT); 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate if (!sysevent_isstrend(channel, uargs.in_data.len)) { 4470Sstevel@tonic-gate kmem_free(channel, uargs.in_data.len); 4480Sstevel@tonic-gate return (EINVAL); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate buf = kmem_alloc(uargs.out_data.len, KM_SLEEP); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate len = evch_usrgetchdata(channel, buf, uargs.out_data.len); 4540Sstevel@tonic-gate if (len == 0) { 4550Sstevel@tonic-gate rc = EOVERFLOW; 4560Sstevel@tonic-gate } else if (len == -1) { 4570Sstevel@tonic-gate rc = ENOENT; 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate if (rc == 0) { 4610Sstevel@tonic-gate ASSERT(len <= uargs.out_data.len); 4620Sstevel@tonic-gate if (copyout(buf, 4630Sstevel@tonic-gate (void *)(uintptr_t)uargs.out_data.name, len) != 0) { 4640Sstevel@tonic-gate rc = EFAULT; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate kmem_free(buf, uargs.out_data.len); 4690Sstevel@tonic-gate kmem_free(channel, uargs.in_data.len); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate return (rc); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /*ARGSUSED*/ 4750Sstevel@tonic-gate static int 4760Sstevel@tonic-gate sysevent_ioctl(dev_t dev, int cmd, intptr_t arg, 4770Sstevel@tonic-gate int flag, cred_t *cr, int *rvalp) 4780Sstevel@tonic-gate { 4790Sstevel@tonic-gate int rc; 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate switch (cmd) { 4820Sstevel@tonic-gate case SEV_PUBLISH: 4830Sstevel@tonic-gate rc = sysevent_publish(dev, rvalp, (void *)arg, flag, cr); 4840Sstevel@tonic-gate break; 4850Sstevel@tonic-gate case SEV_CHAN_OPEN: 4860Sstevel@tonic-gate rc = sysevent_chan_open(dev, rvalp, (void *)arg, flag, cr); 4870Sstevel@tonic-gate break; 4880Sstevel@tonic-gate case SEV_CHAN_CONTROL: 4890Sstevel@tonic-gate rc = sysevent_chan_control(dev, rvalp, (void *)arg, flag, cr); 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate case SEV_SUBSCRIBE: 4920Sstevel@tonic-gate rc = sysevent_subscribe(dev, rvalp, (void *)arg, flag, cr); 4930Sstevel@tonic-gate break; 4940Sstevel@tonic-gate case SEV_UNSUBSCRIBE: 4950Sstevel@tonic-gate rc = sysevent_unsubscribe(dev, rvalp, (void *)arg, flag, cr); 4960Sstevel@tonic-gate break; 4970Sstevel@tonic-gate case SEV_CHANNAMES: 4980Sstevel@tonic-gate rc = sysevent_channames(dev, rvalp, (void *)arg, flag, cr); 4990Sstevel@tonic-gate break; 5000Sstevel@tonic-gate case SEV_CHANDATA: 5010Sstevel@tonic-gate rc = sysevent_chandata(dev, rvalp, (void *)arg, flag, cr); 5020Sstevel@tonic-gate break; 5030Sstevel@tonic-gate default: 5040Sstevel@tonic-gate rc = EINVAL; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate return (rc); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /*ARGSUSED*/ 5110Sstevel@tonic-gate static int 5120Sstevel@tonic-gate sysevent_open(dev_t *devp, int flag, int otyp, cred_t *cr) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate int minor; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate if (otyp != OTYP_CHR) 5170Sstevel@tonic-gate return (EINVAL); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate if (getminor(*devp) != 0) 5200Sstevel@tonic-gate return (ENXIO); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate minor = sysevent_minor_get(); 5230Sstevel@tonic-gate if (minor == 0) 5240Sstevel@tonic-gate /* All minors are busy */ 5250Sstevel@tonic-gate return (EBUSY); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate if (ddi_soft_state_zalloc(evchan_ctlp, minor) 5280Sstevel@tonic-gate != DDI_SUCCESS) { 5290Sstevel@tonic-gate sysevent_minor_rele(minor); 5300Sstevel@tonic-gate return (ENOMEM); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), minor); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate return (0); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /*ARGSUSED*/ 5390Sstevel@tonic-gate static int 5400Sstevel@tonic-gate sysevent_close(dev_t dev, int flag, int otyp, cred_t *cr) 5410Sstevel@tonic-gate { 5420Sstevel@tonic-gate int minor = (int)getminor(dev); 5430Sstevel@tonic-gate evchan_ctl_t *ctl; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (otyp != OTYP_CHR) 5460Sstevel@tonic-gate return (EINVAL); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate ctl = ddi_get_soft_state(evchan_ctlp, minor); 5490Sstevel@tonic-gate if (ctl == NULL) { 5500Sstevel@tonic-gate return (ENXIO); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate if (ctl->chp) { 5540Sstevel@tonic-gate /* Release all non-persistant subscriptions */ 5550Sstevel@tonic-gate evch_usrunsubscribe(ctl->chp, NULL, EVCH_SUB_KEEP); 5560Sstevel@tonic-gate evch_usrchanclose(ctl->chp); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate ddi_soft_state_free(evchan_ctlp, minor); 5600Sstevel@tonic-gate sysevent_minor_rele(minor); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate return (0); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate /* ARGSUSED */ 5660Sstevel@tonic-gate static int 5670Sstevel@tonic-gate sysevent_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 5680Sstevel@tonic-gate void *arg, void **result) 5690Sstevel@tonic-gate { 5700Sstevel@tonic-gate switch (infocmd) { 5710Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 5720Sstevel@tonic-gate *result = sysevent_devi; 5730Sstevel@tonic-gate return (DDI_SUCCESS); 5740Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 5750Sstevel@tonic-gate *result = 0; 5760Sstevel@tonic-gate return (DDI_SUCCESS); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate return (DDI_FAILURE); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* ARGSUSED */ 5820Sstevel@tonic-gate static int 5830Sstevel@tonic-gate sysevent_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 5840Sstevel@tonic-gate { 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (cmd != DDI_ATTACH) { 5870Sstevel@tonic-gate return (DDI_FAILURE); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (ddi_create_minor_node(devi, "sysevent", S_IFCHR, 5910Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 5920Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 5930Sstevel@tonic-gate return (DDI_FAILURE); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate sysevent_devi = devi; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate sysevent_minor_init(); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate return (DDI_SUCCESS); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate static int 6030Sstevel@tonic-gate sysevent_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate if (cmd != DDI_DETACH) { 6060Sstevel@tonic-gate return (DDI_FAILURE); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate sysevent_minor_free(sysevent_minor_bitmap); 6100Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 6110Sstevel@tonic-gate return (DDI_SUCCESS); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate static struct cb_ops sysevent_cb_ops = { 6150Sstevel@tonic-gate sysevent_open, /* open */ 6160Sstevel@tonic-gate sysevent_close, /* close */ 6170Sstevel@tonic-gate nodev, /* strategy */ 6180Sstevel@tonic-gate nodev, /* print */ 6190Sstevel@tonic-gate nodev, /* dump */ 6200Sstevel@tonic-gate nodev, /* read */ 6210Sstevel@tonic-gate nodev, /* write */ 6220Sstevel@tonic-gate sysevent_ioctl, /* ioctl */ 6230Sstevel@tonic-gate nodev, /* devmap */ 6240Sstevel@tonic-gate nodev, /* mmap */ 6250Sstevel@tonic-gate nodev, /* segmap */ 6260Sstevel@tonic-gate nochpoll, /* poll */ 6270Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 6280Sstevel@tonic-gate 0, /* streamtab */ 6290Sstevel@tonic-gate D_NEW|D_MP, /* flag */ 6300Sstevel@tonic-gate NULL, /* aread */ 6310Sstevel@tonic-gate NULL /* awrite */ 6320Sstevel@tonic-gate }; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate static struct dev_ops sysevent_ops = { 6350Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 6360Sstevel@tonic-gate 0, /* refcnt */ 6370Sstevel@tonic-gate sysevent_info, /* info */ 6380Sstevel@tonic-gate nulldev, /* identify */ 6390Sstevel@tonic-gate nulldev, /* probe */ 6400Sstevel@tonic-gate sysevent_attach, /* attach */ 6410Sstevel@tonic-gate sysevent_detach, /* detach */ 6420Sstevel@tonic-gate nodev, /* reset */ 6430Sstevel@tonic-gate &sysevent_cb_ops, /* driver operations */ 6440Sstevel@tonic-gate (struct bus_ops *)0, /* no bus operations */ 645*7656SSherry.Moore@Sun.COM nulldev, /* power */ 646*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 6470Sstevel@tonic-gate }; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate static struct modldrv modldrv = { 650*7656SSherry.Moore@Sun.COM &mod_driverops, "sysevent driver", &sysevent_ops 6510Sstevel@tonic-gate }; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate static struct modlinkage modlinkage = { 6540Sstevel@tonic-gate MODREV_1, &modldrv, NULL 6550Sstevel@tonic-gate }; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate int 6580Sstevel@tonic-gate _init(void) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate int s; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate s = ddi_soft_state_init(&evchan_ctlp, sizeof (evchan_ctl_t), 1); 6630Sstevel@tonic-gate if (s != 0) 6640Sstevel@tonic-gate return (s); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate if ((s = mod_install(&modlinkage)) != 0) 6670Sstevel@tonic-gate ddi_soft_state_fini(&evchan_ctlp); 6680Sstevel@tonic-gate return (s); 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate int 6720Sstevel@tonic-gate _fini(void) 6730Sstevel@tonic-gate { 6740Sstevel@tonic-gate int s; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate if ((s = mod_remove(&modlinkage)) != 0) 6770Sstevel@tonic-gate return (s); 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate ddi_soft_state_fini(&evchan_ctlp); 6800Sstevel@tonic-gate return (s); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate int 6840Sstevel@tonic-gate _info(struct modinfo *modinfop) 6850Sstevel@tonic-gate { 6860Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 6870Sstevel@tonic-gate } 688