blob: 41bd2151a2dea8474cc429a195c3871b4fa79fcd [file] [log] [blame]
San Mehat168415b2009-05-06 11:14:21 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <stdlib.h>
San Mehat3d407292009-05-07 08:49:30 -070017#include <string.h>
San Mehat168415b2009-05-06 11:14:21 -070018
19#define LOG_TAG "NetlinkEvent"
20#include <cutils/log.h>
21
22#include <sysutils/NetlinkEvent.h>
23
Mike J. Chenec16b9d2011-06-23 14:55:28 -070024#include <sys/types.h>
25#include <sys/socket.h>
Lorenzo Colitti381f70f2013-08-02 05:58:37 +090026#include <netinet/in.h>
Lorenzo Colittic7eec832013-08-12 17:03:32 +090027#include <netinet/icmp6.h>
Lorenzo Colitti381f70f2013-08-02 05:58:37 +090028#include <arpa/inet.h>
29#include <net/if.h>
30
Mike J. Chenec16b9d2011-06-23 14:55:28 -070031#include <linux/if.h>
Lorenzo Colitti9b342932014-06-19 13:16:04 +090032#include <linux/if_addr.h>
33#include <linux/if_link.h>
JP Abgralle6f80142011-07-14 16:46:32 -070034#include <linux/netfilter/nfnetlink.h>
35#include <linux/netfilter_ipv4/ipt_ULOG.h>
36/* From kernel's net/netfilter/xt_quota2.c */
37const int QLOG_NL_EVENT = 112;
38
39#include <linux/netlink.h>
40#include <linux/rtnetlink.h>
Mike J. Chenec16b9d2011-06-23 14:55:28 -070041
San Mehat168415b2009-05-06 11:14:21 -070042const int NetlinkEvent::NlActionUnknown = 0;
43const int NetlinkEvent::NlActionAdd = 1;
44const int NetlinkEvent::NlActionRemove = 2;
45const int NetlinkEvent::NlActionChange = 3;
Mike J. Chenec16b9d2011-06-23 14:55:28 -070046const int NetlinkEvent::NlActionLinkUp = 4;
47const int NetlinkEvent::NlActionLinkDown = 5;
Lorenzo Colitti526b8382013-09-03 00:25:14 +090048const int NetlinkEvent::NlActionAddressUpdated = 6;
49const int NetlinkEvent::NlActionAddressRemoved = 7;
Lorenzo Colittic7eec832013-08-12 17:03:32 +090050const int NetlinkEvent::NlActionRdnss = 8;
San Mehat168415b2009-05-06 11:14:21 -070051
52NetlinkEvent::NetlinkEvent() {
53 mAction = NlActionUnknown;
San Mehatebfe3db2009-10-10 17:35:13 -070054 memset(mParams, 0, sizeof(mParams));
55 mPath = NULL;
56 mSubsystem = NULL;
San Mehat168415b2009-05-06 11:14:21 -070057}
58
59NetlinkEvent::~NetlinkEvent() {
60 int i;
61 if (mPath)
62 free(mPath);
63 if (mSubsystem)
64 free(mSubsystem);
65 for (i = 0; i < NL_PARAMS_MAX; i++) {
66 if (!mParams[i])
67 break;
68 free(mParams[i]);
69 }
70}
71
San Mehatd6744132009-12-24 07:17:09 -080072void NetlinkEvent::dump() {
73 int i;
74
75 for (i = 0; i < NL_PARAMS_MAX; i++) {
76 if (!mParams[i])
77 break;
San Mehat7e8529a2010-03-25 09:31:42 -070078 SLOGD("NL param '%s'\n", mParams[i]);
San Mehatd6744132009-12-24 07:17:09 -080079 }
80}
81
Mike J. Chenec16b9d2011-06-23 14:55:28 -070082/*
Lorenzo Colitti9b342932014-06-19 13:16:04 +090083 * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
84 * if parsing that message is not supported.
85 */
86static const char *rtMessageName(int type) {
87#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
88 switch (type) {
89 NL_EVENT_RTM_NAME(RTM_NEWLINK);
90 NL_EVENT_RTM_NAME(RTM_DELLINK);
91 NL_EVENT_RTM_NAME(RTM_NEWADDR);
92 NL_EVENT_RTM_NAME(RTM_DELADDR);
93 NL_EVENT_RTM_NAME(RTM_NEWROUTE);
94 NL_EVENT_RTM_NAME(RTM_DELROUTE);
95 NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
96 NL_EVENT_RTM_NAME(QLOG_NL_EVENT);
97 default:
98 return NULL;
99 }
100#undef NL_EVENT_RTM_NAME
101}
102
103/*
104 * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
105 * size bytes.
106 */
107static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
108 if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
109 SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
110 return false;
111 }
112 return true;
113}
114
115/*
116 * Utility function to log errors.
117 */
118static bool maybeLogDuplicateAttribute(bool isDup,
119 const char *attributeName,
120 const char *messageName) {
121 if (isDup) {
122 SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
123 return true;
124 }
125 return false;
126}
127
128/*
129 * Parse a RTM_NEWLINK message.
130 */
131bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
132 struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
133 if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
134 return false;
135
136 if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
137 return false;
138 }
139
140 int len = IFLA_PAYLOAD(nh);
141 struct rtattr *rta;
142 for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
143 switch(rta->rta_type) {
144 case IFLA_IFNAME:
145 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
146 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp :
147 NlActionLinkDown;
148 mSubsystem = strdup("net");
149 return true;
150 }
151 }
152
153 return false;
154}
155
156/*
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900157 * Parse a RTM_NEWADDR or RTM_DELADDR message.
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900158 */
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900159bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
160 struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900161 struct ifa_cacheinfo *cacheinfo = NULL;
162 char addrstr[INET6_ADDRSTRLEN] = "";
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900163 char ifname[IFNAMSIZ];
164
165 if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
166 return false;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900167
168 // Sanity check.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900169 int type = nh->nlmsg_type;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900170 if (type != RTM_NEWADDR && type != RTM_DELADDR) {
171 SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
172 return false;
173 }
174
175 // For log messages.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900176 const char *msgtype = rtMessageName(type);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900177
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900178 struct rtattr *rta;
179 int len = IFA_PAYLOAD(nh);
180 for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900181 if (rta->rta_type == IFA_ADDRESS) {
182 // Only look at the first address, because we only support notifying
183 // one change at a time.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900184 if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900185 continue;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900186
187 // Convert the IP address to a string.
188 if (ifaddr->ifa_family == AF_INET) {
189 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
190 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700191 SLOGE("Short IPv4 address (%zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900192 RTA_PAYLOAD(rta), msgtype);
193 continue;
194 }
195 inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr));
196 } else if (ifaddr->ifa_family == AF_INET6) {
197 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
198 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700199 SLOGE("Short IPv6 address (%zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900200 RTA_PAYLOAD(rta), msgtype);
201 continue;
202 }
203 inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr));
204 } else {
205 SLOGE("Unknown address family %d\n", ifaddr->ifa_family);
206 continue;
207 }
208
209 // Find the interface name.
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900210 if (!if_indextoname(ifaddr->ifa_index, ifname)) {
211 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
212 return false;
213 }
214
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900215 } else if (rta->rta_type == IFA_CACHEINFO) {
216 // Address lifetime information.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900217 if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900218 continue;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900219
220 if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700221 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900222 RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
223 continue;
224 }
225
226 cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900227 }
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900228 }
229
230 if (addrstr[0] == '\0') {
231 SLOGE("No IFA_ADDRESS in %s\n", msgtype);
232 return false;
233 }
234
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900235 // Fill in netlink event information.
236 mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
237 NlActionAddressRemoved;
238 mSubsystem = strdup("net");
239 asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
240 ifaddr->ifa_prefixlen);
241 asprintf(&mParams[1], "INTERFACE=%s", ifname);
242 asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
243 asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
244
245 if (cacheinfo) {
246 asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
247 asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
248 asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
249 asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
250 }
251
252 return true;
253}
254
255/*
256 * Parse a QLOG_NL_EVENT message.
257 */
258bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
259 const char *devname;
260 ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
261 if (!checkRtNetlinkLength(nh, sizeof(*pm)))
262 return false;
263
264 devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
265 asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
266 asprintf(&mParams[1], "INTERFACE=%s", devname);
267 mSubsystem = strdup("qlog");
268 mAction = NlActionChange;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900269 return true;
270}
271
272/*
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900273 * Parse a RTM_NEWNDUSEROPT message.
274 */
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900275bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
276 struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
277 if (!checkRtNetlinkLength(nh, sizeof(*msg)))
278 return false;
279
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900280 // Check the length is valid.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900281 int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900282 if (msg->nduseropt_opts_len > len) {
283 SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
284 msg->nduseropt_opts_len, len);
285 return false;
286 }
287 len = msg->nduseropt_opts_len;
288
289 // Check address family and packet type.
290 if (msg->nduseropt_family != AF_INET6) {
291 SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n",
292 msg->nduseropt_family);
293 return false;
294 }
295
296 if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
297 msg->nduseropt_icmp_code != 0) {
298 SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n",
299 msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
300 return false;
301 }
302
303 // Find the interface name.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900304 char ifname[IFNAMSIZ];
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900305 if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
306 SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
307 msg->nduseropt_ifindex);
308 return false;
309 }
310
311 // The kernel sends a separate netlink message for each ND option in the RA.
312 // So only parse the first ND option in the message.
313 struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1);
314
315 // The length is in multiples of 8 octets.
316 uint16_t optlen = opthdr->nd_opt_len;
317 if (optlen * 8 > len) {
318 SLOGE("Invalid option length %d > %d for ND option %d\n",
319 optlen * 8, len, opthdr->nd_opt_type);
320 return false;
321 }
322
323 if (opthdr->nd_opt_type == ND_OPT_RDNSS) {
324 // DNS Servers (RFC 6106).
325 // Each address takes up 2*8 octets, and the header takes up 8 octets.
326 // So for a valid option with one or more addresses, optlen must be
327 // odd and greater than 1.
328 if ((optlen < 3) || !(optlen & 0x1)) {
329 SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
330 return false;
331 }
332 int numaddrs = (optlen - 1) / 2;
333
334 // Find the lifetime.
335 struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
336 uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
337
338 // Construct "SERVERS=<comma-separated string of DNS addresses>".
339 // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
340 // the last address are followed by ','; the last is followed by '\0'.
341 static const char kServerTag[] = "SERVERS=";
342 static const int kTagLength = sizeof(kServerTag) - 1;
343 int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
344 char *buf = (char *) malloc(bufsize);
345 if (!buf) {
346 SLOGE("RDNSS option: out of memory\n");
347 return false;
348 }
349 strcpy(buf, kServerTag);
350 int pos = kTagLength;
351
352 struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
353 for (int i = 0; i < numaddrs; i++) {
354 if (i > 0) {
355 buf[pos++] = ',';
356 }
357 inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
358 pos += strlen(buf + pos);
359 }
360 buf[pos] = '\0';
361
362 mAction = NlActionRdnss;
363 mSubsystem = strdup("net");
364 asprintf(&mParams[0], "INTERFACE=%s", ifname);
365 asprintf(&mParams[1], "LIFETIME=%u", lifetime);
366 mParams[2] = buf;
367 } else {
368 SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
369 return false;
370 }
371
372 return true;
373}
374
375/*
376 * Parse a binary message from a NETLINK_ROUTE netlink socket.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900377 *
378 * Note that this function can only parse one message, because the message's
379 * content has to be stored in the class's member variables (mAction,
380 * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
381 * there are multiple valid messages in the buffer, only the first one will be
382 * returned.
383 *
384 * TODO: consider only ever looking at the first message.
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700385 */
386bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
Lorenzo Colitti96834562013-08-17 03:40:31 +0900387 const struct nlmsghdr *nh;
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700388
Lorenzo Colitti96834562013-08-17 03:40:31 +0900389 for (nh = (struct nlmsghdr *) buffer;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900390 NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
Lorenzo Colitti96834562013-08-17 03:40:31 +0900391 nh = NLMSG_NEXT(nh, size)) {
JP Abgralle6f80142011-07-14 16:46:32 -0700392
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900393 if (!rtMessageName(nh->nlmsg_type)) {
394 SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
395 continue;
396 }
397
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700398 if (nh->nlmsg_type == RTM_NEWLINK) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900399 if (parseIfInfoMessage(nh))
400 return true;
JP Abgralle6f80142011-07-14 16:46:32 -0700401
402 } else if (nh->nlmsg_type == QLOG_NL_EVENT) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900403 if (parseUlogPacketMessage(nh))
404 return true;
JP Abgralle6f80142011-07-14 16:46:32 -0700405
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900406 } else if (nh->nlmsg_type == RTM_NEWADDR ||
407 nh->nlmsg_type == RTM_DELADDR) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900408 if (parseIfAddrMessage(nh))
409 return true;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900410
411 } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900412 if (parseNdUserOptMessage(nh))
413 return true;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900414
JP Abgralle6f80142011-07-14 16:46:32 -0700415 }
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700416 }
417
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900418 return false;
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700419}
420
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100421/* If the string between 'str' and 'end' begins with 'prefixlen' characters
422 * from the 'prefix' array, then return 'str + prefixlen', otherwise return
423 * NULL.
424 */
425static const char*
426has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
427{
428 if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
429 return str + prefixlen;
430 else
431 return NULL;
432}
433
434/* Same as strlen(x) for constant string literals ONLY */
435#define CONST_STRLEN(x) (sizeof(x)-1)
436
437/* Convenience macro to call has_prefix with a constant string literal */
438#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
439
440
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700441/*
442 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
443 * netlink socket.
444 */
445bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700446 const char *s = buffer;
447 const char *end;
San Mehat168415b2009-05-06 11:14:21 -0700448 int param_idx = 0;
San Mehat168415b2009-05-06 11:14:21 -0700449 int first = 1;
450
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100451 if (size == 0)
452 return false;
453
454 /* Ensure the buffer is zero-terminated, the code below depends on this */
455 buffer[size-1] = '\0';
456
San Mehat168415b2009-05-06 11:14:21 -0700457 end = s + size;
458 while (s < end) {
459 if (first) {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100460 const char *p;
461 /* buffer is 0-terminated, no need to check p < end */
462 for (p = s; *p != '@'; p++) {
463 if (!*p) { /* no '@', should not happen */
464 return false;
465 }
466 }
467 mPath = strdup(p+1);
San Mehat168415b2009-05-06 11:14:21 -0700468 first = 0;
469 } else {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100470 const char* a;
471 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
San Mehat168415b2009-05-06 11:14:21 -0700472 if (!strcmp(a, "add"))
473 mAction = NlActionAdd;
474 else if (!strcmp(a, "remove"))
475 mAction = NlActionRemove;
476 else if (!strcmp(a, "change"))
477 mAction = NlActionChange;
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100478 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
479 mSeq = atoi(a);
480 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
481 mSubsystem = strdup(a);
482 } else if (param_idx < NL_PARAMS_MAX) {
San Mehat168415b2009-05-06 11:14:21 -0700483 mParams[param_idx++] = strdup(s);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100484 }
San Mehat168415b2009-05-06 11:14:21 -0700485 }
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100486 s += strlen(s) + 1;
San Mehat168415b2009-05-06 11:14:21 -0700487 }
488 return true;
489}
490
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700491bool NetlinkEvent::decode(char *buffer, int size, int format) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700492 if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
493 return parseBinaryNetlinkMessage(buffer, size);
494 } else {
495 return parseAsciiNetlinkMessage(buffer, size);
496 }
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700497}
498
San Mehat168415b2009-05-06 11:14:21 -0700499const char *NetlinkEvent::findParam(const char *paramName) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800500 size_t len = strlen(paramName);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100501 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800502 const char *ptr = mParams[i] + len;
503 if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
504 return ++ptr;
San Mehat168415b2009-05-06 11:14:21 -0700505 }
506
San Mehat7e8529a2010-03-25 09:31:42 -0700507 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
San Mehat168415b2009-05-06 11:14:21 -0700508 return NULL;
509}