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> 26381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti#include <netinet/in.h> 27c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti#include <netinet/icmp6.h> 28381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti#include <arpa/inet.h> 29381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti#include <net/if.h> 30381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 31ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <linux/if.h> 329b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti#include <linux/if_addr.h> 339b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti#include <linux/if_link.h> 34e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netfilter/nfnetlink.h> 359a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey#include <linux/netfilter/nfnetlink_log.h> 36e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netfilter_ipv4/ipt_ULOG.h> 379a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 38e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall/* From kernel's net/netfilter/xt_quota2.c */ 399a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkeyconst int LOCAL_QLOG_NL_EVENT = 112; 409a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkeyconst int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET; 41e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall 42e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netlink.h> 43e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/rtnetlink.h> 44ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 459a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey#include <netlink/attr.h> 469a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey#include <netlink/genl/genl.h> 479a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey#include <netlink/handlers.h> 489a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey#include <netlink/msg.h> 499a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 50168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::NetlinkEvent() { 51e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kUnknown; 52ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat memset(mParams, 0, sizeof(mParams)); 53ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat mPath = NULL; 54ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat mSubsystem = NULL; 55168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 56168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 57168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::~NetlinkEvent() { 58168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int i; 59168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (mPath) 60168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mPath); 61168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (mSubsystem) 62168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mSubsystem); 63168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat for (i = 0; i < NL_PARAMS_MAX; i++) { 64168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (!mParams[i]) 65168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat break; 66168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat free(mParams[i]); 67168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 68168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 69168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 70d674413ff460afe1da049e54bb7a489132799749San Mehatvoid NetlinkEvent::dump() { 71d674413ff460afe1da049e54bb7a489132799749San Mehat int i; 72d674413ff460afe1da049e54bb7a489132799749San Mehat 73d674413ff460afe1da049e54bb7a489132799749San Mehat for (i = 0; i < NL_PARAMS_MAX; i++) { 74d674413ff460afe1da049e54bb7a489132799749San Mehat if (!mParams[i]) 75d674413ff460afe1da049e54bb7a489132799749San Mehat break; 767e8529a8b528fd30586aa037f15a31b29582c537San Mehat SLOGD("NL param '%s'\n", mParams[i]); 77d674413ff460afe1da049e54bb7a489132799749San Mehat } 78d674413ff460afe1da049e54bb7a489132799749San Mehat} 79d674413ff460afe1da049e54bb7a489132799749San Mehat 80ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/* 819b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Returns the message name for a message in the NETLINK_ROUTE family, or NULL 829b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * if parsing that message is not supported. 839b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti */ 849b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittistatic const char *rtMessageName(int type) { 859b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm; 869b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti switch (type) { 879b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_NEWLINK); 889b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_DELLINK); 899b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_NEWADDR); 909b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_DELADDR); 919b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_NEWROUTE); 929b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_DELROUTE); 939b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT); 949a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT); 959a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET); 969b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti default: 979b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return NULL; 989b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 999b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti#undef NL_EVENT_RTM_NAME 1009b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti} 1019b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1029b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti/* 1039b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Checks that a binary NETLINK_ROUTE message is long enough for a payload of 1049b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * size bytes. 1059b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti */ 1069b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittistatic bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) { 1079b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (nh->nlmsg_len < NLMSG_LENGTH(size)) { 1089b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type)); 1099b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 1109b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 1119b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 1129b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti} 1139b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1149b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti/* 1159b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Utility function to log errors. 1169b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti */ 1179b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittistatic bool maybeLogDuplicateAttribute(bool isDup, 1189b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti const char *attributeName, 1199b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti const char *messageName) { 1209b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (isDup) { 1219b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName); 1229b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 1239b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 1249b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 1259b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti} 1269b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1279b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti/* 1289b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Parse a RTM_NEWLINK message. 129381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti */ 1309b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittibool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) { 1319b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh); 1329b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (!checkRtNetlinkLength(nh, sizeof(*ifi))) 1339b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 1349b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1359b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) { 1369b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 1379b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 1389b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1399b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti int len = IFLA_PAYLOAD(nh); 14096834569343f38dc006492fccdf6dad68521b005Lorenzo Colitti struct rtattr *rta; 1419b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 1429b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti switch(rta->rta_type) { 1439b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti case IFLA_IFNAME: 1449b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta)); 145e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp : 146e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey Action::kLinkDown; 1479b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti mSubsystem = strdup("net"); 1489b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 1499b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 1509b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 1519b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1529b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 1539b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti} 1549b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1559b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti/* 1569b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Parse a RTM_NEWADDR or RTM_DELADDR message. 1579b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti */ 1589b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittibool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) { 1599b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh); 160381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti struct ifa_cacheinfo *cacheinfo = NULL; 161381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti char addrstr[INET6_ADDRSTRLEN] = ""; 162ef6454d3d3e54730de1a5b751d6c7b286d5a8575Lorenzo Colitti char ifname[IFNAMSIZ] = ""; 1639b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 1649b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (!checkRtNetlinkLength(nh, sizeof(*ifaddr))) 1659b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 166381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 167381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // Sanity check. 1689b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti int type = nh->nlmsg_type; 169381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (type != RTM_NEWADDR && type != RTM_DELADDR) { 170381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type); 171381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti return false; 172381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 173381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 174381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // For log messages. 1759b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti const char *msgtype = rtMessageName(type); 176381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 1779b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti struct rtattr *rta; 1789b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti int len = IFA_PAYLOAD(nh); 1799b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 180381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (rta->rta_type == IFA_ADDRESS) { 181381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // Only look at the first address, because we only support notifying 182381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // one change at a time. 1839b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype)) 184381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 185381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 186381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // Convert the IP address to a string. 187381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (ifaddr->ifa_family == AF_INET) { 188381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta); 189381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { 19080f63d4b2c45bd609cbda78bcd016baf0138a5d3Mark Salyzyn SLOGE("Short IPv4 address (%zu bytes) in %s", 191381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti RTA_PAYLOAD(rta), msgtype); 192381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 193381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 194381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); 195381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } else if (ifaddr->ifa_family == AF_INET6) { 196381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta); 197381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { 19880f63d4b2c45bd609cbda78bcd016baf0138a5d3Mark Salyzyn SLOGE("Short IPv6 address (%zu bytes) in %s", 199381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti RTA_PAYLOAD(rta), msgtype); 200381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 201381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 202381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); 203381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } else { 204381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti SLOGE("Unknown address family %d\n", ifaddr->ifa_family); 205381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 206381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 207381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 208381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // Find the interface name. 209381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (!if_indextoname(ifaddr->ifa_index, ifname)) { 210ef6454d3d3e54730de1a5b751d6c7b286d5a8575Lorenzo Colitti SLOGD("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype); 211381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 212381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 213381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } else if (rta->rta_type == IFA_CACHEINFO) { 214381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti // Address lifetime information. 2159b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype)) 216381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 217381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 218381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { 21980f63d4b2c45bd609cbda78bcd016baf0138a5d3Mark Salyzyn SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s", 220381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); 221381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti continue; 222381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 223381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 224381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta); 225381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 226381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 227381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 228381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti if (addrstr[0] == '\0') { 229381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti SLOGE("No IFA_ADDRESS in %s\n", msgtype); 230381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti return false; 231381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } 232381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 2339b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti // Fill in netlink event information. 234e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated : 235e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey Action::kAddressRemoved; 2369b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti mSubsystem = strdup("net"); 237ef6454d3d3e54730de1a5b751d6c7b286d5a8575Lorenzo Colitti asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen); 2389b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[1], "INTERFACE=%s", ifname); 2399b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags); 2409b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope); 2419b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 2429b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (cacheinfo) { 2439b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered); 2449b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid); 2459b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp); 2469b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp); 2479b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 2489b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 2499b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 2509b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti} 2519b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 2529b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti/* 2539b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Parse a QLOG_NL_EVENT message. 2549b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti */ 2559b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittibool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) { 2569b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti const char *devname; 2579b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh); 2589b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (!checkRtNetlinkLength(nh, sizeof(*pm))) 2599b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 2609b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 2619b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name; 2629b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix); 2639b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti asprintf(&mParams[1], "INTERFACE=%s", devname); 2649b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti mSubsystem = strdup("qlog"); 265e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kChange; 266381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti return true; 267381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti} 268381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti 269381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti/* 2709a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey * Parse a LOCAL_NFLOG_PACKET message. 2719a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey */ 2729a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkeybool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) { 2739a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey int uid = -1; 2749a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey int len = 0; 2759a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey char* raw = NULL; 2769a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 2779a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID); 2789a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey if (uid_attr) { 2799a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey uid = ntohl(nla_get_u32(uid_attr)); 2809a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey } 2819a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 2829a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); 2839a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey if (payload) { 2849a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey /* First 256 bytes is plenty */ 2859a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey len = nla_len(payload); 2869a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey if (len > 256) len = 256; 2879a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey raw = (char*) nla_data(payload); 2889a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey } 2899a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 2909a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey char* hex = (char*) calloc(1, 5 + (len * 2)); 2919a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey strcpy(hex, "HEX="); 2929a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey for (int i = 0; i < len; i++) { 2939a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf]; 2949a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf]; 2959a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey } 2969a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 2979a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey asprintf(&mParams[0], "UID=%d", uid); 2989a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey mParams[1] = hex; 2999a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey mSubsystem = strdup("strict"); 300e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kChange; 3019a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey return true; 3029a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey} 3039a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 3049a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey/* 305d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti * Parse a RTM_NEWROUTE or RTM_DELROUTE message. 306d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti */ 307d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colittibool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) { 308d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti uint8_t type = nh->nlmsg_type; 309d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti const char *msgname = rtMessageName(type); 310d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 311d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // Sanity check. 312d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { 313d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname); 314d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 315d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 316d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 317d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh); 318d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!checkRtNetlinkLength(nh, sizeof(*rtm))) 319d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 320d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 321d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (// Ignore static routes we've set up ourselves. 322d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti (rtm->rtm_protocol != RTPROT_KERNEL && 323d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti rtm->rtm_protocol != RTPROT_RA) || 324d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // We're only interested in global unicast routes. 325d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti (rtm->rtm_scope != RT_SCOPE_UNIVERSE) || 326d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti (rtm->rtm_type != RTN_UNICAST) || 327d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // We don't support source routing. 328d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti (rtm->rtm_src_len != 0) || 329d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // Cloned routes aren't real routes. 330d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti (rtm->rtm_flags & RTM_F_CLONED)) { 331d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 332d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 333d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 334d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti int family = rtm->rtm_family; 335d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti int prefixLength = rtm->rtm_dst_len; 336d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 337d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // Currently we only support: destination, (one) next hop, ifindex. 338d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti char dst[INET6_ADDRSTRLEN] = ""; 339d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti char gw[INET6_ADDRSTRLEN] = ""; 340d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti char dev[IFNAMSIZ] = ""; 341d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 342d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti size_t len = RTM_PAYLOAD(nh); 343d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti struct rtattr *rta; 344d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 345d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti switch (rta->rta_type) { 346d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti case RTA_DST: 347d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname)) 348d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 349d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst))) 350d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 351d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 352d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti case RTA_GATEWAY: 353d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname)) 354d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 355d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw))) 356d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 357d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 358d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti case RTA_OIF: 359d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname)) 360d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 361d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!if_indextoname(* (int *) RTA_DATA(rta), dev)) 362d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 363d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti default: 364d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti continue; 365d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 366d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 367d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 368d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // If there's no RTA_DST attribute, then: 369d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // - If the prefix length is zero, it's the default route. 370d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // - If the prefix length is nonzero, there's something we don't understand. 371d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // Ignore the event. 372d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!*dst && !prefixLength) { 373d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (family == AF_INET) { 374d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti strncpy(dst, "0.0.0.0", sizeof(dst)); 375d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } else if (family == AF_INET6) { 376d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti strncpy(dst, "::", sizeof(dst)); 377d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 378d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } 379d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 380d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // A useful route must have a destination and at least either a gateway or 381d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // an interface. 382d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (!*dst || (!*gw && !*dev)) 383d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return false; 384d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 385d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti // Fill in netlink event information. 386e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated : 387e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey Action::kRouteRemoved; 388d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti mSubsystem = strdup("net"); 389d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength); 390d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : ""); 391d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : ""); 392d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 393d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return true; 394d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti} 395d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 396d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti/* 397c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti * Parse a RTM_NEWNDUSEROPT message. 398c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti */ 3999b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colittibool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) { 4009b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh); 4019b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (!checkRtNetlinkLength(nh, sizeof(*msg))) 4029b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 4039b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti 404c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Check the length is valid. 4059b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti int len = NLMSG_PAYLOAD(nh, sizeof(*msg)); 406c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (msg->nduseropt_opts_len > len) { 407c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n", 408c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti msg->nduseropt_opts_len, len); 409c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 410c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 411c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti len = msg->nduseropt_opts_len; 412c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 413c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Check address family and packet type. 414c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (msg->nduseropt_family != AF_INET6) { 415c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n", 416c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti msg->nduseropt_family); 417c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 418c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 419c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 420c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT || 421c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti msg->nduseropt_icmp_code != 0) { 422c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n", 423c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti msg->nduseropt_icmp_type, msg->nduseropt_icmp_code); 424c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 425c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 426c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 427c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Find the interface name. 4289b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti char ifname[IFNAMSIZ]; 429c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (!if_indextoname(msg->nduseropt_ifindex, ifname)) { 430c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n", 431c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti msg->nduseropt_ifindex); 432c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 433c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 434c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 435c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // The kernel sends a separate netlink message for each ND option in the RA. 436c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // So only parse the first ND option in the message. 437c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1); 438c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 439c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // The length is in multiples of 8 octets. 440c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti uint16_t optlen = opthdr->nd_opt_len; 441c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (optlen * 8 > len) { 442c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("Invalid option length %d > %d for ND option %d\n", 443c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti optlen * 8, len, opthdr->nd_opt_type); 444c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 445c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 446c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 447c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (opthdr->nd_opt_type == ND_OPT_RDNSS) { 448c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // DNS Servers (RFC 6106). 449c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Each address takes up 2*8 octets, and the header takes up 8 octets. 450c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // So for a valid option with one or more addresses, optlen must be 451c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // odd and greater than 1. 452c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if ((optlen < 3) || !(optlen & 0x1)) { 453c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("Invalid optlen %d for RDNSS option\n", optlen); 454c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 455c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 456ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline const int numaddrs = (optlen - 1) / 2; 457c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 458c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Find the lifetime. 459c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr; 460ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime); 461c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 462c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti // Construct "SERVERS=<comma-separated string of DNS addresses>". 463c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti static const char kServerTag[] = "SERVERS="; 464cc451785fe4426566f6c4a6a5156d4fb40bcc22dErik Kline static const size_t kTagLength = strlen(kServerTag); 465ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline // Reserve sufficient space for an IPv6 link-local address: all but the 466ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline // last address are followed by ','; the last is followed by '\0'. 467cc451785fe4426566f6c4a6a5156d4fb40bcc22dErik Kline static const size_t kMaxSingleAddressLength = 468ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(","); 469cc451785fe4426566f6c4a6a5156d4fb40bcc22dErik Kline const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength; 470c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti char *buf = (char *) malloc(bufsize); 471c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (!buf) { 472c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGE("RDNSS option: out of memory\n"); 473c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 474c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 475c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti strcpy(buf, kServerTag); 476cc451785fe4426566f6c4a6a5156d4fb40bcc22dErik Kline size_t pos = kTagLength; 477c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 478c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1); 479c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti for (int i = 0; i < numaddrs; i++) { 480c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti if (i > 0) { 481c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti buf[pos++] = ','; 482c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 483c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos); 484c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti pos += strlen(buf + pos); 485ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) { 486ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline buf[pos++] = '%'; 487ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline pos += strlcpy(buf + pos, ifname, bufsize - pos); 488ba48ff7a5975ab9b90d2c98293dd2424baf52924Erik Kline } 489c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 490c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti buf[pos] = '\0'; 491c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 492e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kRdnss; 493c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti mSubsystem = strdup("net"); 494c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti asprintf(&mParams[0], "INTERFACE=%s", ifname); 495c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti asprintf(&mParams[1], "LIFETIME=%u", lifetime); 496c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti mParams[2] = buf; 497c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } else { 498c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type); 499c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return false; 500c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } 501c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 502c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti return true; 503c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti} 504c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 505c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti/* 506c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti * Parse a binary message from a NETLINK_ROUTE netlink socket. 5079b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * 5089b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * Note that this function can only parse one message, because the message's 5099b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * content has to be stored in the class's member variables (mAction, 5109b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if 5119b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * there are multiple valid messages in the buffer, only the first one will be 5129b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * returned. 5139b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * 5149b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti * TODO: consider only ever looking at the first message. 515ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */ 516ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { 5179a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey struct nlmsghdr *nh; 518ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 51996834569343f38dc006492fccdf6dad68521b005Lorenzo Colitti for (nh = (struct nlmsghdr *) buffer; 520c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); 52196834569343f38dc006492fccdf6dad68521b005Lorenzo Colitti nh = NLMSG_NEXT(nh, size)) { 522e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall 5239b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (!rtMessageName(nh->nlmsg_type)) { 5249b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type); 5259b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti continue; 5269b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti } 527e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall 5289b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (nh->nlmsg_type == RTM_NEWLINK) { 5299b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (parseIfInfoMessage(nh)) 5309b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 531ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 5329a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) { 5339b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (parseUlogPacketMessage(nh)) 5349b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 535e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall 536381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti } else if (nh->nlmsg_type == RTM_NEWADDR || 537381f70f52a282e6da780e4b686aaa9c230be2cdcLorenzo Colitti nh->nlmsg_type == RTM_DELADDR) { 5389b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (parseIfAddrMessage(nh)) 5399b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 540c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 541d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti } else if (nh->nlmsg_type == RTM_NEWROUTE || 542d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti nh->nlmsg_type == RTM_DELROUTE) { 543d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti if (parseRtMessage(nh)) 544d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti return true; 545d7ff7ea65220718398cae1e1aa0005072229b4e7Lorenzo Colitti 546c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) { 5479b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti if (parseNdUserOptMessage(nh)) 5489b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return true; 549c7eec83f08329a2a0008ba939c07dd1dc7d9b7ffLorenzo Colitti 5509a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) { 5519a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey if (parseNfPacketMessage(nh)) 5529a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey return true; 5539a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey 554e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall } 555ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen } 556ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 5579b34293566833ead1d7bac7518e5ccad0d92d61cLorenzo Colitti return false; 558ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen} 559ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 5603311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* If the string between 'str' and 'end' begins with 'prefixlen' characters 5613311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * from the 'prefix' array, then return 'str + prefixlen', otherwise return 5623311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * NULL. 5633311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner */ 5643311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerstatic const char* 5653311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerhas_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) 5663311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner{ 5673311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen)) 5683311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return str + prefixlen; 5693311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner else 5703311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return NULL; 5713311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner} 5723311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 5733311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Same as strlen(x) for constant string literals ONLY */ 5743311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define CONST_STRLEN(x) (sizeof(x)-1) 5753311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 5763311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Convenience macro to call has_prefix with a constant string literal */ 5773311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) 5783311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 5793311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 580ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/* 581ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT 582ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * netlink socket. 583ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */ 584ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { 58517260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen const char *s = buffer; 58617260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen const char *end; 587168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int param_idx = 0; 588168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat int first = 1; 589168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 5903311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if (size == 0) 5913311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return false; 5923311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 5933311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner /* Ensure the buffer is zero-terminated, the code below depends on this */ 5943311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner buffer[size-1] = '\0'; 5953311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner 596168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat end = s + size; 597168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat while (s < end) { 598168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (first) { 5993311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner const char *p; 6003311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner /* buffer is 0-terminated, no need to check p < end */ 6013311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner for (p = s; *p != '@'; p++) { 6023311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if (!*p) { /* no '@', should not happen */ 6033311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner return false; 6043311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 6053311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 6063311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mPath = strdup(p+1); 607168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat first = 0; 608168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } else { 6093311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner const char* a; 6103311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { 611168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat if (!strcmp(a, "add")) 612e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kAdd; 613168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat else if (!strcmp(a, "remove")) 614e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kRemove; 615168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat else if (!strcmp(a, "change")) 616e4f394087d2073dbe8309e5a2d87127cfda66ff9Jeff Sharkey mAction = Action::kChange; 6173311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { 6183311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mSeq = atoi(a); 6193311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { 6203311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner mSubsystem = strdup(a); 6213311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } else if (param_idx < NL_PARAMS_MAX) { 622168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat mParams[param_idx++] = strdup(s); 6233311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner } 624168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 6253311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner s += strlen(s) + 1; 626168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 627168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat return true; 628168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 629168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 630ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::decode(char *buffer, int size, int format) { 6319a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey if (format == NetlinkListener::NETLINK_FORMAT_BINARY 6329a20e67fa62c1e0e0080910deec4be82ebecc922Jeff Sharkey || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) { 63317260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen return parseBinaryNetlinkMessage(buffer, size); 63417260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen } else { 63517260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen return parseAsciiNetlinkMessage(buffer, size); 63617260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen } 637ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen} 638ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen 639168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst char *NetlinkEvent::findParam(const char *paramName) { 64080ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang size_t len = strlen(paramName); 6413311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { 64280ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang const char *ptr = mParams[i] + len; 64380ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang if (!strncmp(mParams[i], paramName, len) && *ptr == '=') 64480ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang return ++ptr; 645168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat } 646168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat 6477e8529a8b528fd30586aa037f15a31b29582c537San Mehat SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); 648168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat return NULL; 649168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat} 650