blob: f2eb664d812a210fac796d8b049bde6d40eeb701 [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>
26#include <linux/rtnetlink.h>
27#include <linux/if.h>
28
San Mehat168415b2009-05-06 11:14:21 -070029const int NetlinkEvent::NlActionUnknown = 0;
30const int NetlinkEvent::NlActionAdd = 1;
31const int NetlinkEvent::NlActionRemove = 2;
32const int NetlinkEvent::NlActionChange = 3;
Mike J. Chenec16b9d2011-06-23 14:55:28 -070033const int NetlinkEvent::NlActionLinkUp = 4;
34const int NetlinkEvent::NlActionLinkDown = 5;
San Mehat168415b2009-05-06 11:14:21 -070035
36NetlinkEvent::NetlinkEvent() {
37 mAction = NlActionUnknown;
San Mehatebfe3db2009-10-10 17:35:13 -070038 memset(mParams, 0, sizeof(mParams));
39 mPath = NULL;
40 mSubsystem = NULL;
San Mehat168415b2009-05-06 11:14:21 -070041}
42
43NetlinkEvent::~NetlinkEvent() {
44 int i;
45 if (mPath)
46 free(mPath);
47 if (mSubsystem)
48 free(mSubsystem);
49 for (i = 0; i < NL_PARAMS_MAX; i++) {
50 if (!mParams[i])
51 break;
52 free(mParams[i]);
53 }
54}
55
San Mehatd6744132009-12-24 07:17:09 -080056void NetlinkEvent::dump() {
57 int i;
58
59 for (i = 0; i < NL_PARAMS_MAX; i++) {
60 if (!mParams[i])
61 break;
San Mehat7e8529a2010-03-25 09:31:42 -070062 SLOGD("NL param '%s'\n", mParams[i]);
San Mehatd6744132009-12-24 07:17:09 -080063 }
64}
65
Mike J. Chenec16b9d2011-06-23 14:55:28 -070066/*
67 * Parse an binary message from a NETLINK_ROUTE netlink socket.
68 */
69bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
70 size_t sz = size;
Mike J. Chen17260b12011-06-23 15:00:30 -070071 const struct nlmsghdr *nh = (struct nlmsghdr *) buffer;
Mike J. Chenec16b9d2011-06-23 14:55:28 -070072
73 while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) {
74 if (nh->nlmsg_type == RTM_NEWLINK) {
75 int len = nh->nlmsg_len - sizeof(*nh);
76 struct ifinfomsg *ifi;
77
78 if (sizeof(*ifi) <= (size_t) len) {
79 ifi = (ifinfomsg *)NLMSG_DATA(nh);
80
81 if ((ifi->ifi_flags & IFF_LOOPBACK) == 0) {
82 struct rtattr *rta = (struct rtattr *)
83 ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
84 len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
85
86 while(RTA_OK(rta, len)) {
87 switch(rta->rta_type) {
88 case IFLA_IFNAME:
89 char buffer[16 + IFNAMSIZ];
90 snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
91 (char *) RTA_DATA(rta));
92 mParams[0] = strdup(buffer);
93 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
94 NlActionLinkUp : NlActionLinkDown;
95 mSubsystem = strdup("net");
96 break;
97 }
98
99 rta = RTA_NEXT(rta, len);
100 }
101 }
102 }
103 }
104
105 nh = NLMSG_NEXT(nh, size);
106 }
107
108 return true;
109}
110
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100111/* If the string between 'str' and 'end' begins with 'prefixlen' characters
112 * from the 'prefix' array, then return 'str + prefixlen', otherwise return
113 * NULL.
114 */
115static const char*
116has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
117{
118 if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
119 return str + prefixlen;
120 else
121 return NULL;
122}
123
124/* Same as strlen(x) for constant string literals ONLY */
125#define CONST_STRLEN(x) (sizeof(x)-1)
126
127/* Convenience macro to call has_prefix with a constant string literal */
128#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
129
130
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700131/*
132 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
133 * netlink socket.
134 */
135bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700136 const char *s = buffer;
137 const char *end;
San Mehat168415b2009-05-06 11:14:21 -0700138 int param_idx = 0;
139 int i;
140 int first = 1;
141
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100142 if (size == 0)
143 return false;
144
145 /* Ensure the buffer is zero-terminated, the code below depends on this */
146 buffer[size-1] = '\0';
147
San Mehat168415b2009-05-06 11:14:21 -0700148 end = s + size;
149 while (s < end) {
150 if (first) {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100151 const char *p;
152 /* buffer is 0-terminated, no need to check p < end */
153 for (p = s; *p != '@'; p++) {
154 if (!*p) { /* no '@', should not happen */
155 return false;
156 }
157 }
158 mPath = strdup(p+1);
San Mehat168415b2009-05-06 11:14:21 -0700159 first = 0;
160 } else {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100161 const char* a;
162 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
San Mehat168415b2009-05-06 11:14:21 -0700163 if (!strcmp(a, "add"))
164 mAction = NlActionAdd;
165 else if (!strcmp(a, "remove"))
166 mAction = NlActionRemove;
167 else if (!strcmp(a, "change"))
168 mAction = NlActionChange;
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100169 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
170 mSeq = atoi(a);
171 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
172 mSubsystem = strdup(a);
173 } else if (param_idx < NL_PARAMS_MAX) {
San Mehat168415b2009-05-06 11:14:21 -0700174 mParams[param_idx++] = strdup(s);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100175 }
San Mehat168415b2009-05-06 11:14:21 -0700176 }
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100177 s += strlen(s) + 1;
San Mehat168415b2009-05-06 11:14:21 -0700178 }
179 return true;
180}
181
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700182bool NetlinkEvent::decode(char *buffer, int size, int format) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700183 if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
184 return parseBinaryNetlinkMessage(buffer, size);
185 } else {
186 return parseAsciiNetlinkMessage(buffer, size);
187 }
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700188}
189
San Mehat168415b2009-05-06 11:14:21 -0700190const char *NetlinkEvent::findParam(const char *paramName) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800191 size_t len = strlen(paramName);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100192 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800193 const char *ptr = mParams[i] + len;
194 if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
195 return ++ptr;
San Mehat168415b2009-05-06 11:14:21 -0700196 }
197
San Mehat7e8529a2010-03-25 09:31:42 -0700198 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
San Mehat168415b2009-05-06 11:14:21 -0700199 return NULL;
200}