NetlinkEvent.cpp revision ec16b9d47cacb0d873ee0ff80c919f49215c0005
1/* 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> 17#include <string.h> 18 19#define LOG_TAG "NetlinkEvent" 20#include <cutils/log.h> 21 22#include <sysutils/NetlinkListener.h> 23#include <sysutils/NetlinkEvent.h> 24 25#include <sys/types.h> 26#include <sys/socket.h> 27#include <linux/rtnetlink.h> 28#include <linux/if.h> 29 30const int NetlinkEvent::NlActionUnknown = 0; 31const int NetlinkEvent::NlActionAdd = 1; 32const int NetlinkEvent::NlActionRemove = 2; 33const int NetlinkEvent::NlActionChange = 3; 34const int NetlinkEvent::NlActionLinkUp = 4; 35const int NetlinkEvent::NlActionLinkDown = 5; 36 37NetlinkEvent::NetlinkEvent() { 38 mAction = NlActionUnknown; 39 memset(mParams, 0, sizeof(mParams)); 40 mPath = NULL; 41 mSubsystem = NULL; 42} 43 44NetlinkEvent::~NetlinkEvent() { 45 int i; 46 if (mPath) 47 free(mPath); 48 if (mSubsystem) 49 free(mSubsystem); 50 for (i = 0; i < NL_PARAMS_MAX; i++) { 51 if (!mParams[i]) 52 break; 53 free(mParams[i]); 54 } 55} 56 57void NetlinkEvent::dump() { 58 int i; 59 60 for (i = 0; i < NL_PARAMS_MAX; i++) { 61 if (!mParams[i]) 62 break; 63 SLOGD("NL param '%s'\n", mParams[i]); 64 } 65} 66 67/* 68 * Parse an binary message from a NETLINK_ROUTE netlink socket. 69 */ 70bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { 71 size_t sz = size; 72 struct nlmsghdr *nh = (struct nlmsghdr *) buffer; 73 74 while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) { 75 if (nh->nlmsg_type == RTM_NEWLINK) { 76 int len = nh->nlmsg_len - sizeof(*nh); 77 struct ifinfomsg *ifi; 78 79 if (sizeof(*ifi) <= (size_t) len) { 80 ifi = (ifinfomsg *)NLMSG_DATA(nh); 81 82 if ((ifi->ifi_flags & IFF_LOOPBACK) == 0) { 83 struct rtattr *rta = (struct rtattr *) 84 ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi))); 85 len = NLMSG_PAYLOAD(nh, sizeof(*ifi)); 86 87 while(RTA_OK(rta, len)) { 88 switch(rta->rta_type) { 89 case IFLA_IFNAME: 90 char buffer[16 + IFNAMSIZ]; 91 snprintf(buffer, sizeof(buffer), "INTERFACE=%s", 92 (char *) RTA_DATA(rta)); 93 mParams[0] = strdup(buffer); 94 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? 95 NlActionLinkUp : NlActionLinkDown; 96 mSubsystem = strdup("net"); 97 break; 98 } 99 100 rta = RTA_NEXT(rta, len); 101 } 102 } 103 } 104 } 105 106 nh = NLMSG_NEXT(nh, size); 107 } 108 109 return true; 110} 111 112/* If the string between 'str' and 'end' begins with 'prefixlen' characters 113 * from the 'prefix' array, then return 'str + prefixlen', otherwise return 114 * NULL. 115 */ 116static const char* 117has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) 118{ 119 if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen)) 120 return str + prefixlen; 121 else 122 return NULL; 123} 124 125/* Same as strlen(x) for constant string literals ONLY */ 126#define CONST_STRLEN(x) (sizeof(x)-1) 127 128/* Convenience macro to call has_prefix with a constant string literal */ 129#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) 130 131 132/* 133 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT 134 * netlink socket. 135 */ 136bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { 137 char *s = buffer; 138 char *end; 139 int param_idx = 0; 140 int i; 141 int first = 1; 142 143 if (size == 0) 144 return false; 145 146 /* Ensure the buffer is zero-terminated, the code below depends on this */ 147 buffer[size-1] = '\0'; 148 149 end = s + size; 150 while (s < end) { 151 if (first) { 152 const char *p; 153 /* buffer is 0-terminated, no need to check p < end */ 154 for (p = s; *p != '@'; p++) { 155 if (!*p) { /* no '@', should not happen */ 156 return false; 157 } 158 } 159 mPath = strdup(p+1); 160 first = 0; 161 } else { 162 const char* a; 163 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { 164 if (!strcmp(a, "add")) 165 mAction = NlActionAdd; 166 else if (!strcmp(a, "remove")) 167 mAction = NlActionRemove; 168 else if (!strcmp(a, "change")) 169 mAction = NlActionChange; 170 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { 171 mSeq = atoi(a); 172 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { 173 mSubsystem = strdup(a); 174 } else if (param_idx < NL_PARAMS_MAX) { 175 mParams[param_idx++] = strdup(s); 176 } 177 } 178 s += strlen(s) + 1; 179 } 180 return true; 181} 182 183bool NetlinkEvent::decode(char *buffer, int size, int format) { 184 if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { 185 return parseBinaryNetlinkMessage(buffer, size); 186 } else { 187 return parseAsciiNetlinkMessage(buffer, size); 188 } 189} 190 191const char *NetlinkEvent::findParam(const char *paramName) { 192 size_t len = strlen(paramName); 193 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { 194 const char *ptr = mParams[i] + len; 195 if (!strncmp(mParams[i], paramName, len) && *ptr == '=') 196 return ++ptr; 197 } 198 199 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); 200 return NULL; 201} 202