1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdarg.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21#include <errno.h> 22 23#define LOG_TAG "Netd" 24 25#include <cutils/log.h> 26 27#include <netutils/ifc.h> 28#include <sysutils/NetlinkEvent.h> 29#include "NetlinkHandler.h" 30#include "NetlinkManager.h" 31#include "ResponseCode.h" 32 33static const char *kUpdated = "updated"; 34static const char *kRemoved = "removed"; 35 36NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket, 37 int format) : 38 NetlinkListener(listenerSocket, format) { 39 mNm = nm; 40} 41 42NetlinkHandler::~NetlinkHandler() { 43} 44 45int NetlinkHandler::start() { 46 return this->startListener(); 47} 48 49int NetlinkHandler::stop() { 50 return this->stopListener(); 51} 52 53void NetlinkHandler::onEvent(NetlinkEvent *evt) { 54 const char *subsys = evt->getSubsystem(); 55 if (!subsys) { 56 ALOGW("No subsystem found in netlink event"); 57 return; 58 } 59 60 if (!strcmp(subsys, "net")) { 61 NetlinkEvent::Action action = evt->getAction(); 62 const char *iface = evt->findParam("INTERFACE"); 63 64 if (action == NetlinkEvent::Action::kAdd) { 65 notifyInterfaceAdded(iface); 66 } else if (action == NetlinkEvent::Action::kRemove) { 67 notifyInterfaceRemoved(iface); 68 } else if (action == NetlinkEvent::Action::kChange) { 69 evt->dump(); 70 notifyInterfaceChanged("nana", true); 71 } else if (action == NetlinkEvent::Action::kLinkUp) { 72 notifyInterfaceLinkChanged(iface, true); 73 } else if (action == NetlinkEvent::Action::kLinkDown) { 74 notifyInterfaceLinkChanged(iface, false); 75 } else if (action == NetlinkEvent::Action::kAddressUpdated || 76 action == NetlinkEvent::Action::kAddressRemoved) { 77 const char *address = evt->findParam("ADDRESS"); 78 const char *flags = evt->findParam("FLAGS"); 79 const char *scope = evt->findParam("SCOPE"); 80 if (action == NetlinkEvent::Action::kAddressRemoved && iface && address) { 81 int resetMask = strchr(address, ':') ? RESET_IPV6_ADDRESSES : RESET_IPV4_ADDRESSES; 82 resetMask |= RESET_IGNORE_INTERFACE_ADDRESS; 83 if (int ret = ifc_reset_connections(iface, resetMask)) { 84 ALOGE("ifc_reset_connections failed on iface %s for address %s (%s)", iface, 85 address, strerror(ret)); 86 } 87 } 88 if (iface && flags && scope) { 89 notifyAddressChanged(action, address, iface, flags, scope); 90 } 91 } else if (action == NetlinkEvent::Action::kRdnss) { 92 const char *lifetime = evt->findParam("LIFETIME"); 93 const char *servers = evt->findParam("SERVERS"); 94 if (lifetime && servers) { 95 notifyInterfaceDnsServers(iface, lifetime, servers); 96 } 97 } else if (action == NetlinkEvent::Action::kRouteUpdated || 98 action == NetlinkEvent::Action::kRouteRemoved) { 99 const char *route = evt->findParam("ROUTE"); 100 const char *gateway = evt->findParam("GATEWAY"); 101 const char *iface = evt->findParam("INTERFACE"); 102 if (route && (gateway || iface)) { 103 notifyRouteChange(action, route, gateway, iface); 104 } 105 } 106 107 } else if (!strcmp(subsys, "qlog")) { 108 const char *alertName = evt->findParam("ALERT_NAME"); 109 const char *iface = evt->findParam("INTERFACE"); 110 notifyQuotaLimitReached(alertName, iface); 111 112 } else if (!strcmp(subsys, "strict")) { 113 const char *uid = evt->findParam("UID"); 114 const char *hex = evt->findParam("HEX"); 115 notifyStrictCleartext(uid, hex); 116 117 } else if (!strcmp(subsys, "xt_idletimer")) { 118 const char *label = evt->findParam("INTERFACE"); 119 const char *state = evt->findParam("STATE"); 120 const char *timestamp = evt->findParam("TIME_NS"); 121 const char *uid = evt->findParam("UID"); 122 if (state) 123 notifyInterfaceClassActivity(label, !strcmp("active", state), 124 timestamp, uid); 125 126#if !LOG_NDEBUG 127 } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) { 128 /* It is not a VSYNC or a backlight event */ 129 ALOGV("unexpected event from subsystem %s", subsys); 130#endif 131 } 132} 133 134void NetlinkHandler::notify(int code, const char *format, ...) { 135 char *msg; 136 va_list args; 137 va_start(args, format); 138 if (vasprintf(&msg, format, args) >= 0) { 139 mNm->getBroadcaster()->sendBroadcast(code, msg, false); 140 free(msg); 141 } else { 142 SLOGE("Failed to send notification: vasprintf: %s", strerror(errno)); 143 } 144 va_end(args); 145} 146 147void NetlinkHandler::notifyInterfaceAdded(const char *name) { 148 notify(ResponseCode::InterfaceChange, "Iface added %s", name); 149} 150 151void NetlinkHandler::notifyInterfaceRemoved(const char *name) { 152 notify(ResponseCode::InterfaceChange, "Iface removed %s", name); 153} 154 155void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) { 156 notify(ResponseCode::InterfaceChange, 157 "Iface changed %s %s", name, (isUp ? "up" : "down")); 158} 159 160void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) { 161 notify(ResponseCode::InterfaceChange, 162 "Iface linkstate %s %s", name, (isUp ? "up" : "down")); 163} 164 165void NetlinkHandler::notifyQuotaLimitReached(const char *name, const char *iface) { 166 notify(ResponseCode::BandwidthControl, "limit alert %s %s", name, iface); 167} 168 169void NetlinkHandler::notifyInterfaceClassActivity(const char *name, 170 bool isActive, 171 const char *timestamp, 172 const char *uid) { 173 if (timestamp == NULL) 174 notify(ResponseCode::InterfaceClassActivity, 175 "IfaceClass %s %s", isActive ? "active" : "idle", name); 176 else if (uid != NULL && isActive) 177 notify(ResponseCode::InterfaceClassActivity, 178 "IfaceClass active %s %s %s", name, timestamp, uid); 179 else 180 notify(ResponseCode::InterfaceClassActivity, 181 "IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp); 182} 183 184void NetlinkHandler::notifyAddressChanged(NetlinkEvent::Action action, const char *addr, 185 const char *iface, const char *flags, 186 const char *scope) { 187 notify(ResponseCode::InterfaceAddressChange, 188 "Address %s %s %s %s %s", 189 (action == NetlinkEvent::Action::kAddressUpdated) ? kUpdated : kRemoved, 190 addr, iface, flags, scope); 191} 192 193void NetlinkHandler::notifyInterfaceDnsServers(const char *iface, 194 const char *lifetime, 195 const char *servers) { 196 notify(ResponseCode::InterfaceDnsInfo, "DnsInfo servers %s %s %s", 197 iface, lifetime, servers); 198} 199 200void NetlinkHandler::notifyRouteChange(NetlinkEvent::Action action, const char *route, 201 const char *gateway, const char *iface) { 202 notify(ResponseCode::RouteChange, 203 "Route %s %s%s%s%s%s", 204 (action == NetlinkEvent::Action::kRouteUpdated) ? kUpdated : kRemoved, 205 route, 206 *gateway ? " via " : "", 207 gateway, 208 *iface ? " dev " : "", 209 iface); 210} 211 212void NetlinkHandler::notifyStrictCleartext(const char* uid, const char* hex) { 213 notify(ResponseCode::StrictCleartext, "%s %s", uid, hex); 214} 215