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