|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* acpi_ids.c - ACPI Netlink Group and Family IDs
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* Copyright (C) 2008 Ted Felix (www.tedfelix.com)
|
|
Packit Service |
26469c |
* Portions from acpi_genl Copyright (C) Zhang Rui <rui.zhang@intel.com>
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
26469c |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
26469c |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
26469c |
* (at your option) any later version.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
26469c |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
26469c |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
26469c |
* GNU General Public License for more details.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
26469c |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
26469c |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#include <stdio.h>
|
|
Packit Service |
26469c |
/* needed by netlink.h, should be in there */
|
|
Packit Service |
26469c |
#include <arpa/inet.h>
|
|
Packit Service |
26469c |
#include <linux/types.h>
|
|
Packit Service |
26469c |
#include <string.h>
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#include "genetlink.h"
|
|
Packit Service |
26469c |
#include "libnetlink.h"
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#include "acpid.h"
|
|
Packit Service |
26469c |
#include "acpi_ids.h"
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#define GENL_MAX_FAM_GRPS 256
|
|
Packit Service |
26469c |
#define ACPI_EVENT_FAMILY_NAME "acpi_event"
|
|
Packit Service |
26469c |
#define ACPI_EVENT_MCAST_GROUP_NAME "acpi_mc_group"
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
static int initialized = 0;
|
|
Packit Service |
26469c |
static __u16 acpi_event_family_id = 0;
|
|
Packit Service |
26469c |
static __u32 acpi_event_mcast_group_id = 0;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* A CTRL_CMD_GETFAMILY message returns an attribute table that looks
|
|
Packit Service |
26469c |
* like this:
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* CTRL_ATTR_FAMILY_ID Use this to make sure we get the proper msgs
|
|
Packit Service |
26469c |
* CTRL_ATTR_MCAST_GROUPS
|
|
Packit Service |
26469c |
* CTRL_ATTR_MCAST_GRP_NAME
|
|
Packit Service |
26469c |
* CTRL_ATTR_MCAST_GRP_ID Need this for the group mask
|
|
Packit Service |
26469c |
* ...
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
static int
|
|
Packit Service |
26469c |
get_ctrl_grp_id(struct rtattr *arg)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
|
|
Packit Service |
26469c |
char *name;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (arg == NULL)
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* nested within the CTRL_ATTR_MCAST_GROUPS attribute are the */
|
|
Packit Service |
26469c |
/* group name and ID */
|
|
Packit Service |
26469c |
parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if either of the entries needed cannot be found, bail */
|
|
Packit Service |
26469c |
if (!tb[CTRL_ATTR_MCAST_GRP_NAME] || !tb[CTRL_ATTR_MCAST_GRP_ID])
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* get the name of this multicast group we've found */
|
|
Packit Service |
26469c |
name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if it does not match the ACPI event multicast group name, bail */
|
|
Packit Service |
26469c |
if (strcmp(name, ACPI_EVENT_MCAST_GROUP_NAME))
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* At this point, we've found what we were looking for. We now */
|
|
Packit Service |
26469c |
/* have the multicast group ID for ACPI events over generic netlink. */
|
|
Packit Service |
26469c |
acpi_event_mcast_group_id =
|
|
Packit Service |
26469c |
*((__u32 *)RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]));
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* n = the response to a CTRL_CMD_GETFAMILY message */
|
|
Packit Service |
26469c |
static int
|
|
Packit Service |
26469c |
genl_get_mcast_group_id(struct nlmsghdr *n)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* Attribute table. Note the type name "rtattr" which means "route
|
|
Packit Service |
26469c |
* attribute". This is a vestige of one of netlink's main uses:
|
|
Packit Service |
26469c |
* routing.
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
struct rtattr *tb[CTRL_ATTR_MAX + 1];
|
|
Packit Service |
26469c |
/* place for the generic netlink header in the incoming message */
|
|
Packit Service |
26469c |
struct genlmsghdr ghdr;
|
|
Packit Service |
26469c |
/* length of the attribute and payload */
|
|
Packit Service |
26469c |
int len = n->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
|
|
Packit Service |
26469c |
/* Pointer to the attribute portion of the message */
|
|
Packit Service |
26469c |
struct rtattr *attrs;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (len < 0) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: netlink CTRL_CMD_GETFAMILY response, "
|
|
Packit Service |
26469c |
"wrong controller message len: %d\n", progname, len);
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (n->nlmsg_type != GENL_ID_CTRL) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: not a netlink controller message, "
|
|
Packit Service |
26469c |
"nlmsg_len=%d nlmsg_type=0x%x\n",
|
|
Packit Service |
26469c |
progname, n->nlmsg_len, n->nlmsg_type);
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* copy generic netlink header into structure */
|
|
Packit Service |
26469c |
memcpy(&ghdr, NLMSG_DATA(n), GENL_HDRLEN);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (ghdr.cmd != CTRL_CMD_GETFAMILY &&
|
|
Packit Service |
26469c |
ghdr.cmd != CTRL_CMD_DELFAMILY &&
|
|
Packit Service |
26469c |
ghdr.cmd != CTRL_CMD_NEWFAMILY &&
|
|
Packit Service |
26469c |
ghdr.cmd != CTRL_CMD_NEWMCAST_GRP &&
|
|
Packit Service |
26469c |
ghdr.cmd != CTRL_CMD_DELMCAST_GRP) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: unknown netlink controller command %d\n",
|
|
Packit Service |
26469c |
progname, ghdr.cmd);
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* set attrs to point to the attribute */
|
|
Packit Service |
26469c |
attrs = (struct rtattr *)(NLMSG_DATA(n) + GENL_HDRLEN);
|
|
Packit Service |
26469c |
/* Read the table from the message into "tb". This actually just */
|
|
Packit Service |
26469c |
/* places pointers into the message into tb[]. */
|
|
Packit Service |
26469c |
parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if a family ID attribute is present, get it */
|
|
Packit Service |
26469c |
if (tb[CTRL_ATTR_FAMILY_ID])
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
acpi_event_family_id =
|
|
Packit Service |
26469c |
*((__u32 *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]));
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if a "multicast groups" attribute is present... */
|
|
Packit Service |
26469c |
if (tb[CTRL_ATTR_MCAST_GROUPS]) {
|
|
Packit Service |
26469c |
struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
|
|
Packit Service |
26469c |
int i;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* get the group table within this attribute */
|
|
Packit Service |
26469c |
parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
|
|
Packit Service |
26469c |
tb[CTRL_ATTR_MCAST_GROUPS]);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* for each group */
|
|
Packit Service |
26469c |
for (i = 0; i < GENL_MAX_FAM_GRPS; i++)
|
|
Packit Service |
26469c |
/* if this group is valid */
|
|
Packit Service |
26469c |
if (tb2[i])
|
|
Packit Service |
26469c |
/* Parse the ID. If successful, we're done. */
|
|
Packit Service |
26469c |
if (!get_ctrl_grp_id(tb2[i]))
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
static int
|
|
Packit Service |
26469c |
genl_get_ids(char *family_name)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
/* handle to the netlink connection */
|
|
Packit Service |
26469c |
struct rtnl_handle rth;
|
|
Packit Service |
26469c |
/* holds the request we are going to send and the reply */
|
|
Packit Service |
26469c |
struct {
|
|
Packit Service |
26469c |
struct nlmsghdr n;
|
|
Packit Service |
26469c |
char buf[4096]; /* ??? Is this big enough for all cases? */
|
|
Packit Service |
26469c |
} req;
|
|
Packit Service |
26469c |
/* pointer to the nlmsghdr in req */
|
|
Packit Service |
26469c |
struct nlmsghdr *nlh;
|
|
Packit Service |
26469c |
/* place for the generic netlink header before copied into req */
|
|
Packit Service |
26469c |
struct genlmsghdr ghdr;
|
|
Packit Service |
26469c |
/* return value */
|
|
Packit Service |
26469c |
int ret = -1;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* clear out the request */
|
|
Packit Service |
26469c |
memset(&req, 0, sizeof(req));
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* set up nlh to point to the netlink header in req */
|
|
Packit Service |
26469c |
nlh = &req.n;
|
|
Packit Service |
26469c |
/* set up the netlink header */
|
|
Packit Service |
26469c |
nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
|
|
Packit Service |
26469c |
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
|
Packit Service |
26469c |
nlh->nlmsg_type = GENL_ID_CTRL;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* clear out the generic netlink message header */
|
|
Packit Service |
26469c |
memset(&ghdr, 0, sizeof(struct genlmsghdr));
|
|
Packit Service |
26469c |
/* set the command we want to run: "GETFAMILY" */
|
|
Packit Service |
26469c |
ghdr.cmd = CTRL_CMD_GETFAMILY;
|
|
Packit Service |
26469c |
/* copy it into req */
|
|
Packit Service |
26469c |
memcpy(NLMSG_DATA(&req.n), &ghdr, GENL_HDRLEN);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* the message payload is the family name */
|
|
Packit Service |
26469c |
addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
|
|
Packit Service |
26469c |
family_name, strlen(family_name) + 1);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* open a generic netlink connection */
|
|
Packit Service |
26469c |
if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: cannot open generic netlink socket\n",
|
|
Packit Service |
26469c |
progname);
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* Send CTRL_CMD_GETFAMILY message (in nlh) to the generic
|
|
Packit Service |
26469c |
* netlink controller. Reply will be in nlh upon return.
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: error talking to the kernel via netlink\n",
|
|
Packit Service |
26469c |
progname);
|
|
Packit Service |
26469c |
goto ctrl_done;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* process the response */
|
|
Packit Service |
26469c |
if (genl_get_mcast_group_id(nlh) < 0) {
|
|
Packit Service |
26469c |
fprintf(stderr, "%s: failed to get acpi_event netlink "
|
|
Packit Service |
26469c |
"multicast group\n", progname);
|
|
Packit Service |
26469c |
goto ctrl_done;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
ret = 0;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
ctrl_done:
|
|
Packit Service |
26469c |
rtnl_close(&rth);
|
|
Packit Service |
26469c |
return ret;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* initialize the ACPI IDs */
|
|
Packit Service |
26469c |
static void
|
|
Packit Service |
26469c |
acpi_ids_init(void)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
genl_get_ids(ACPI_EVENT_FAMILY_NAME);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
initialized = 1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* returns the netlink family ID for ACPI event messages */
|
|
Packit Service |
26469c |
__u16
|
|
Packit Service |
26469c |
acpi_ids_getfamily(void)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
/* if the IDs haven't been initialized, initialize them */
|
|
Packit Service |
26469c |
if (initialized == 0)
|
|
Packit Service |
26469c |
acpi_ids_init();
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return acpi_event_family_id;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* returns the netlink multicast group ID for ACPI event messages */
|
|
Packit Service |
26469c |
__u32
|
|
Packit Service |
26469c |
acpi_ids_getgroup(void)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
/* if the IDs haven't been initialized, initialize them */
|
|
Packit Service |
26469c |
if (initialized == 0)
|
|
Packit Service |
26469c |
acpi_ids_init();
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return acpi_event_mcast_group_id;
|
|
Packit Service |
26469c |
}
|