Add NETLINK_ROUTE processing to the netlink client code, so that Ethernet
physical-layer up/down events can be tracked. Upper layers will use these
events to enable/disable Ethernet connectivity.
Change-Id: If07c30c4d79f26cf94eb5597be651ebbf9d072c6
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 86c1f42..2e3143d 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -19,12 +19,20 @@
#define LOG_TAG "NetlinkEvent"
#include <cutils/log.h>
+#include <sysutils/NetlinkListener.h>
#include <sysutils/NetlinkEvent.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+#include <linux/if.h>
+
const int NetlinkEvent::NlActionUnknown = 0;
const int NetlinkEvent::NlActionAdd = 1;
const int NetlinkEvent::NlActionRemove = 2;
const int NetlinkEvent::NlActionChange = 3;
+const int NetlinkEvent::NlActionLinkUp = 4;
+const int NetlinkEvent::NlActionLinkDown = 5;
NetlinkEvent::NetlinkEvent() {
mAction = NlActionUnknown;
@@ -56,7 +64,56 @@
}
}
-bool NetlinkEvent::decode(char *buffer, int size) {
+/*
+ * Parse an binary message from a NETLINK_ROUTE netlink socket.
+ */
+bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
+ size_t sz = size;
+ struct nlmsghdr *nh = (struct nlmsghdr *) buffer;
+
+ while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) {
+ if (nh->nlmsg_type == RTM_NEWLINK) {
+ int len = nh->nlmsg_len - sizeof(*nh);
+ struct ifinfomsg *ifi;
+
+ if (sizeof(*ifi) <= (size_t) len) {
+ ifi = (ifinfomsg *)NLMSG_DATA(nh);
+
+ if ((ifi->ifi_flags & IFF_LOOPBACK) == 0) {
+ struct rtattr *rta = (struct rtattr *)
+ ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
+ len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
+
+ while(RTA_OK(rta, len)) {
+ switch(rta->rta_type) {
+ case IFLA_IFNAME:
+ char buffer[16 + IFNAMSIZ];
+ snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
+ (char *) RTA_DATA(rta));
+ mParams[0] = strdup(buffer);
+ mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
+ NlActionLinkUp : NlActionLinkDown;
+ mSubsystem = strdup("net");
+ break;
+ }
+
+ rta = RTA_NEXT(rta, len);
+ }
+ }
+ }
+ }
+
+ nh = NLMSG_NEXT(nh, size);
+ }
+
+ return true;
+}
+
+/*
+ * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
+ * netlink socket.
+ */
+bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
char *s = buffer;
char *end;
int param_idx = 0;
@@ -92,6 +149,14 @@
return true;
}
+bool NetlinkEvent::decode(char *buffer, int size, int format) {
+ if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
+ return parseBinaryNetlinkMessage(buffer, size);
+ } else {
+ return parseAsciiNetlinkMessage(buffer, size);
+ }
+}
+
const char *NetlinkEvent::findParam(const char *paramName) {
size_t len = strlen(paramName);
for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) {