• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
NetlinkEvent()50  NetlinkEvent::NetlinkEvent() {
51      mAction = Action::kUnknown;
52      memset(mParams, 0, sizeof(mParams));
53      mPath = NULL;
54      mSubsystem = NULL;
55  }
56  
~NetlinkEvent()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  
dump()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   */
rtMessageName(int type)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   */
checkRtNetlinkLength(const struct nlmsghdr * nh,size_t size)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   */
maybeLogDuplicateAttribute(bool isDup,const char * attributeName,const char * messageName)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   */
parseIfInfoMessage(const struct nlmsghdr * nh)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   */
parseIfAddrMessage(const struct nlmsghdr * nh)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   */
parseUlogPacketMessage(const struct nlmsghdr * nh)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   */
parseNfPacketMessage(struct nlmsghdr * nh)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   */
parseRtMessage(const struct nlmsghdr * nh)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   */
parseNdUserOptMessage(const struct nlmsghdr * nh)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   */
parseBinaryNetlinkMessage(char * buffer,int size)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*
has_prefix(const char * str,const char * end,const char * prefix,size_t prefixlen)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   */
parseAsciiNetlinkMessage(char * buffer,int size)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  
decode(char * buffer,int size,int format)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  
findParam(const char * paramName)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