Home | History | Annotate | Download | only in server
      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 
     33 static const char *kUpdated = "updated";
     34 static const char *kRemoved = "removed";
     35 
     36 NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket,
     37                                int format) :
     38                         NetlinkListener(listenerSocket, format) {
     39     mNm = nm;
     40 }
     41 
     42 NetlinkHandler::~NetlinkHandler() {
     43 }
     44 
     45 int NetlinkHandler::start() {
     46     return this->startListener();
     47 }
     48 
     49 int NetlinkHandler::stop() {
     50     return this->stopListener();
     51 }
     52 
     53 void 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         int action = evt->getAction();
     62         const char *iface = evt->findParam("INTERFACE");
     63 
     64         if (action == evt->NlActionAdd) {
     65             notifyInterfaceAdded(iface);
     66         } else if (action == evt->NlActionRemove) {
     67             notifyInterfaceRemoved(iface);
     68         } else if (action == evt->NlActionChange) {
     69             evt->dump();
     70             notifyInterfaceChanged("nana", true);
     71         } else if (action == evt->NlActionLinkUp) {
     72             notifyInterfaceLinkChanged(iface, true);
     73         } else if (action == evt->NlActionLinkDown) {
     74             notifyInterfaceLinkChanged(iface, false);
     75         } else if (action == evt->NlActionAddressUpdated ||
     76                    action == evt->NlActionAddressRemoved) {
     77             const char *address = evt->findParam("ADDRESS");
     78             const char *flags = evt->findParam("FLAGS");
     79             const char *scope = evt->findParam("SCOPE");
     80             if (action == evt->NlActionAddressRemoved && 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 == evt->NlActionRdnss) {
     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 == evt->NlActionRouteUpdated ||
     98                    action == evt->NlActionRouteRemoved) {
     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, "xt_idletimer")) {
    113         const char *label = evt->findParam("INTERFACE");
    114         const char *state = evt->findParam("STATE");
    115         const char *timestamp = evt->findParam("TIME_NS");
    116         if (state)
    117             notifyInterfaceClassActivity(label, !strcmp("active", state), timestamp);
    118 
    119 #if !LOG_NDEBUG
    120     } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
    121         /* It is not a VSYNC or a backlight event */
    122         ALOGV("unexpected event from subsystem %s", subsys);
    123 #endif
    124     }
    125 }
    126 
    127 void NetlinkHandler::notify(int code, const char *format, ...) {
    128     char *msg;
    129     va_list args;
    130     va_start(args, format);
    131     if (vasprintf(&msg, format, args) >= 0) {
    132         mNm->getBroadcaster()->sendBroadcast(code, msg, false);
    133         free(msg);
    134     } else {
    135         SLOGE("Failed to send notification: vasprintf: %s", strerror(errno));
    136     }
    137     va_end(args);
    138 }
    139 
    140 void NetlinkHandler::notifyInterfaceAdded(const char *name) {
    141     notify(ResponseCode::InterfaceChange, "Iface added %s", name);
    142 }
    143 
    144 void NetlinkHandler::notifyInterfaceRemoved(const char *name) {
    145     notify(ResponseCode::InterfaceChange, "Iface removed %s", name);
    146 }
    147 
    148 void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) {
    149     notify(ResponseCode::InterfaceChange,
    150            "Iface changed %s %s", name, (isUp ? "up" : "down"));
    151 }
    152 
    153 void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) {
    154     notify(ResponseCode::InterfaceChange,
    155            "Iface linkstate %s %s", name, (isUp ? "up" : "down"));
    156 }
    157 
    158 void NetlinkHandler::notifyQuotaLimitReached(const char *name, const char *iface) {
    159     notify(ResponseCode::BandwidthControl, "limit alert %s %s", name, iface);
    160 }
    161 
    162 void NetlinkHandler::notifyInterfaceClassActivity(const char *name,
    163                                                   bool isActive, const char *timestamp) {
    164     if (timestamp == NULL)
    165         notify(ResponseCode::InterfaceClassActivity,
    166            "IfaceClass %s %s", isActive ? "active" : "idle", name);
    167     else
    168         notify(ResponseCode::InterfaceClassActivity,
    169            "IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp);
    170 }
    171 
    172 void NetlinkHandler::notifyAddressChanged(int action, const char *addr,
    173                                           const char *iface, const char *flags,
    174                                           const char *scope) {
    175     notify(ResponseCode::InterfaceAddressChange,
    176            "Address %s %s %s %s %s",
    177            (action == NetlinkEvent::NlActionAddressUpdated) ? kUpdated : kRemoved,
    178            addr, iface, flags, scope);
    179 }
    180 
    181 void NetlinkHandler::notifyInterfaceDnsServers(const char *iface,
    182                                                const char *lifetime,
    183                                                const char *servers) {
    184     notify(ResponseCode::InterfaceDnsInfo, "DnsInfo servers %s %s %s",
    185            iface, lifetime, servers);
    186 }
    187 
    188 void NetlinkHandler::notifyRouteChange(int action, const char *route,
    189                                        const char *gateway, const char *iface) {
    190     notify(ResponseCode::RouteChange,
    191            "Route %s %s%s%s%s%s",
    192            (action == NetlinkEvent::NlActionRouteUpdated) ? kUpdated : kRemoved,
    193            route,
    194            *gateway ? " via " : "",
    195            gateway,
    196            *iface ? " dev " : "",
    197            iface);
    198 }
    199