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                 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
    211                 return false;
    212             }
    213 
    214         } else if (rta->rta_type == IFA_CACHEINFO) {
    215             // Address lifetime information.
    216             if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
    217                 continue;
    218 
    219             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
    220                 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
    221                       RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
    222                 continue;
    223             }
    224 
    225             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
    226         }
    227     }
    228 
    229     if (addrstr[0] == '\0') {
    230         SLOGE("No IFA_ADDRESS in %s\n", msgtype);
    231         return false;
    232     }
    233 
    234     // Fill in netlink event information.
    235     mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
    236                                       Action::kAddressRemoved;
    237     mSubsystem = strdup("net");
    238     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
    239              ifaddr->ifa_prefixlen);
    240     asprintf(&mParams[1], "INTERFACE=%s", ifname);
    241     asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
    242     asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
    243 
    244     if (cacheinfo) {
    245         asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
    246         asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
    247         asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
    248         asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
    249     }
    250 
    251     return true;
    252 }
    253 
    254 /*
    255  * Parse a QLOG_NL_EVENT message.
    256  */
    257 bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
    258     const char *devname;
    259     ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
    260     if (!checkRtNetlinkLength(nh, sizeof(*pm)))
    261         return false;
    262 
    263     devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
    264     asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
    265     asprintf(&mParams[1], "INTERFACE=%s", devname);
    266     mSubsystem = strdup("qlog");
    267     mAction = Action::kChange;
    268     return true;
    269 }
    270 
    271 /*
    272  * Parse a LOCAL_NFLOG_PACKET message.
    273  */
    274 bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
    275     int uid = -1;
    276     int len = 0;
    277     char* raw = NULL;
    278 
    279     struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID);
    280     if (uid_attr) {
    281         uid = ntohl(nla_get_u32(uid_attr));
    282     }
    283 
    284     struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD);
    285     if (payload) {
    286         /* First 256 bytes is plenty */
    287         len = nla_len(payload);
    288         if (len > 256) len = 256;
    289         raw = (char*) nla_data(payload);
    290     }
    291 
    292     char* hex = (char*) calloc(1, 5 + (len * 2));
    293     strcpy(hex, "HEX=");
    294     for (int i = 0; i < len; i++) {
    295         hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf];
    296         hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf];
    297     }
    298 
    299     asprintf(&mParams[0], "UID=%d", uid);
    300     mParams[1] = hex;
    301     mSubsystem = strdup("strict");
    302     mAction = Action::kChange;
    303     return true;
    304 }
    305 
    306 /*
    307  * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
    308  */
    309 bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
    310     uint8_t type = nh->nlmsg_type;
    311     const char *msgname = rtMessageName(type);
    312 
    313     // Sanity check.
    314     if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
    315         SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
    316         return false;
    317     }
    318 
    319     struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
    320     if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
    321         return false;
    322 
    323     if (// Ignore static routes we've set up ourselves.
    324         (rtm->rtm_protocol != RTPROT_KERNEL &&
    325          rtm->rtm_protocol != RTPROT_RA) ||
    326         // We're only interested in global unicast routes.
    327         (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
    328         (rtm->rtm_type != RTN_UNICAST) ||
    329         // We don't support source routing.
    330         (rtm->rtm_src_len != 0) ||
    331         // Cloned routes aren't real routes.
    332         (rtm->rtm_flags & RTM_F_CLONED)) {
    333         return false;
    334     }
    335 
    336     int family = rtm->rtm_family;
    337     int prefixLength = rtm->rtm_dst_len;
    338 
    339     // Currently we only support: destination, (one) next hop, ifindex.
    340     char dst[INET6_ADDRSTRLEN] = "";
    341     char gw[INET6_ADDRSTRLEN] = "";
    342     char dev[IFNAMSIZ] = "";
    343 
    344     size_t len = RTM_PAYLOAD(nh);
    345     struct rtattr *rta;
    346     for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
    347         switch (rta->rta_type) {
    348             case RTA_DST:
    349                 if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
    350                     continue;
    351                 if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
    352                     return false;
    353                 continue;
    354             case RTA_GATEWAY:
    355                 if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
    356                     continue;
    357                 if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
    358                     return false;
    359                 continue;
    360             case RTA_OIF:
    361                 if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
    362                     continue;
    363                 if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
    364                     return false;
    365             default:
    366                 continue;
    367         }
    368     }
    369 
    370    // If there's no RTA_DST attribute, then:
    371    // - If the prefix length is zero, it's the default route.
    372    // - If the prefix length is nonzero, there's something we don't understand.
    373    //   Ignore the event.
    374    if (!*dst && !prefixLength) {
    375         if (family == AF_INET) {
    376             strncpy(dst, "0.0.0.0", sizeof(dst));
    377         } else if (family == AF_INET6) {
    378             strncpy(dst, "::", sizeof(dst));
    379         }
    380     }
    381 
    382     // A useful route must have a destination and at least either a gateway or
    383     // an interface.
    384     if (!*dst || (!*gw && !*dev))
    385         return false;
    386 
    387     // Fill in netlink event information.
    388     mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated :
    389                                        Action::kRouteRemoved;
    390     mSubsystem = strdup("net");
    391     asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
    392     asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
    393     asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
    394 
    395     return true;
    396 }
    397 
    398 /*
    399  * Parse a RTM_NEWNDUSEROPT message.
    400  */
    401 bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
    402     struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
    403     if (!checkRtNetlinkLength(nh, sizeof(*msg)))
    404         return false;
    405 
    406     // Check the length is valid.
    407     int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
    408     if (msg->nduseropt_opts_len > len) {
    409         SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
    410               msg->nduseropt_opts_len, len);
    411         return false;
    412     }
    413     len = msg->nduseropt_opts_len;
    414 
    415     // Check address family and packet type.
    416     if (msg->nduseropt_family != AF_INET6) {
    417         SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n",
    418               msg->nduseropt_family);
    419         return false;
    420     }
    421 
    422     if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
    423         msg->nduseropt_icmp_code != 0) {
    424         SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n",
    425               msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
    426         return false;
    427     }
    428 
    429     // Find the interface name.
    430     char ifname[IFNAMSIZ];
    431     if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
    432         SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
    433               msg->nduseropt_ifindex);
    434         return false;
    435     }
    436 
    437     // The kernel sends a separate netlink message for each ND option in the RA.
    438     // So only parse the first ND option in the message.
    439     struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1);
    440 
    441     // The length is in multiples of 8 octets.
    442     uint16_t optlen = opthdr->nd_opt_len;
    443     if (optlen * 8 > len) {
    444         SLOGE("Invalid option length %d > %d for ND option %d\n",
    445               optlen * 8, len, opthdr->nd_opt_type);
    446         return false;
    447     }
    448 
    449     if (opthdr->nd_opt_type == ND_OPT_RDNSS) {
    450         // DNS Servers (RFC 6106).
    451         // Each address takes up 2*8 octets, and the header takes up 8 octets.
    452         // So for a valid option with one or more addresses, optlen must be
    453         // odd and greater than 1.
    454         if ((optlen < 3) || !(optlen & 0x1)) {
    455             SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
    456             return false;
    457         }
    458         const int numaddrs = (optlen - 1) / 2;
    459 
    460         // Find the lifetime.
    461         struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
    462         const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
    463 
    464         // Construct "SERVERS=<comma-separated string of DNS addresses>".
    465         static const char kServerTag[] = "SERVERS=";
    466         static const size_t kTagLength = strlen(kServerTag);
    467         // Reserve sufficient space for an IPv6 link-local address: all but the
    468         // last address are followed by ','; the last is followed by '\0'.
    469         static const size_t kMaxSingleAddressLength =
    470                 INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
    471         const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
    472         char *buf = (char *) malloc(bufsize);
    473         if (!buf) {
    474             SLOGE("RDNSS option: out of memory\n");
    475             return false;
    476         }
    477         strcpy(buf, kServerTag);
    478         size_t pos = kTagLength;
    479 
    480         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
    481         for (int i = 0; i < numaddrs; i++) {
    482             if (i > 0) {
    483                 buf[pos++] = ',';
    484             }
    485             inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
    486             pos += strlen(buf + pos);
    487             if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) {
    488                 buf[pos++] = '%';
    489                 pos += strlcpy(buf + pos, ifname, bufsize - pos);
    490             }
    491         }
    492         buf[pos] = '\0';
    493 
    494         mAction = Action::kRdnss;
    495         mSubsystem = strdup("net");
    496         asprintf(&mParams[0], "INTERFACE=%s", ifname);
    497         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
    498         mParams[2] = buf;
    499     } else {
    500         SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
    501         return false;
    502     }
    503 
    504     return true;
    505 }
    506 
    507 /*
    508  * Parse a binary message from a NETLINK_ROUTE netlink socket.
    509  *
    510  * Note that this function can only parse one message, because the message's
    511  * content has to be stored in the class's member variables (mAction,
    512  * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
    513  * there are multiple valid messages in the buffer, only the first one will be
    514  * returned.
    515  *
    516  * TODO: consider only ever looking at the first message.
    517  */
    518 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
    519     struct nlmsghdr *nh;
    520 
    521     for (nh = (struct nlmsghdr *) buffer;
    522          NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
    523          nh = NLMSG_NEXT(nh, size)) {
    524 
    525         if (!rtMessageName(nh->nlmsg_type)) {
    526             SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
    527             continue;
    528         }
    529 
    530         if (nh->nlmsg_type == RTM_NEWLINK) {
    531             if (parseIfInfoMessage(nh))
    532                 return true;
    533 
    534         } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) {
    535             if (parseUlogPacketMessage(nh))
    536                 return true;
    537 
    538         } else if (nh->nlmsg_type == RTM_NEWADDR ||
    539                    nh->nlmsg_type == RTM_DELADDR) {
    540             if (parseIfAddrMessage(nh))
    541                 return true;
    542 
    543         } else if (nh->nlmsg_type == RTM_NEWROUTE ||
    544                    nh->nlmsg_type == RTM_DELROUTE) {
    545             if (parseRtMessage(nh))
    546                 return true;
    547 
    548         } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
    549             if (parseNdUserOptMessage(nh))
    550                 return true;
    551 
    552         } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) {
    553             if (parseNfPacketMessage(nh))
    554                 return true;
    555 
    556         }
    557     }
    558 
    559     return false;
    560 }
    561 
    562 /* If the string between 'str' and 'end' begins with 'prefixlen' characters
    563  * from the 'prefix' array, then return 'str + prefixlen', otherwise return
    564  * NULL.
    565  */
    566 static const char*
    567 has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
    568 {
    569     if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
    570         return str + prefixlen;
    571     else
    572         return NULL;
    573 }
    574 
    575 /* Same as strlen(x) for constant string literals ONLY */
    576 #define CONST_STRLEN(x)  (sizeof(x)-1)
    577 
    578 /* Convenience macro to call has_prefix with a constant string literal  */
    579 #define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
    580 
    581 
    582 /*
    583  * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
    584  * netlink socket.
    585  */
    586 bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
    587     const char *s = buffer;
    588     const char *end;
    589     int param_idx = 0;
    590     int first = 1;
    591 
    592     if (size == 0)
    593         return false;
    594 
    595     /* Ensure the buffer is zero-terminated, the code below depends on this */
    596     buffer[size-1] = '\0';
    597 
    598     end = s + size;
    599     while (s < end) {
    600         if (first) {
    601             const char *p;
    602             /* buffer is 0-terminated, no need to check p < end */
    603             for (p = s; *p != '@'; p++) {
    604                 if (!*p) { /* no '@', should not happen */
    605                     return false;
    606                 }
    607             }
    608             mPath = strdup(p+1);
    609             first = 0;
    610         } else {
    611             const char* a;
    612             if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
    613                 if (!strcmp(a, "add"))
    614                     mAction = Action::kAdd;
    615                 else if (!strcmp(a, "remove"))
    616                     mAction = Action::kRemove;
    617                 else if (!strcmp(a, "change"))
    618                     mAction = Action::kChange;
    619             } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
    620                 mSeq = atoi(a);
    621             } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
    622                 mSubsystem = strdup(a);
    623             } else if (param_idx < NL_PARAMS_MAX) {
    624                 mParams[param_idx++] = strdup(s);
    625             }
    626         }
    627         s += strlen(s) + 1;
    628     }
    629     return true;
    630 }
    631 
    632 bool NetlinkEvent::decode(char *buffer, int size, int format) {
    633     if (format == NetlinkListener::NETLINK_FORMAT_BINARY
    634             || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
    635         return parseBinaryNetlinkMessage(buffer, size);
    636     } else {
    637         return parseAsciiNetlinkMessage(buffer, size);
    638     }
    639 }
    640 
    641 const char *NetlinkEvent::findParam(const char *paramName) {
    642     size_t len = strlen(paramName);
    643     for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
    644         const char *ptr = mParams[i] + len;
    645         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
    646             return ++ptr;
    647     }
    648 
    649     SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
    650     return NULL;
    651 }
    652