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