2 * acpi_ids.c - ACPI Netlink Group and Family IDs
4 * Copyright (C) 2008 Ted Felix (www.tedfelix.com)
5 * Portions from acpi_genl Copyright (C) Zhang Rui <rui.zhang@intel.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* needed by netlink.h, should be in there */
24 #include <arpa/inet.h>
25 #include <linux/types.h>
28 #include "genetlink.h"
29 #include "libnetlink.h"
34 #define GENL_MAX_FAM_GRPS 256
35 #define ACPI_EVENT_FAMILY_NAME "acpi_event"
36 #define ACPI_EVENT_MCAST_GROUP_NAME "acpi_mc_group"
38 static int initialized = 0;
39 static __u16 acpi_event_family_id = 0;
40 static __u32 acpi_event_mcast_group_id = 0;
43 * A CTRL_CMD_GETFAMILY message returns an attribute table that looks
46 * CTRL_ATTR_FAMILY_ID Use this to make sure we get the proper msgs
47 * CTRL_ATTR_MCAST_GROUPS
48 * CTRL_ATTR_MCAST_GRP_NAME
49 * CTRL_ATTR_MCAST_GRP_ID Need this for the group mask
54 get_ctrl_grp_id(struct rtattr *arg)
56 struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
62 /* nested within the CTRL_ATTR_MCAST_GROUPS attribute are the */
63 /* group name and ID */
64 parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
66 /* if either of the entries needed cannot be found, bail */
67 if (!tb[CTRL_ATTR_MCAST_GRP_NAME] || !tb[CTRL_ATTR_MCAST_GRP_ID])
70 /* get the name of this multicast group we've found */
71 name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
73 /* if it does not match the ACPI event multicast group name, bail */
74 if (strcmp(name, ACPI_EVENT_MCAST_GROUP_NAME))
77 /* At this point, we've found what we were looking for. We now */
78 /* have the multicast group ID for ACPI events over generic netlink. */
79 acpi_event_mcast_group_id =
80 *((__u32 *)RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]));
85 /* n = the response to a CTRL_CMD_GETFAMILY message */
87 genl_get_mcast_group_id(struct nlmsghdr *n)
90 * Attribute table. Note the type name "rtattr" which means "route
91 * attribute". This is a vestige of one of netlink's main uses:
94 struct rtattr *tb[CTRL_ATTR_MAX + 1];
95 /* place for the generic netlink header in the incoming message */
96 struct genlmsghdr ghdr;
97 /* length of the attribute and payload */
98 int len = n->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
99 /* Pointer to the attribute portion of the message */
100 struct rtattr *attrs;
103 fprintf(stderr, "%s: netlink CTRL_CMD_GETFAMILY response, "
104 "wrong controller message len: %d\n", progname, len);
108 if (n->nlmsg_type != GENL_ID_CTRL) {
109 fprintf(stderr, "%s: not a netlink controller message, "
110 "nlmsg_len=%d nlmsg_type=0x%x\n",
111 progname, n->nlmsg_len, n->nlmsg_type);
115 /* copy generic netlink header into structure */
116 memcpy(&ghdr, NLMSG_DATA(n), GENL_HDRLEN);
118 if (ghdr.cmd != CTRL_CMD_GETFAMILY &&
119 ghdr.cmd != CTRL_CMD_DELFAMILY &&
120 ghdr.cmd != CTRL_CMD_NEWFAMILY &&
121 ghdr.cmd != CTRL_CMD_NEWMCAST_GRP &&
122 ghdr.cmd != CTRL_CMD_DELMCAST_GRP) {
123 fprintf(stderr, "%s: unknown netlink controller command %d\n",
128 /* set attrs to point to the attribute */
129 attrs = (struct rtattr *)(NLMSG_DATA(n) + GENL_HDRLEN);
130 /* Read the table from the message into "tb". This actually just */
131 /* places pointers into the message into tb[]. */
132 parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
134 /* if a family ID attribute is present, get it */
135 if (tb[CTRL_ATTR_FAMILY_ID])
137 acpi_event_family_id =
138 *((__u32 *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]));
141 /* if a "multicast groups" attribute is present... */
142 if (tb[CTRL_ATTR_MCAST_GROUPS]) {
143 struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
146 /* get the group table within this attribute */
147 parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
148 tb[CTRL_ATTR_MCAST_GROUPS]);
151 for (i = 0; i < GENL_MAX_FAM_GRPS; i++)
152 /* if this group is valid */
154 /* Parse the ID. If successful, we're done. */
155 if (!get_ctrl_grp_id(tb2[i]))
163 genl_get_ids(char *family_name)
165 /* handle to the netlink connection */
166 struct rtnl_handle rth;
167 /* holds the request we are going to send and the reply */
170 char buf[4096]; /* ??? Is this big enough for all cases? */
172 /* pointer to the nlmsghdr in req */
173 struct nlmsghdr *nlh;
174 /* place for the generic netlink header before copied into req */
175 struct genlmsghdr ghdr;
179 /* clear out the request */
180 memset(&req, 0, sizeof(req));
182 /* set up nlh to point to the netlink header in req */
184 /* set up the netlink header */
185 nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
186 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
187 nlh->nlmsg_type = GENL_ID_CTRL;
189 /* clear out the generic netlink message header */
190 memset(&ghdr, 0, sizeof(struct genlmsghdr));
191 /* set the command we want to run: "GETFAMILY" */
192 ghdr.cmd = CTRL_CMD_GETFAMILY;
193 /* copy it into req */
194 memcpy(NLMSG_DATA(&req.n), &ghdr, GENL_HDRLEN);
196 /* the message payload is the family name */
197 addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
198 family_name, strlen(family_name) + 1);
200 /* open a generic netlink connection */
201 if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
202 fprintf(stderr, "%s: cannot open generic netlink socket\n",
208 * Send CTRL_CMD_GETFAMILY message (in nlh) to the generic
209 * netlink controller. Reply will be in nlh upon return.
211 if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
212 fprintf(stderr, "%s: error talking to the kernel via netlink\n",
217 /* process the response */
218 if (genl_get_mcast_group_id(nlh) < 0) {
219 fprintf(stderr, "%s: failed to get acpi_event netlink "
220 "multicast group\n", progname);
231 /* initialize the ACPI IDs */
235 genl_get_ids(ACPI_EVENT_FAMILY_NAME);
240 /* returns the netlink family ID for ACPI event messages */
242 acpi_ids_getfamily(void)
244 /* if the IDs haven't been initialized, initialize them */
245 if (initialized == 0)
248 return acpi_event_family_id;
251 /* returns the netlink multicast group ID for ACPI event messages */
253 acpi_ids_getgroup(void)
255 /* if the IDs haven't been initialized, initialize them */
256 if (initialized == 0)
259 return acpi_event_mcast_group_id;