NetlinkEvent.cpp revision 17260b14682d4fe59dad3de2de8c9370e6ba9a71
1168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat/* 2168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Copyright (C) 2008 The Android Open Source Project 3168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * 4168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Licensed under the Apache License, Version 2.0 (the "License"); 5168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * you may not use this file except in compliance with the License. 6168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * You may obtain a copy of the License at 7168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * 8168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * http://www.apache.org/licenses/LICENSE-2.0 9168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * 10168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * Unless required by applicable law or agreed to in writing, software 11168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * distributed under the License is distributed on an "AS IS" BASIS, 12168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * See the License for the specific language governing permissions and 14168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat * limitations under the License. 15168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat */ 16168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#include <stdlib.h> 173d40729054803fae1c4d4bb5ac7554665a132b26San Mehat#include <string.h> 18168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 19168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#define LOG_TAG "NetlinkEvent" 20168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#include <cutils/log.h> 21168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 22168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat#include <sysutils/NetlinkEvent.h> 23168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 24ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <sys/types.h> 25ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <sys/socket.h> 26ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <linux/rtnetlink.h> 27ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <linux/if.h> 28ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 29168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionUnknown = 0; 30168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionAdd = 1; 31168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionRemove = 2; 32168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionChange = 3; 33ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenconst int NetlinkEvent::NlActionLinkUp = 4; 34ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenconst int NetlinkEvent::NlActionLinkDown = 5; 35168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 36168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::NetlinkEvent() { 37168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mAction = NlActionUnknown; 38ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat memset(mParams, 0, sizeof(mParams)); 39ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat mPath = NULL; 40ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat mSubsystem = NULL; 41168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 42168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 43168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::~NetlinkEvent() { 44168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int i; 45168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (mPath) 46168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mPath); 47168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (mSubsystem) 48168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mSubsystem); 49168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat for (i = 0; i < NL_PARAMS_MAX; i++) { 50168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (!mParams[i]) 51168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat break; 52168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mParams[i]); 53168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 54168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 55168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 56d674413ff460afe1da049e54bb7a489132799749San Mehatvoid NetlinkEvent::dump() { 57d674413ff460afe1da049e54bb7a489132799749San Mehat int i; 58d674413ff460afe1da049e54bb7a489132799749San Mehat 59d674413ff460afe1da049e54bb7a489132799749San Mehat for (i = 0; i < NL_PARAMS_MAX; i++) { 60d674413ff460afe1da049e54bb7a489132799749San Mehat if (!mParams[i]) 61d674413ff460afe1da049e54bb7a489132799749San Mehat break; 627e8529a8b528fd30586aa037f15a31b29582c537San Mehat SLOGD("NL param '%s'\n", mParams[i]); 63d674413ff460afe1da049e54bb7a489132799749San Mehat } 64d674413ff460afe1da049e54bb7a489132799749San Mehat} 65d674413ff460afe1da049e54bb7a489132799749San Mehat 66ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/* 67ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * Parse an binary message from a NETLINK_ROUTE netlink socket. 68ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */ 69ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { 70ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen size_t sz = size; 7117260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen const struct nlmsghdr *nh = (struct nlmsghdr *) buffer; 72ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 73ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) { 74ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen if (nh->nlmsg_type == RTM_NEWLINK) { 75ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen int len = nh->nlmsg_len - sizeof(*nh); 76ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen struct ifinfomsg *ifi; 77ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 78ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen if (sizeof(*ifi) <= (size_t) len) { 79ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen ifi = (ifinfomsg *)NLMSG_DATA(nh); 80ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 81ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen if ((ifi->ifi_flags & IFF_LOOPBACK) == 0) { 82ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen struct rtattr *rta = (struct rtattr *) 83ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi))); 84ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen len = NLMSG_PAYLOAD(nh, sizeof(*ifi)); 85ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 86ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen while(RTA_OK(rta, len)) { 87ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen switch(rta->rta_type) { 88ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen case IFLA_IFNAME: 89ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen char buffer[16 + IFNAMSIZ]; 90ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen snprintf(buffer, sizeof(buffer), "INTERFACE=%s", 91ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen (char *) RTA_DATA(rta)); 92ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen mParams[0] = strdup(buffer); 93ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? 94ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen NlActionLinkUp : NlActionLinkDown; 95ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen mSubsystem = strdup("net"); 96ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen break; 97ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 98ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 99ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen rta = RTA_NEXT(rta, len); 100ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 101ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 102ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 103ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 104ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 105ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen nh = NLMSG_NEXT(nh, size); 106ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 107ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 108ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen return true; 109ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen} 110ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 1113311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* If the string between 'str' and 'end' begins with 'prefixlen' characters 1123311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * from the 'prefix' array, then return 'str + prefixlen', otherwise return 1133311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * NULL. 1143311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner */ 1153311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerstatic const char* 1163311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerhas_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) 1173311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner{ 1183311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen)) 1193311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return str + prefixlen; 1203311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner else 1213311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return NULL; 1223311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner} 1233311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 1243311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Same as strlen(x) for constant string literals ONLY */ 1253311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define CONST_STRLEN(x) (sizeof(x)-1) 1263311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 1273311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Convenience macro to call has_prefix with a constant string literal */ 1283311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) 1293311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 1303311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 131ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/* 132ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT 133ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * netlink socket. 134ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */ 135ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { 13617260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen const char *s = buffer; 13717260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen const char *end; 138168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int param_idx = 0; 139168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int i; 140168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int first = 1; 141168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 1423311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if (size == 0) 1433311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return false; 1443311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 1453311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner /* Ensure the buffer is zero-terminated, the code below depends on this */ 1463311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner buffer[size-1] = '\0'; 1473311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 148168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat end = s + size; 149168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat while (s < end) { 150168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (first) { 1513311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner const char *p; 1523311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner /* buffer is 0-terminated, no need to check p < end */ 1533311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner for (p = s; *p != '@'; p++) { 1543311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if (!*p) { /* no '@', should not happen */ 1553311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return false; 1563311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 1573311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 1583311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mPath = strdup(p+1); 159168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat first = 0; 160168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } else { 1613311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner const char* a; 1623311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { 163168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (!strcmp(a, "add")) 164168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mAction = NlActionAdd; 165168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat else if (!strcmp(a, "remove")) 166168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mAction = NlActionRemove; 167168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat else if (!strcmp(a, "change")) 168168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mAction = NlActionChange; 1693311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { 1703311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mSeq = atoi(a); 1713311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { 1723311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mSubsystem = strdup(a); 1733311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if (param_idx < NL_PARAMS_MAX) { 174168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mParams[param_idx++] = strdup(s); 1753311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 176168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 1773311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner s += strlen(s) + 1; 178168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 179168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat return true; 180168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 181168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 182ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::decode(char *buffer, int size, int format) { 18317260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { 18417260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen return parseBinaryNetlinkMessage(buffer, size); 18517260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen } else { 18617260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen return parseAsciiNetlinkMessage(buffer, size); 18717260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen } 188ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen} 189ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 190168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst char *NetlinkEvent::findParam(const char *paramName) { 19180ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang size_t len = strlen(paramName); 1923311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { 19380ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang const char *ptr = mParams[i] + len; 19480ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang if (!strncmp(mParams[i], paramName, len) && *ptr == '=') 19580ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang return ++ptr; 196168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 197168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 1987e8529a8b528fd30586aa037f15a31b29582c537San Mehat SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); 199168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat return NULL; 200168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 201