diff --git a/sys/netlink/netlink_sysevent.h b/sys/netlink/netlink_sysevent.h --- a/sys/netlink/netlink_sysevent.h +++ b/sys/netlink/netlink_sysevent.h @@ -37,4 +37,13 @@ __NLSE_ATTR_MAX, }; #define NLSE_ATTR_MAX (__NLSE_ATTR_MAX -1) + +/* commands */ +enum { + NLSE_CMD_UNSPEC = 0, + NLSE_CMD_NEWEVENT = 1, + __NLSE_CMD_MAX, +}; +#define NLSE_CMD_MAX (__NLSE_CMD_MAX - 1) + #endif diff --git a/sys/netlink/netlink_sysevent.c b/sys/netlink/netlink_sysevent.c --- a/sys/netlink/netlink_sysevent.c +++ b/sys/netlink/netlink_sysevent.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -47,12 +48,69 @@ #define NLSE_FAMILY_NAME "nlsysevent" static uint32_t ctrl_family_id; +static int nlse_new_event(struct nlmsghdr *hdr, struct nl_pstate *npt); +void sysevent_send(const char *system, const char *subsystem, const char *type, + const char *data); + #define MAX_SYSEVENT_GROUPS 64 static struct sysevent_group { char *name; uint32_t id; } sysevent_groups[MAX_SYSEVENT_GROUPS] = {}; +static const struct genl_cmd nlse_cmds[] = { + { + .cmd_num = NLSE_CMD_NEWEVENT, + .cmd_name = "NEWEVENT", + .cmd_cb = nlse_new_event, + .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_EVENTS, + } +}; + +struct nl_sysevent { + char *system; + char *subsystem; + char *type; + char *data; +}; + +#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _OUT(_field) offsetof(struct nl_sysevent, _field) +static const struct nlattr_parser nla_p_set[] = { + { .type = NLSE_ATTR_SYSTEM, .off = _OUT(system), .cb = nlattr_get_string }, + { .type = NLSE_ATTR_SUBSYSTEM, .off = _OUT(subsystem), .cb = nlattr_get_string }, + { .type = NLSE_ATTR_TYPE, .off = _OUT(type), .cb = nlattr_get_string }, + { .type = NLSE_ATTR_DATA, .off = _OUT(data), .cb = nlattr_get_string }, +}; +static const struct nlfield_parser nlf_p_set[] = { +}; +NL_DECLARE_PARSER(event_parser, struct genlmsghdr, nlf_p_set, nla_p_set); +#undef _IN +#undef _OUT + +int +nlse_new_event(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct nl_sysevent se = {}; + int error; + + error = nl_parse_nlmsg(hdr, &event_parser, npt, &se); + if (error != 0) + return (error); + if (se.system == NULL) + return (EINVAL); + if (se.subsystem == NULL) + return (EINVAL); + if (se.type == NULL) + return (EINVAL); + if (se.data == NULL) + return (EINVAL); + + sysevent_send(se.system, se.subsystem, se.type, se.data); + return (0); +} + static void sysevent_write(struct sysevent_group *se, const char *subsystem, const char *type, const char *data) @@ -112,7 +170,7 @@ return (NULL); } -static void +void sysevent_send(const char *system, const char *subsystem, const char *type, const char *data) { @@ -134,6 +192,8 @@ { devctl_set_notify_hook(sysevent_send); ctrl_family_id = genl_register_family(NLSE_FAMILY_NAME, 0, 2, NLSE_ATTR_MAX); + genl_register_cmds(NLSE_FAMILY_NAME, nlse_cmds, NL_ARRAY_LEN(nlse_cmds)); + for (size_t i = 0; i < nitems(devctl_systems); i++) { if (i >= MAX_SYSEVENT_GROUPS) { NL_LOG(LOG_WARNING, "impossible to add the event %s, too many events\n", devctl_systems[i]); diff --git a/sys/sys/priv.h b/sys/sys/priv.h --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -83,6 +83,7 @@ #define PRIV_SETTIMEOFDAY 18 /* Can call settimeofday. */ #define _PRIV_SETHOSTID 19 /* Removed. */ #define _PRIV_SETDOMAINNAME 20 /* Removed. */ +#define PRIV_EVENTS 21 /* Can to send events to the kernel */ /* * Audit subsystem privileges.