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>
26a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti#include <netinet/in.h>
27a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti#include <arpa/inet.h>
28a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti#include <net/if.h>
29a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
30ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen#include <linux/if.h>
31e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netfilter/nfnetlink.h>
32e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netfilter_ipv4/ipt_ULOG.h>
33e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall/* From kernel's net/netfilter/xt_quota2.c */
34e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrallconst int QLOG_NL_EVENT  = 112;
35e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
36e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/netlink.h>
37e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall#include <linux/rtnetlink.h>
38ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
39168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionUnknown = 0;
40168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionAdd = 1;
41168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionRemove = 2;
42168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst int NetlinkEvent::NlActionChange = 3;
43ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenconst int NetlinkEvent::NlActionLinkUp = 4;
44ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenconst int NetlinkEvent::NlActionLinkDown = 5;
45f34861346d5c207912075fba9874090e4c947869Lorenzo Colitticonst int NetlinkEvent::NlActionAddressUpdated = 6;
46f34861346d5c207912075fba9874090e4c947869Lorenzo Colitticonst int NetlinkEvent::NlActionAddressRemoved = 7;
47168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
48168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::NetlinkEvent() {
49168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    mAction = NlActionUnknown;
50ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat    memset(mParams, 0, sizeof(mParams));
51ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat    mPath = NULL;
52ebfe3db361c51d9d99bf6cfd495bd16bdf815e1fSan Mehat    mSubsystem = NULL;
53168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
54168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
55168415b822cae1f8b54ef09c41c11a9b97b87f40San MehatNetlinkEvent::~NetlinkEvent() {
56168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int i;
57168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    if (mPath)
58168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        free(mPath);
59168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    if (mSubsystem)
60168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        free(mSubsystem);
61168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    for (i = 0; i < NL_PARAMS_MAX; i++) {
62168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        if (!mParams[i])
63168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat            break;
64168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        free(mParams[i]);
65168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    }
66168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
67168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
68d674413ff460afe1da049e54bb7a489132799749San Mehatvoid NetlinkEvent::dump() {
69d674413ff460afe1da049e54bb7a489132799749San Mehat    int i;
70d674413ff460afe1da049e54bb7a489132799749San Mehat
71d674413ff460afe1da049e54bb7a489132799749San Mehat    for (i = 0; i < NL_PARAMS_MAX; i++) {
72d674413ff460afe1da049e54bb7a489132799749San Mehat        if (!mParams[i])
73d674413ff460afe1da049e54bb7a489132799749San Mehat            break;
747e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGD("NL param '%s'\n", mParams[i]);
75d674413ff460afe1da049e54bb7a489132799749San Mehat    }
76d674413ff460afe1da049e54bb7a489132799749San Mehat}
77d674413ff460afe1da049e54bb7a489132799749San Mehat
78ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/*
79a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti * Decode a RTM_NEWADDR or RTM_DELADDR message.
80a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti */
81a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colittibool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
82a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                                      int rtasize) {
833984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti    struct rtattr *rta;
84a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    struct ifa_cacheinfo *cacheinfo = NULL;
85a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    char addrstr[INET6_ADDRSTRLEN] = "";
86a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
87a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    // Sanity check.
88a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    if (type != RTM_NEWADDR && type != RTM_DELADDR) {
89a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
90a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        return false;
91a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    }
92a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
93a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    // For log messages.
94a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
95a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
963984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
973984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti         rta = RTA_NEXT(rta, rtasize)) {
98a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        if (rta->rta_type == IFA_ADDRESS) {
99a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // Only look at the first address, because we only support notifying
100a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // one change at a time.
101a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (*addrstr != '\0') {
102a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
103a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
104a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
105a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
106a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // Convert the IP address to a string.
107a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (ifaddr->ifa_family == AF_INET) {
108a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
109a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
110a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                    SLOGE("Short IPv4 address (%d bytes) in %s",
111a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                          RTA_PAYLOAD(rta), msgtype);
112a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                    continue;
113a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                }
114a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr));
115a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            } else if (ifaddr->ifa_family == AF_INET6) {
116a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
117a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
118a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                    SLOGE("Short IPv6 address (%d bytes) in %s",
119a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                          RTA_PAYLOAD(rta), msgtype);
120a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                    continue;
121a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                }
122a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr));
123a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            } else {
124a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Unknown address family %d\n", ifaddr->ifa_family);
125a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
126a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
127a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
128a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // Find the interface name.
129a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            char ifname[IFNAMSIZ + 1];
130a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (!if_indextoname(ifaddr->ifa_index, ifname)) {
131a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
132a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                return false;
133a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
134a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
135a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // Fill in interface information.
136f34861346d5c207912075fba9874090e4c947869Lorenzo Colitti            mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
137f34861346d5c207912075fba9874090e4c947869Lorenzo Colitti                                              NlActionAddressRemoved;
138f34861346d5c207912075fba9874090e4c947869Lorenzo Colitti            mSubsystem = strdup("net");
139a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
140a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                     ifaddr->ifa_prefixlen);
141f34861346d5c207912075fba9874090e4c947869Lorenzo Colitti            asprintf(&mParams[1], "INTERFACE=%s", ifname);
142a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
143a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
144a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        } else if (rta->rta_type == IFA_CACHEINFO) {
145a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            // Address lifetime information.
146a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (cacheinfo) {
147a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                // We only support one address.
148a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
149a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
150a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
151a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
152a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
153a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s",
154a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                      RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
155a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
156a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
157a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
158a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
159a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
160a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
161a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
162a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
163a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        }
164a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    }
165a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
166a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    if (addrstr[0] == '\0') {
167a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        SLOGE("No IFA_ADDRESS in %s\n", msgtype);
168a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        return false;
169a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    }
170a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
171a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti    return true;
172a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti}
173a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
174a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti/*
175b982bce73b7e2c824ffb50115ea382fe45c751a4JP Abgrall * Parse an binary message from a NETLINK_ROUTE netlink socket.
176ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */
177ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
1783984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti    const struct nlmsghdr *nh;
179ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
1803984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti    for (nh = (struct nlmsghdr *) buffer;
1813984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti         NLMSG_OK(nh, size) && (nh->nlmsg_type != NLMSG_DONE);
1823984276ce47c965ad02a522280a139e0a0c7e5cfLorenzo Colitti         nh = NLMSG_NEXT(nh, size)) {
183e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
184ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen        if (nh->nlmsg_type == RTM_NEWLINK) {
185ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen            int len = nh->nlmsg_len - sizeof(*nh);
186ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen            struct ifinfomsg *ifi;
187ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
188e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            if (sizeof(*ifi) > (size_t) len) {
189e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                SLOGE("Got a short RTM_NEWLINK message\n");
190e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                continue;
191e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            }
192e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
193e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            ifi = (ifinfomsg *)NLMSG_DATA(nh);
194e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
195e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                continue;
196e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            }
197e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
198e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            struct rtattr *rta = (struct rtattr *)
199e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall              ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
200e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
201e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
202e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            while(RTA_OK(rta, len)) {
203e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                switch(rta->rta_type) {
204e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                case IFLA_IFNAME:
205e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                    char buffer[16 + IFNAMSIZ];
206e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                    snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
207e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                             (char *) RTA_DATA(rta));
208e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                    mParams[0] = strdup(buffer);
209e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                    mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
210e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                      NlActionLinkUp : NlActionLinkDown;
211f34861346d5c207912075fba9874090e4c947869Lorenzo Colitti                    mSubsystem = strdup("net");
212e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                    break;
213ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen                }
214e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
215e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                rta = RTA_NEXT(rta, len);
216ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen            }
217ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
218e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall        } else if (nh->nlmsg_type == QLOG_NL_EVENT) {
219e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            char *devname;
220e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            ulog_packet_msg_t *pm;
221e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            size_t len = nh->nlmsg_len - sizeof(*nh);
222e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            if (sizeof(*pm) > len) {
223e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                SLOGE("Got a short QLOG message\n");
224e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                continue;
225e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            }
226e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
227e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
228e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
229e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            asprintf(&mParams[1], "INTERFACE=%s", devname);
230e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            mSubsystem = strdup("qlog");
231e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall            mAction = NlActionChange;
232e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall
233a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti        } else if (nh->nlmsg_type == RTM_NEWADDR ||
234a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                   nh->nlmsg_type == RTM_DELADDR) {
235a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            int len = nh->nlmsg_len - sizeof(*nh);
236a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            struct ifaddrmsg *ifa;
237a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
238a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (sizeof(*ifa) > (size_t) len) {
239a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                SLOGE("Got a short RTM_xxxADDR message\n");
240a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
241a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
242a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti
243a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            ifa = (ifaddrmsg *)NLMSG_DATA(nh);
244a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            size_t rtasize = IFA_PAYLOAD(nh);
245a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
246a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti                continue;
247a4b4e9ad8e35ab424e61d76ebe6654445fc61e63Lorenzo Colitti            }
248e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall        } else {
249e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall                SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type);
250e6f80149a201e02ddd1e251e0690ad100b688cd6JP Abgrall        }
251ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen    }
252ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
253ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen    return true;
254ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen}
255ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
2563311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* If the string between 'str' and 'end' begins with 'prefixlen' characters
2573311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * from the 'prefix' array, then return 'str + prefixlen', otherwise return
2583311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner * NULL.
2593311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner */
2603311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerstatic const char*
2613311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turnerhas_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
2623311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner{
2633311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
2643311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner        return str + prefixlen;
2653311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    else
2663311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner        return NULL;
2673311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner}
2683311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
2693311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Same as strlen(x) for constant string literals ONLY */
2703311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define CONST_STRLEN(x)  (sizeof(x)-1)
2713311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
2723311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner/* Convenience macro to call has_prefix with a constant string literal  */
2733311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner#define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
2743311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
2753311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
276ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen/*
277ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
278ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen * netlink socket.
279ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen */
280ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
28117260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen    const char *s = buffer;
28217260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen    const char *end;
283168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int param_idx = 0;
284168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int i;
285168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    int first = 1;
286168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
2873311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    if (size == 0)
2883311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner        return false;
2893311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
2903311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    /* Ensure the buffer is zero-terminated, the code below depends on this */
2913311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    buffer[size-1] = '\0';
2923311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner
293168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    end = s + size;
294168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    while (s < end) {
295168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        if (first) {
2963311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            const char *p;
2973311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            /* buffer is 0-terminated, no need to check p < end */
2983311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            for (p = s; *p != '@'; p++) {
2993311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner                if (!*p) { /* no '@', should not happen */
3003311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner                    return false;
3013311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner                }
3023311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            }
3033311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            mPath = strdup(p+1);
304168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat            first = 0;
305168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        } else {
3063311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            const char* a;
3073311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
308168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                if (!strcmp(a, "add"))
309168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                    mAction = NlActionAdd;
310168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                else if (!strcmp(a, "remove"))
311168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                    mAction = NlActionRemove;
312168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                else if (!strcmp(a, "change"))
313168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                    mAction = NlActionChange;
3143311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
3153311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner                mSeq = atoi(a);
3163311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
3173311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner                mSubsystem = strdup(a);
3183311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            } else if (param_idx < NL_PARAMS_MAX) {
319168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat                mParams[param_idx++] = strdup(s);
3203311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner            }
321168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat        }
3223311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner        s += strlen(s) + 1;
323168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    }
324168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    return true;
325168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
326168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
327ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chenbool NetlinkEvent::decode(char *buffer, int size, int format) {
32817260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen    if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
32917260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen        return parseBinaryNetlinkMessage(buffer, size);
33017260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen    } else {
33117260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen        return parseAsciiNetlinkMessage(buffer, size);
33217260b14682d4fe59dad3de2de8c9370e6ba9a71Mike J. Chen    }
333ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen}
334ec16b9d47cacb0d873ee0ff80c919f49215c0005Mike J. Chen
335168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehatconst char *NetlinkEvent::findParam(const char *paramName) {
33680ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang    size_t len = strlen(paramName);
3373311eea1d3881e6f3d6806988b7db3de0a5f68d5David 'Digit' Turner    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
33880ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang        const char *ptr = mParams[i] + len;
33980ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang        if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
34080ec37aa15c138beee5889a257d1241c30a1e8d7Chih-Wei Huang            return ++ptr;
341168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    }
342168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat
3437e8529a8b528fd30586aa037f15a31b29582c537San Mehat    SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
344168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat    return NULL;
345168415b822cae1f8b54ef09c41c11a9b97b87f40San Mehat}
346