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