Home | History | Annotate | Download | only in src
      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 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #define LOG_TAG "NetlinkEvent"
     20 #include <cutils/log.h>
     21 
     22 #include <sysutils/NetlinkEvent.h>
     23 
     24 #include <sys/types.h>
     25 #include <sys/socket.h>
     26 #include <netinet/in.h>
     27 #include <netinet/icmp6.h>
     28 #include <arpa/inet.h>
     29 #include <net/if.h>
     30 
     31 #include <linux/if.h>
     32 #include <linux/if_addr.h>
     33 #include <linux/if_link.h>
     34 #include <linux/netfilter/nfnetlink.h>
     35 #include <linux/netfilter/nfnetlink_log.h>
     36 #include <linux/netfilter_ipv4/ipt_ULOG.h>
     37 
     38 /* From kernel's net/netfilter/xt_quota2.c */
     39 const int LOCAL_QLOG_NL_EVENT = 112;
     40 const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
     41 
     42 #include <linux/netlink.h>
     43 #include <linux/rtnetlink.h>
     44 
     45 #include <netlink/attr.h>
     46 #include <netlink/genl/genl.h>
     47 #include <netlink/handlers.h>
     48 #include <netlink/msg.h>
     49 
     50 NetlinkEvent::NetlinkEvent() {
     51     mAction = Action::kUnknown;
     52     memset(mParams, 0, sizeof(mParams));
     53     mPath = NULL;
     54     mSubsystem = NULL;
     55 }
     56 
     57 NetlinkEvent::~NetlinkEvent() {
     58     int i;
     59     if (mPath)
     60         free(mPath);
     61     if (mSubsystem)
     62         free(mSubsystem);
     63     for (i = 0; i < NL_PARAMS_MAX; i++) {
     64         if (!mParams[i])
     65             break;
     66         free(mParams[i]);
     67     }
     68 }
     69 
     70 void NetlinkEvent::dump() {
     71     int i;
     72 
     73     for (i = 0; i < NL_PARAMS_MAX; i++) {
     74         if (!mParams[i])
     75             break;
     76         SLOGD("NL param '%s'\n", mParams[i]);
     77     }
     78 }
     79 
     80 /*
     81  * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
     82  * if parsing that message is not supported.
     83  */
     84 static const char *rtMessageName(int type) {
     85 #define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
     86     switch (type) {
     87         NL_EVENT_RTM_NAME(RTM_NEWLINK);
     88         NL_EVENT_RTM_NAME(RTM_DELLINK);
     89         NL_EVENT_RTM_NAME(RTM_NEWADDR);
     90         NL_EVENT_RTM_NAME(RTM_DELADDR);
     91         NL_EVENT_RTM_NAME(RTM_NEWROUTE);
     92         NL_EVENT_RTM_NAME(RTM_DELROUTE);
     93         NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
     94         NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
     95         NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
     96         default:
     97             return NULL;
     98     }
     99 #undef NL_EVENT_RTM_NAME
    100 }
    101 
    102 /*
    103  * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
    104  * size bytes.
    105  */
    106 static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
    107     if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
    108         SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
    109         return false;
    110     }
    111     return true;
    112 }
    113 
    114 /*
    115  * Utility function to log errors.
    116  */
    117 static bool maybeLogDuplicateAttribute(bool isDup,
    118                                        const char *attributeName,
    119                                        const char *messageName) {
    120     if (isDup) {
    121         SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
    122         return true;
    123     }
    124     return false;
    125 }
    126 
    127 /*
    128  * Parse a RTM_NEWLINK message.
    129  */
    130 bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
    131     struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
    132     if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
    133         return false;
    134 
    135     if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
    136         return false;
    137     }
    138 
    139     int len = IFLA_PAYLOAD(nh);
    140     struct rtattr *rta;
    141     for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
    142         switch(rta->rta_type) {
    143             case IFLA_IFNAME:
    144                 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
    145                 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp :
    146                                                             Action::kLinkDown;
    147                 mSubsystem = strdup("net");
    148                 return true;
    149         }
    150     }
    151 
    152     return false;
    153 }
    154 
    155 /*
    156  * Parse a RTM_NEWADDR or RTM_DELADDR message.
    157  */
    158 bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
    159     struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
    160     struct ifa_cacheinfo *cacheinfo = NULL;
    161     char addrstr[INET6_ADDRSTRLEN] = "";
    162     char ifname[IFNAMSIZ] = "";
    163 
    164     if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
    165         return false;
    166 
    167     // Sanity check.
    168     int type = nh->nlmsg_type;
    169     if (type != RTM_NEWADDR && type != RTM_DELADDR) {
    170         SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
    171         return false;
    172     }
    173 
    174     // For log messages.
    175     const char *msgtype = rtMessageName(type);
    176 
    177     struct rtattr *rta;
    178     int len = IFA_PAYLOAD(nh);
    179     for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
    180         if (rta->rta_type == IFA_ADDRESS) {
    181             // Only look at the first address, because we only support notifying
    182             // one change at a time.
    183             if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
    184                 continue;
    185 
    186             // Convert the IP address to a string.
    187             if (ifaddr->ifa_family == AF_INET) {
    188                 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
    189                 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
    190                     SLOGE("Short IPv4 address (%zu bytes) in %s",
    191                           RTA_PAYLOAD(rta), msgtype);
    192                     continue;
    193                 }
    194                 inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr));
    195             } else if (ifaddr->ifa_family == AF_INET6) {
    196                 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
    197                 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
    198                     SLOGE("Short IPv6 address (%zu bytes) in %s",
    199                           RTA_PAYLOAD(rta), msgtype);
    200                     continue;
    201                 }
    202                 inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr));
    203             } else {
    204                 SLOGE("Unknown address family %d\n", ifaddr->ifa_family);
    205                 continue;
    206             }
    207 
    208             // Find the interface name.
    209             if (!if_indextoname(ifaddr->ifa_index, ifname)) {
    210                 SLOGD("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
    211             }
    212 
    213         } else if (rta->rta_type == IFA_CACHEINFO) {
    214             // Address lifetime information.
    215             if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
    216                 continue;
    217 
    218             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
    219                 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
    220                       RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
    221                 continue;
    222             }
    223 
    224             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
    225         }
    226     }
    227 
    228     if (addrstr[0] == '\0') {
    229         SLOGE("No IFA_ADDRESS in %s\n", msgtype);
    230         return false;
    231     }
    232 
    233     // Fill in netlink event information.
    234     mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
    235                                       Action::kAddressRemoved;
    236     mSubsystem = strdup("net");
    237     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
    238     asprintf(&mParams[1], "INTERFACE=%s", ifname);
    239     asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
    240     asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
    241 
    242     if (cacheinfo) {
    243         asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
    244         asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
    245         asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
    246         asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
    247     }
    248 
    249     return true;
    250 }
    251 
    252 /*
    253  * Parse a QLOG_NL_EVENT message.
    254  */
    255 bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
    256     const char *devname;
    257     ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
    258     if (!checkRtNetlinkLength(nh, sizeof(*pm)))
    259         return false;
    260 
    261     devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
    262     asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
    263     asprintf(&mParams[1], "INTERFACE=%s", devname);
    264     mSubsystem = strdup("qlog");
    265     mAction = Action::kChange;
    266     return true;
    267 }
    268 
    269 /*
    270  * Parse a LOCAL_NFLOG_PACKET message.
    271  */
    272 bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
    273     int uid = -1;
    274     int len = 0;
    275     char* raw = NULL;
    276 
    277     struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID);
    278     if (uid_attr) {
    279         uid = ntohl(nla_get_u32(uid_attr));
    280     }
    281 
    282     struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD);
    283     if (payload) {
    284         /* First 256 bytes is plenty */
    285         len = nla_len(payload);
    286         if (len > 256) len = 256;
    287         raw = (char*) nla_data(payload);
    288     }
    289 
    290     char* hex = (char*) calloc(1, 5 + (len * 2));
    291     strcpy(hex, "HEX=");
    292     for (int i = 0; i < len; i++) {
    293         hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf];
    294         hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf];
    295     }
    296 
    297     asprintf(&mParams[0], "UID=%d", uid);
    298     mParams[1] = hex;
    299     mSubsystem = strdup("strict");
    300     mAction = Action::kChange;
    301     return true;
    302 }
    303 
    304 /*
    305  * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
    306  */
    307 bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
    308     uint8_t type = nh->nlmsg_type;
    309     const char *msgname = rtMessageName(type);
    310 
    311     // Sanity check.
    312     if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
    313         SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
    314         return false;
    315     }
    316 
    317     struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
    318     if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
    319         return false;
    320 
    321     if (// Ignore static routes we've set up ourselves.
    322         (rtm->rtm_protocol != RTPROT_KERNEL &&
    323          rtm->rtm_protocol != RTPROT_RA) ||
    324         // We're only interested in global unicast routes.
    325         (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
    326         (rtm->rtm_type != RTN_UNICAST) ||
    327         // We don't support source routing.
    328         (rtm->rtm_src_len != 0) ||
    329         // Cloned routes aren't real routes.
    330         (rtm->rtm_flags & RTM_F_CLONED)) {
    331         return false;
    332     }
    333 
    334     int family = rtm->rtm_family;
    335     int prefixLength = rtm->rtm_dst_len;
    336 
    337     // Currently we only support: destination, (one) next hop, ifindex.
    338     char dst[INET6_ADDRSTRLEN] = "";
    339     char gw[INET6_ADDRSTRLEN] = "";
    340     char dev[IFNAMSIZ] = "";
    341 
    342     size_t len = RTM_PAYLOAD(nh);
    343     struct rtattr *rta;
    344     for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
    345         switch (rta->rta_type) {
    346             case RTA_DST:
    347                 if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
    348                     continue;
    349                 if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
    350                     return false;
    351                 continue;
    352             case RTA_GATEWAY:
    353                 if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
    354                     continue;
    355                 if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
    356                     return false;
    357                 continue;
    358             case RTA_OIF:
    359                 if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
    360                     continue;
    361                 if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
    362                     return false;
    363             default:
    364                 continue;
    365         }
    366     }
    367 
    368    // If there's no RTA_DST attribute, then:
    369    // - If the prefix length is zero, it's the default route.
    370    // - If the prefix length is nonzero, there's something we don't understand.
    371    //   Ignore the event.
    372    if (!*dst && !prefixLength) {
    373         if (family == AF_INET) {
    374             strncpy(dst, "0.0.0.0", sizeof(dst));
    375         } else if (family == AF_INET6) {
    376             strncpy(dst, "::", sizeof(dst));
    377         }
    378     }
    379 
    380     // A useful route must have a destination and at least either a gateway or
    381     // an interface.
    382     if (!*dst || (!*gw && !*dev))
    383         return false;
    384 
    385     // Fill in netlink event information.
    386     mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated :
    387                                        Action::kRouteRemoved;
    388     mSubsystem = strdup("net");
    389     asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
    390     asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
    391     asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
    392 
    393     return true;
    394 }
    395 
    396 /*
    397  * Parse a RTM_NEWNDUSEROPT message.
    398  */
    399 bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
    400     struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
    401     if (!checkRtNetlinkLength(nh, sizeof(*msg)))
    402         return false;
    403 
    404     // Check the length is valid.
    405     int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
    406     if (msg->nduseropt_opts_len > len) {
    407         SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
    408               msg->nduseropt_opts_len, len);
    409         return false;
    410     }
    411     len = msg->nduseropt_opts_len;
    412 
    413     // Check address family and packet type.
    414     if (msg->nduseropt_family != AF_INET6) {
    415         SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n",
    416               msg->nduseropt_family);
    417         return false;
    418     }
    419 
    420     if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
    421         msg->nduseropt_icmp_code != 0) {
    422         SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n",
    423               msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
    424         return false;
    425     }
    426 
    427     // Find the interface name.
    428     char ifname[IFNAMSIZ];
    429     if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
    430         SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
    431               msg->nduseropt_ifindex);
    432         return false;
    433     }
    434 
    435     // The kernel sends a separate netlink message for each ND option in the RA.
    436     // So only parse the first ND option in the message.
    437     struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1);
    438 
    439     // The length is in multiples of 8 octets.
    440     uint16_t optlen = opthdr->nd_opt_len;
    441     if (optlen * 8 > len) {
    442         SLOGE("Invalid option length %d > %d for ND option %d\n",
    443               optlen * 8, len, opthdr->nd_opt_type);
    444         return false;
    445     }
    446 
    447     if (opthdr->nd_opt_type == ND_OPT_RDNSS) {
    448         // DNS Servers (RFC 6106).
    449         // Each address takes up 2*8 octets, and the header takes up 8 octets.
    450         // So for a valid option with one or more addresses, optlen must be
    451         // odd and greater than 1.
    452         if ((optlen < 3) || !(optlen & 0x1)) {
    453             SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
    454             return false;
    455         }
    456         const int numaddrs = (optlen - 1) / 2;
    457 
    458         // Find the lifetime.
    459         struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
    460         const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
    461 
    462         // Construct "SERVERS=<comma-separated string of DNS addresses>".
    463         static const char kServerTag[] = "SERVERS=";
    464         static const size_t kTagLength = strlen(kServerTag);
    465         // Reserve sufficient space for an IPv6 link-local address: all but the
    466         // last address are followed by ','; the last is followed by '\0'.
    467         static const size_t kMaxSingleAddressLength =
    468                 INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
    469         const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
    470         char *buf = (char *) malloc(bufsize);
    471         if (!buf) {
    472             SLOGE("RDNSS option: out of memory\n");
    473             return false;
    474         }
    475         strcpy(buf, kServerTag);
    476         size_t pos = kTagLength;
    477 
    478         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
    479         for (int i = 0; i < numaddrs; i++) {
    480             if (i > 0) {
    481                 buf[pos++] = ',';
    482             }
    483             inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
    484             pos += strlen(buf + pos);
    485             if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) {
    486                 buf[pos++] = '%';
    487                 pos += strlcpy(buf + pos, ifname, bufsize - pos);
    488             }
    489         }
    490         buf[pos] = '\0';
    491 
    492         mAction = Action::kRdnss;
    493         mSubsystem = strdup("net");
    494         asprintf(&mParams[0], "INTERFACE=%s", ifname);
    495         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
    496         mParams[2] = buf;
    497     } else {
    498         SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
    499         return false;
    500     }
    501 
    502     return true;
    503 }
    504 
    505 /*
    506  * Parse a binary message from a NETLINK_ROUTE netlink socket.
    507  *
    508  * Note that this function can only parse one message, because the message's
    509  * content has to be stored in the class's member variables (mAction,
    510  * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
    511  * there are multiple valid messages in the buffer, only the first one will be
    512  * returned.
    513  *
    514  * TODO: consider only ever looking at the first message.
    515  */
    516 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
    517     struct nlmsghdr *nh;
    518 
    519     for (nh = (struct nlmsghdr *) buffer;
    520          NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
    521          nh = NLMSG_NEXT(nh, size)) {
    522 
    523         if (!rtMessageName(nh->nlmsg_type)) {
    524             SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
    525             continue;
    526         }
    527 
    528         if (nh->nlmsg_type == RTM_NEWLINK) {
    529             if (parseIfInfoMessage(nh))
    530                 return true;
    531 
    532         } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) {
    533             if (parseUlogPacketMessage(nh))
    534                 return true;
    535 
    536         } else if (nh->nlmsg_type == RTM_NEWADDR ||
    537                    nh->nlmsg_type == RTM_DELADDR) {
    538             if (parseIfAddrMessage(nh))
    539                 return true;
    540 
    541         } else if (nh->nlmsg_type == RTM_NEWROUTE ||
    542                    nh->nlmsg_type == RTM_DELROUTE) {
    543             if (parseRtMessage(nh))
    544                 return true;
    545 
    546         } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
    547             if (parseNdUserOptMessage(nh))
    548                 return true;
    549 
    550         } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) {
    551             if (parseNfPacketMessage(nh))
    552                 return true;
    553 
    554         }
    555     }
    556 
    557     return false;
    558 }
    559 
    560 /* If the string between 'str' and 'end' begins with 'prefixlen' characters
    561  * from the 'prefix' array, then return 'str + prefixlen', otherwise return
    562  * NULL.
    563  */
    564 static const char*
    565 has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
    566 {
    567     if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
    568         return str + prefixlen;
    569     else
    570         return NULL;
    571 }
    572 
    573 /* Same as strlen(x) for constant string literals ONLY */
    574 #define CONST_STRLEN(x)  (sizeof(x)-1)
    575 
    576 /* Convenience macro to call has_prefix with a constant string literal  */
    577 #define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
    578 
    579 
    580 /*
    581  * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
    582  * netlink socket.
    583  */
    584 bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
    585     const char *s = buffer;
    586     const char *end;
    587     int param_idx = 0;
    588     int first = 1;
    589 
    590     if (size == 0)
    591         return false;
    592 
    593     /* Ensure the buffer is zero-terminated, the code below depends on this */
    594     buffer[size-1] = '\0';
    595 
    596     end = s + size;
    597     while (s < end) {
    598         if (first) {
    599             const char *p;
    600             /* buffer is 0-terminated, no need to check p < end */
    601             for (p = s; *p != '@'; p++) {
    602                 if (!*p) { /* no '@', should not happen */
    603                     return false;
    604                 }
    605             }
    606             mPath = strdup(p+1);
    607             first = 0;
    608         } else {
    609             const char* a;
    610             if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
    611                 if (!strcmp(a, "add"))
    612                     mAction = Action::kAdd;
    613                 else if (!strcmp(a, "remove"))
    614                     mAction = Action::kRemove;
    615                 else if (!strcmp(a, "change"))
    616                     mAction = Action::kChange;
    617             } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
    618                 mSeq = atoi(a);
    619             } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
    620                 mSubsystem = strdup(a);
    621             } else if (param_idx < NL_PARAMS_MAX) {
    622                 mParams[param_idx++] = strdup(s);
    623             }
    624         }
    625         s += strlen(s) + 1;
    626     }
    627     return true;
    628 }
    629 
    630 bool NetlinkEvent::decode(char *buffer, int size, int format) {
    631     if (format == NetlinkListener::NETLINK_FORMAT_BINARY
    632             || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
    633         return parseBinaryNetlinkMessage(buffer, size);
    634     } else {
    635         return parseAsciiNetlinkMessage(buffer, size);
    636     }
    637 }
    638 
    639 const char *NetlinkEvent::findParam(const char *paramName) {
    640     size_t len = strlen(paramName);
    641     for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
    642         const char *ptr = mParams[i] + len;
    643         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
    644             return ++ptr;
    645     }
    646 
    647     SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
    648     return NULL;
    649 }
    650