root/usr/src/uts/common/sys/sysevent_impl.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _SYS_SYSEVENT_IMPL_H
#define _SYS_SYSEVENT_IMPL_H

#include <sys/nvpair.h>
#include <sys/id_space.h>
#include <sys/door.h>

#ifdef  __cplusplus
extern "C" {
#endif

typedef uint64_t se_data_t;

/*
 * The following data structure assist in loading and extracting event
 * header and attribute data into contiguous memory.  Access to all typed
 * data done so on 64-bit boundaries.  *Do Not* alter any of the structures
 * defined below without thorough thought and testing.
 */

/* Attribute name */
typedef struct se_name {
        int32_t         name_sz;
        int32_t         name_pad;
        se_data_t       name;   /* 64-bit aligned offset */
} se_name_t;

/* Attribute value */
typedef struct se_value {
        int32_t         value_type;     /* data type */
        int32_t         value_sz;
        se_data_t       value;          /* data value - 64-bit aligned offset */
} se_value_t;

/* sysevent internal attribute name-value pair stored in contiguous memory */
typedef struct sysevent_attr_impl {
        int32_t         se_attr_sz;     /* Size of attribute data */
        int32_t         se_attr_pad;    /* pad */
        se_data_t       se_attr_name;   /* name of data attribute */
        se_data_t       se_attr_val;    /* value and type of data */
} sysevent_attr_impl_t;

/* Attribute list states */
#define ATTR_DETACHED   0
#define ATTR_ATTACHED   1

/*
 * The following type definitions describe a sysevent object that is
 * generated by a call to sysevent_alloc and sent to userland.
 */

/*
 * sysevent event header information -
 *      contained in every event generated.  The header and the event
 *      must remain 64-bit aligned.  The header, up to the attribute
 *      offset, can be contained in a single cache line.
 */
typedef struct sysevent_hdr {
        sysevent_id_t   se_id;          /* unique identifier */
        uint32_t        se_version;     /* version of this data structure */
        uint32_t        se_flag;
        uint32_t        se_class;       /* event class id - reserved */
        uint32_t        se_subclass;    /* event subclass id - reserved */
        int32_t         se_payload_sz;  /* size of attr data + strings */
        uint16_t        se_subclass_off; /* offset to subclass string */
        uint16_t        se_pub_off;     /* offset to publisher string */
        uint64_t        se_attr_off;    /* pointer or offset to attr data */
} sysevent_hdr_t;

/* sysevent event buffer - 64-bit aligned offsets */
typedef struct sys_event_impl {
        sysevent_hdr_t  se_header;
        se_data_t       se_class_name;  /* class string in contig memory */
        se_data_t       se_subclass_name; /* subclass string in contig memory */
        se_data_t       se_pub;         /* publisher string in contig mem */
        se_data_t       se_attr_buf;    /* contiguous attribute memory  */
} sysevent_impl_t;

/* Helpful defines */
#define seh_version     se_header.se_version
#define seh_class       se_header.se_class
#define seh_subclass    se_header.se_subclass
#define seh_seq         se_header.se_id.eid_seq
#define seh_time        se_header.se_id.eid_ts
#define seh_subclass_off se_header.se_subclass_off
#define seh_pub_off     se_header.se_pub_off
#define seh_attr_off    se_header.se_attr_off
#define seh_payload_sz  se_header.se_payload_sz
#define seh_flag        se_header.se_flag

/* Event buffer version */
#define SYS_EVENT_VERSION       0

/* Event buffer flags */
#define SE_PACKED_BUF   1

#define SYSEVENT_IMPL(ev)       ((sysevent_impl_t *)(void *)(ev))
#define SE_VERSION(ev)          (SYSEVENT_IMPL(ev)->seh_version)
#define SE_CLASS(ev)            (SYSEVENT_IMPL(ev)->seh_class)
#define SE_SUBCLASS(ev)         (SYSEVENT_IMPL(ev)->seh_subclass)
#define SE_SEQ(ev)              (SYSEVENT_IMPL(ev)->seh_seq)
#define SE_TIME(ev)             (SYSEVENT_IMPL(ev)->seh_time)
#define SE_SUBCLASS_OFF(ev)     (SYSEVENT_IMPL(ev)->seh_subclass_off)
#define SE_PUB_OFF(ev)          (SYSEVENT_IMPL(ev)->seh_pub_off)
#define SE_PAYLOAD_SZ(ev)       (SYSEVENT_IMPL(ev)->seh_payload_sz)
#define SE_FLAG(ev)             (SYSEVENT_IMPL(ev)->seh_flag)
#define SE_SIZE(ev)             (sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev))
#define SE_CLASS_NAME(ev)       ((char *)&(SYSEVENT_IMPL(ev)->se_class_name))
#define SE_SUBCLASS_NAME(ev)    ((char *)((caddr_t)(ev) + SE_SUBCLASS_OFF(ev)))
#define SE_PUB_NAME(ev)         ((char *)((caddr_t)(ev) + SE_PUB_OFF(ev)))

/*
 * Attribute data can be stored in contiguous memory or
 * as a list of attribute data elements.  The storage format is determined
 * by the SE_PACKED_BUF flag in the event buffer flags.
 *
 */

/* 64-bit boundary alignment function */
#define SE_ALIGN(x)     ((((ulong_t)x) + 7ul) & ~7ul)

/* Access to unpacked attribute list */
#define SE_ATTR_PTR(ev)         (SYSEVENT_IMPL(ev)->seh_attr_off)

/* Offset to packed attribute data */
#define SE_ATTR_OFF(ev) SE_PUB_OFF(ev) + SE_ALIGN(strlen(SE_PUB_NAME(ev)) + 1)

/* syseventd door */
#define LOGEVENT_DOOR_UPCALL    "/var/run/sysevent_door"

/*
 * door upcall data structures
 */
typedef struct log_event_upcall_arg {
        int32_t retcode;
        int32_t pad;
        sysevent_impl_t buf;
} log_event_upcall_arg_t;

typedef struct log_eventq {
        struct log_eventq       *next;
        log_event_upcall_arg_t  arg;
} log_eventq_t;

/* Syseventd Channel structures */

#define MAX_CHAN        256     /* Maximum channels per system */
#define MAX_SUBSCRIBERS 100     /* Maximum subscribers per channel */
#define MAX_PUBLISHERS  1       /* Maximum publishers per channel */

/*
 * Channel-based subscription structures
 */

/* Class hashing defines */
#define CLASS_HASH_SZ   63
#define CLASS_HASH(class_name)  ((hash_func(class_name) \
                                % CLASS_HASH_SZ) + 1)
#define CHAN_HASH_SZ    32

typedef struct subclass_lst {
        struct subclass_lst     *sl_next;
        char                    *sl_name;
        uchar_t                 sl_num[MAX_SUBSCRIBERS + 1];
} subclass_lst_t;

typedef struct class_lst {
        struct class_lst        *cl_next;
        char                    *cl_name;
        struct subclass_lst     *cl_subclass_list;
} class_lst_t;

/* User/Kernel Structure to pass event registration modctl data */
typedef struct se_pubsub {
        uint32_t        ps_buflen;
        uint32_t        ps_channel_name_len;
        uint32_t        ps_id;
        uint32_t        ps_op;
        uint32_t        ps_type;
} se_pubsub_t;

/* op defines */
#define SE_REGISTER             0
#define SE_UNREGISTER           1
#define SE_CLEANUP              2
#define SE_OPEN_REGISTRATION    3
#define SE_CLOSE_REGISTRATION   4
#define SE_BIND_REGISTRATION    5
#define SE_UNBIND_REGISTRATION  6
#define SE_GET_REGISTRATION     7

/* type defines */
#define SUBSCRIBER      0
#define PUBLISHER       1

/* nvpair names */
#define CLASS_NAME      "class"

#ifdef  _KERNEL

typedef struct sysevent_channel_descriptor {
        char   *scd_channel_name;       /* Name of channel */
        struct sysevent_channel_descriptor *scd_next;
        int    scd_ref_cnt;             /* Reference count of channel opens */
        id_space_t *scd_subscriber_cache;       /* cache of subscriber ids */
        id_space_t *scd_publisher_cache;        /* cache of publisher ids */
        uchar_t scd_subscriber_ids[MAX_SUBSCRIBERS + 1]; /* used sub ids */
        uchar_t scd_publisher_ids[MAX_PUBLISHERS + 1];  /* used  pub ids */
        class_lst_t *scd_class_list_tbl[CLASS_HASH_SZ + 1];
} sysevent_channel_descriptor_t;

/*
 * log_sysevent private interfaces
 */
extern void log_event_init(void);
extern void log_sysevent_flushq(int, uint_t);
extern int log_sysevent_filename(char *);
extern int log_usr_sysevent(sysevent_t *, int, sysevent_id_t *);
extern int log_sysevent_copyout_data(sysevent_id_t *, size_t, caddr_t);
extern int log_sysevent_free_data(sysevent_id_t *);
extern int log_sysevent_register(char *, char *, se_pubsub_t *);
extern uint64_t log_sysevent_new_id(void);

/*
 * Structures and definitions for general purpose event channels
 */

/* Limits */
#define EVCH_MAX_CHANNELS               1024
#define EVCH_MAX_BINDS_PER_CHANNEL      512
#define EVCH_MAX_SUBSCRIPTIONS          32
#define EVCH_SUBPOOLFACT                8
#define EVCH_DEFAULT_EVENTS             2000
#define EVCH_MAX_TRY_DELIVERY           3

/* Linkage element for evch_dlist_t lists */
typedef struct evch_dlelem {
        struct evch_dlelem      *dl_next;
        struct evch_dlelem      *dl_prev;
} evch_dlelem_t;

/* List head */
typedef struct {
        evch_dlelem_t   dh_head;
        int             dh_count;
} evch_dlist_t;

/* Placeholder for elements in a evch_squeue_t queue */
typedef struct evch_qelem {
        struct evch_qelem       *q_next;
        void                    *q_objref;
        size_t                  q_objsize;
} evch_qelem_t;

/* Queue head data */
typedef struct {
        evch_qelem_t    *sq_head;
        evch_qelem_t    *sq_tail;
        uint32_t        sq_count;
        uint32_t        sq_highwm;
} evch_squeue_t;

/*
 * Defines for event queue routines
 */
#define EVQ_IGNORE      1
#define EVQ_DELIVER     2

#define EVQ_CONT        0
#define EVQ_AGAIN       1
#define EVQ_SLEEP       2

/* Call back routine typedefs */
typedef int (*filter_f)(void *, void *);
typedef int (*deliver_f)(void *, void *);
typedef int (*kerndlv_f)(void *, void *);
typedef void (*destr_f)(void *, void *);
typedef int (*compare_f)(evch_dlelem_t *, char *);

/*
 * Event structure handled by evch_evq_* functions. Sysevent type events are
 * stored as the payload.
 */
typedef struct {
        uint32_t        ge_size;        /* Total size of event structure */
        uint32_t        ge_refcount;    /* No of queues event is linked to */
        destr_f         ge_destruct;    /* Destructor for event structure */
        uint32_t        *ge_dstcookie;  /* Cookie for destructor function */
        uchar_t         ge_payload[1];  /* Placeholder for event data */
} evch_gevent_t;

/*
 * Event queue descriptor
 */
typedef struct {
        evch_squeue_t   eq_eventq;      /* Protected by eq_dtmutex */
        kt_did_t        eq_thrid;       /* Id delivery thread */
        kmutex_t        eq_queuemx;     /* Protect. of this struct and ev q */
        kcondvar_t      eq_thrsleepcv;  /* Delivery thread sleeps on empty q */
        int             eq_dactive;     /* Event delivery is in progress */
        kcondvar_t      eq_dactivecv;   /* Unsubscr. has to wait on this */
        evch_dlist_t    eq_subscr;      /* Chain of all evch_evqsub_t */
        uint32_t        eq_nsleep;      /* Statistic: Publisher set to sleep */
        int             eq_holdmode;    /* Hold event delivery */
        evch_gevent_t   *eq_curevent;   /* Event currently beeing delivered */
        evch_qelem_t    *eq_nextev;     /* For iterating over events in a q */
        kcondvar_t      eq_onholdcv;    /* To signal hold mode of deliv. thr. */
        uchar_t         eq_tabortflag;  /* Request to abort delivery thread */
} evch_eventq_t;

/*
 * Event queue per subscriber structure
 */
typedef struct {
        evch_dlelem_t   su_link;
        filter_f        su_filter;      /* Event filter function pointer */
        void            *su_fcookie;    /* cookie for event filter */
        deliver_f       su_callb;       /* Event delivery callback */
        void            *su_cbcookie;   /* callback cookie */
} evch_evqsub_t;

/* Eveny delivery type */
#define EVCH_DELKERN            1       /* Kernel event delivery */
#define EVCH_DELDOOR            2       /* User event delivery via doors */

/*
 * Per channel subscriber data structure. Chained in a linked list to an
 * event channel and to a binding.
 */
typedef struct chsubd {
        evch_dlelem_t   sd_link;        /* Links all subscribers of this ch. */
        struct chsubd   *sd_subnxt;     /* Links all subscr. for a binding */
        char            *sd_ident;      /* Subscriber identifier */
        evch_eventq_t   *sd_queue;      /* Event queue for this subscriber */
        evch_evqsub_t   *sd_msub;       /* Main event queue subscr. */
        char            *sd_classname;  /* Filter criteria */
        size_t          sd_clnsize;     /* Size of sd_classname buffer */
        evch_evqsub_t   *sd_ssub;       /* Subscriber queue subscr. */
        int             sd_type;        /* Type of event delivery */
        kerndlv_f       sd_callback;    /* Callback for kernel delivery */
        void            *sd_cbcookie;   /* Cookie for kernel delivery */
        door_handle_t   sd_door;        /* Door handle for user delivery */
        int             sd_active;      /* Subscription is in use indicator */
        pid_t           sd_pid;         /* PID of subscribing process */
        uint8_t         sd_persist;     /* Persistent user land subscription */
        uint8_t         sd_dump;        /* Dump with sysevent_evc_walk_* */
} evch_subd_t;

/*
 * General purpose event channel descriptor structure. This is the main
 * structure for event subscribing, publishing, delivery to/from an event
 * channel.
 */
typedef struct {
        evch_dlelem_t   ch_link;        /* Must be first elem. of structure */
        char            *ch_name;       /* Channel name */
        size_t          ch_namelen;     /* Length of channel name buffer */
        kmutex_t        ch_mutex;       /* To protect this structure */
        evch_eventq_t   *ch_queue;      /* Publisher event queue */
        evch_dlist_t    ch_subscr;      /* List of subscr. data (evch_subd_t) */
        uint32_t        ch_bindings;    /* No of bindings to this channel */
        int             ch_maxbinds;    /* Maximum number of binds */
        uid_t           ch_uid;         /* Creators effective user id */
        gid_t           ch_gid;         /* Creators effective group id */
        kmutex_t        ch_pubmx;       /* Mutex for ch_pubcv and ch_nevents */
        kcondvar_t      ch_pubcv;       /* To set publisher to sleep */
        uint32_t        ch_nevents;     /* Current number of events */
        uint32_t        ch_maxev;       /* Maximum number of events */
        int             ch_maxsubscr;   /* Maximum number of subscriptions */
        int             ch_holdpend;    /* Hold pending events mode if != 0 */
        time_t          ch_ctime;       /* Channel creation time */
        nvlist_t        *ch_propnvl;    /* Channel properties nvlist */
        int64_t         ch_propnvlgen;  /* Properties generation number */
} evch_chan_t;

/*
 * Channel binding structure. Allocated per binding to a channel. Protected
 * by locking the channel structure
 */
typedef struct {
        evch_chan_t     *bd_channel;
        evch_subd_t     *bd_sublst;     /* chain of all subscriptions */
} evch_bind_t;

/*
 * Structure to keep a snapshot of all events of a channel
 */
typedef struct {
        evch_eventq_t   *sn_queue;      /* Event queue with snapshot of ev's */
        sysevent_impl_t *sn_nxtev;      /* Pointer to find next event */
} evchanq_t;

/* Project private interfaces */
extern evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err);
extern void evch_usrchanclose(evchan_t *cbp);
extern sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags);
extern void evch_usrfreeev(sysevent_impl_t *ev);
extern int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags);
extern int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
    int d, uint32_t flags);
extern int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value);
extern int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value);
extern void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag);
extern int evch_usrgetchnames(char *buf, size_t size);
extern int evch_usrgetchdata(char *chname, void *buf, size_t size);
extern void evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl);
extern int evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp);

extern void sysevent_evc_init();
extern void sysevent_evc_thrinit();
extern evchanq_t *sysevent_evc_walk_init(evchan_t *, char *);
extern sysevent_t *sysevent_evc_walk_step(evchanq_t *);
extern void sysevent_evc_walk_fini(evchanq_t *);
extern char *sysevent_evc_event_attr(sysevent_t *, size_t *);

#endif /* _KERNEL */

/*
 * Structures and limits to deliver channel data to syseventadm
 */
#define EVCH_MAX_DATA_SIZE      (1024 * 1024)

typedef struct {
        uint32_t        sb_nextoff;     /* Offset to next subscr info struct */
        uint32_t        sb_stroff;      /* Offset to strings */
        uint32_t        sb_clnamoff;    /* Offset of class in sb_strings */
        uint32_t        sb_pid;         /* Subscriber process id */
        uint32_t        sb_nevents;     /* Current no of event in sub q */
        uint32_t        sb_evhwm;       /* High watermark of sub q */
        uint32_t        sb_persist;     /* != 0 if subscription persists */
        uint32_t        sb_status;      /* != 0 if subscription is inactive */
        uint32_t        sb_active;      /* > 0 if subscription is in use */
        uint32_t        sb_dump;        /* != 0 if sub will be dumped */
        char            sb_strings[1];  /* String space for subid and class */
} sev_subinfo_t;

typedef struct {
        uint32_t        cd_version;     /* Version of this structure */
        uint32_t        cd_suboffs;     /* Offset of subscriber info struct */
        uint64_t        cd_ctime;       /* Creation time */
        uint32_t        cd_uid;         /* User id */
        uint32_t        cd_gid;         /* Owner group id */
        uint32_t        cd_perms;       /* Permission bits */
        uint32_t        cd_maxev;       /* Max number of events */
        uint32_t        cd_evhwm;       /* High watermark of main event queue */
        uint32_t        cd_nevents;     /* current no of events in main ev q */
        uint32_t        cd_maxsub;      /* Max number of subscriptions */
        uint32_t        cd_nsub;        /* Current number of subscriptions */
        uint32_t        cd_maxbinds;    /* Max number of binds */
        uint32_t        cd_nbinds;      /* Current number of binds */
        uint32_t        cd_holdpend;    /* != 0 when HOLDPEND mode is set */
        uint32_t        cd_limev;       /* Limit of events per channel */
        sev_subinfo_t   cd_subinfo[1];  /* Per subscriber data */
} sev_chinfo_t;

/*
 * Project private flags for sysevent_evc_subscribe. Bits 0 to 7 are reserved
 * for the consolidation private interface, so we must use bits 8-15 here.
 */
#define EVCH_SUB_DUMP           (0x01 << 8)

/*
 * Permission flags
 */
#define EVCH_PUB                0x0004  /* wants to publish events */
#define EVCH_SUB                0x0008  /* wants to subscribe to channel */

#define EVCH_SUBU               0x0001  /* Subscribing allowed for uid */
#define EVCH_PUBU               0x0002  /* Publishing allowed for uid */
#define EVCH_PSUSR              0x0003  /* EVCH_SUBU + EVCH_PUBU */
#define EVCH_SUBG               0x0004  /* Subscribing allowed for gid */
#define EVCH_PUBG               0x0008  /* Publishing allowed for gid */
#define EVCH_PSGRP              0x000C  /* EVCH_SUBG + EVCH_PUBG */
#define EVCH_SUBO               0x0010  /* Subscribing allowed to all users */
#define EVCH_PUBO               0x0020  /* Publishing allowed to all users */
#define EVCH_PSOTH              0x0030  /* EVCH_SUBO + EVCH_PUBO */
#define EVCH_PSALL              0x003f  /* Mask of all permission bits */

/*
 * Sysevent driver ioctls
 */
#define SEV_BASE                0x53455600
#define SEV_PUBLISH             SEV_BASE | 0x01
#define SEV_CHAN_OPEN           SEV_BASE | 0x02
#define SEV_CHAN_CONTROL        SEV_BASE | 0x03
#define SEV_SUBSCRIBE           SEV_BASE | 0x04
#define SEV_UNSUBSCRIBE         SEV_BASE | 0x05
#define SEV_CHANNAMES           SEV_BASE | 0x06
#define SEV_CHANDATA            SEV_BASE | 0x07
#define SEV_SETPROPNVL          SEV_BASE | 0x08
#define SEV_GETPROPNVL          SEV_BASE | 0x09

#define DEVSYSEVENT     "/dev/sysevent"
#define DEVICESYSEVENT  "/devices/pseudo/sysevent@0:sysevent"

/*
 * Maximum allowed binding handles
 * It's a limit required by bitmap algorithm design (see sys/bitmap.h).
 * Use pack(4) to make sizeof structs be the same on x86 and amd64.
 */
#define SYSEVENT_MINOR_MAX      SHRT_MAX

#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack(4)
#endif

/* copyin/copyout data */
typedef struct box {
        uint64_t name;          /* pointer to something */
        uint32_t len;
} sev_box_t;

typedef struct bind_args {
        sev_box_t chan_name;
        uint32_t flags;
} sev_bind_args_t;

typedef struct control_args {
        uint32_t cmd;
        uint32_t value;
} sev_control_args_t;

typedef struct publish_args {
        sev_box_t ev;
        uint32_t flags;
} sev_publish_args_t;

typedef struct subscribe_args {
        sev_box_t sid;
        sev_box_t class_info;
        int door_desc;
        uint32_t flags;
} sev_subscribe_args_t;

typedef struct unsubscribe_args {
        sev_box_t sid;
} sev_unsubscribe_args_t;

typedef struct chandata {
        sev_box_t in_data;
        sev_box_t out_data;
} sev_chandata_args_t;

typedef struct propnvl_args {
        sev_box_t packednvl;    /* input and output */
        int64_t generation;     /* output on get operation */
} sev_propnvl_args_t;

#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack()
#endif

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_SYSEVENT_IMPL_H */