Merge changes Ia6ae54ec,I65e7c9b7,I7875fc6e,Ia5363453,Id77b7720, ...

* changes:
  Improve IPv6 networking for radio
  Return the auth status as the error code for +CSIM
  Pass the size of the vatiable instead of a pointer to it
  Add support for carrier restrictions to ril
  Add support to query modem activity info in ril
  Emulator: add CSIM authentication support
  Return result after RIL set auto network selection
diff --git a/ril/Android.mk b/ril/Android.mk
index 34bd227..cb5f31a 100644
--- a/ril/Android.mk
+++ b/ril/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES:= \
     reference-ril.c \
     atchannel.c \
+    if_monitor.cpp \
     misc.c \
     at_tok.c
 
diff --git a/ril/atchannel.c b/ril/atchannel.c
index 0041836..407a204 100644
--- a/ril/atchannel.c
+++ b/ril/atchannel.c
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <pthread.h>
 #include <ctype.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
diff --git a/ril/if_monitor.cpp b/ril/if_monitor.cpp
new file mode 100644
index 0000000..289477d
--- /dev/null
+++ b/ril/if_monitor.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "if_monitor.h"
+
+#include <errno.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+#define LOG_TAG "RIL-IFMON"
+#include <utils/Log.h>
+
+static const size_t kReadBufferSize = 32768;
+
+static const size_t kControlServer = 0;
+static const size_t kControlClient = 1;
+
+// A list of commands that can be sent to the monitor. These should be one
+// character long as that is all that the monitor will read and process.
+static const char kMonitorStopCommand[] = "\1";
+static const char kMonitorAckCommand[] = "\2";
+
+static size_t addrLength(int addrFamily) {
+    switch (addrFamily) {
+        case AF_INET:
+            return 4;
+        case AF_INET6:
+            return 16;
+        default:
+            return 0;
+    }
+}
+
+bool operator==(const struct ifAddress& left, const struct ifAddress& right) {
+    // The prefix length does not factor in to whether two addresses are the
+    // same or not. Only the family and the address data. This matches the
+    // kernel behavior when attempting to add the same address with different
+    // prefix lengths, those changes are rejected because the address already
+    // exists.
+    return left.family == right.family &&
+           memcmp(&left.addr, &right.addr, addrLength(left.family)) == 0;
+}
+
+class InterfaceMonitor {
+public:
+    InterfaceMonitor() : mSocketFd(-1) {
+        mControlSocket[kControlServer] = -1;
+        mControlSocket[kControlClient] = -1;
+    }
+
+    ~InterfaceMonitor() {
+        if (mControlSocket[kControlClient] != -1) {
+            ::close(mControlSocket[kControlClient]);
+            mControlSocket[kControlClient] = -1;
+        }
+        if (mControlSocket[kControlServer] != -1) {
+            ::close(mControlSocket[kControlServer]);
+            mControlSocket[kControlServer] = -1;
+        }
+
+        if (mSocketFd != -1) {
+            ::close(mSocketFd);
+            mSocketFd = -1;
+        }
+    }
+
+    bool init() {
+        if (mSocketFd != -1) {
+            RLOGE("InterfaceMonitor already initialized");
+            return false;
+        }
+
+        mSocketFd = ::socket(AF_NETLINK,
+                             SOCK_DGRAM | SOCK_CLOEXEC,
+                             NETLINK_ROUTE);
+        if (mSocketFd == -1) {
+            RLOGE("InterfaceMonitor failed to open socket: %s", strerror(errno));
+            return false;
+        }
+
+        if (::socketpair(AF_UNIX, SOCK_DGRAM, 0, mControlSocket) != 0) {
+            RLOGE("Unable to create control socket pair: %s", strerror(errno));
+            return false;
+        }
+
+        struct sockaddr_nl addr;
+        memset(&addr, 0, sizeof(addr));
+        addr.nl_family = AF_NETLINK;
+        addr.nl_groups = (1 << (RTNLGRP_IPV4_IFADDR - 1)) |
+                         (1 << (RTNLGRP_IPV6_IFADDR - 1));
+
+        struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(&addr);
+        if (::bind(mSocketFd, sa, sizeof(addr)) != 0) {
+            RLOGE("InterfaceMonitor failed to bind socket: %s",
+                  strerror(errno));
+            return false;
+        }
+
+        return true;
+    }
+
+    void setCallback(ifMonitorCallback callback) {
+        mOnAddressChangeCallback = callback;
+    }
+
+    void runAsync() {
+        std::unique_lock<std::mutex> lock(mThreadMutex);
+        mThread = std::make_unique<std::thread>([this]() { run(); });
+    }
+
+    void requestAddress() {
+        struct {
+            struct nlmsghdr hdr;
+            struct ifaddrmsg msg;
+            char padding[16];
+        } request;
+
+        memset(&request, 0, sizeof(request));
+        request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
+        request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+        request.hdr.nlmsg_type = RTM_GETADDR;
+
+        int status = ::send(mSocketFd, &request, request.hdr.nlmsg_len, 0);
+        if (status < 0 ||
+            static_cast<unsigned int>(status) != request.hdr.nlmsg_len) {
+            if (status < 0) {
+                RLOGE("Failed to send netlink request: %s", strerror(errno));
+            } else {
+                RLOGE("Short send only sent %d out of %d bytes",
+                      status, (int)request.hdr.nlmsg_len);
+            }
+        }
+    }
+
+    void run() {
+        requestAddress();
+
+        std::vector<struct pollfd> fds(2);
+        fds[0].events = POLLIN;
+        fds[0].fd = mControlSocket[kControlServer];
+        fds[1].events = POLLIN;
+        fds[1].fd = mSocketFd;
+        while (true) {
+            int status = ::poll(fds.data(), fds.size(), -1);
+            if (status < 0) {
+                if (errno == EINTR) {
+                    // Interrupted, just keep going
+                    continue;
+                }
+                // Actual error, time to quit
+                RLOGE("Polling failed: %s", strerror(errno));
+                break;
+            } else if (status == 0) {
+                // Timeout
+                continue;
+            }
+
+            if (fds[0].revents & POLLIN) {
+                // Control message received
+                char command = -1;
+                if (::read(mControlSocket[kControlServer],
+                           &command,
+                           sizeof(command)) == 1) {
+                    if (command == kMonitorStopCommand[0]) {
+                        break;
+                    }
+                }
+            } else if (fds[1].revents & POLLIN) {
+                onReadAvailable();
+            }
+        }
+        ::write(mControlSocket[kControlServer], kMonitorAckCommand, 1);
+    }
+
+    void stop() {
+        std::unique_lock<std::mutex> lock(mThreadMutex);
+        if (mThread) {
+            ::write(mControlSocket[kControlClient], kMonitorStopCommand, 1);
+            char ack = -1;
+            while (ack != kMonitorAckCommand[0]) {
+                ::read(mControlSocket[kControlClient], &ack, sizeof(ack));
+            }
+            mThread->join();
+            mThread.reset();
+        }
+    }
+
+private:
+    void onReadAvailable() {
+        char buffer[kReadBufferSize];
+        struct sockaddr_storage storage;
+
+        while (true) {
+            socklen_t addrSize = sizeof(storage);
+            int status = ::recvfrom(mSocketFd,
+                                    buffer,
+                                    sizeof(buffer),
+                                    MSG_DONTWAIT,
+                                    reinterpret_cast<struct sockaddr*>(&storage),
+                                    &addrSize);
+            if (status < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+                // Nothing to receive, everything is fine
+                return;
+            } else if (status < 0 && errno == EINTR) {
+                // Caught interrupt, try again
+                continue;
+            } else if (status < 0) {
+                RLOGE("InterfaceMonitor receive failed: %s", strerror(errno));
+                return;
+            } else if (addrSize < 0 ||
+                       static_cast<size_t>(addrSize) != sizeof(struct sockaddr_nl)) {
+                RLOGE("InterfaceMonitor received invalid address size");
+                return;
+            }
+
+            size_t length = static_cast<size_t>(status);
+
+            auto hdr = reinterpret_cast<struct nlmsghdr*>(buffer);
+            while (NLMSG_OK(hdr, length) && hdr->nlmsg_type != NLMSG_DONE) {
+                switch (hdr->nlmsg_type) {
+                    case RTM_NEWADDR:
+                    case RTM_DELADDR:
+                        handleAddressChange(hdr);
+                        break;
+                    default:
+                        RLOGE("Received message type %d", (int)hdr->nlmsg_type);
+                        break;
+                }
+                NLMSG_NEXT(hdr, length);
+            }
+        }
+    }
+
+    void handleAddressChange(const struct nlmsghdr* hdr) {
+        if (!mOnAddressChangeCallback) {
+            return;
+        }
+
+        auto msg = reinterpret_cast<const struct ifaddrmsg*>(NLMSG_DATA(hdr));
+        std::vector<ifAddress>& ifAddrs = mAddresses[msg->ifa_index];
+
+        auto attr = reinterpret_cast<const struct rtattr*>(IFA_RTA(msg));
+        int attrLen = IFA_PAYLOAD(hdr);
+
+        bool somethingChanged = false;
+        for (;attr && RTA_OK(attr, attrLen); attr = RTA_NEXT(attr, attrLen)) {
+            if (attr->rta_type != IFA_LOCAL && attr->rta_type != IFA_ADDRESS) {
+                continue;
+            }
+
+            ifAddress addr;
+            memset(&addr, 0, sizeof(addr));
+
+            // Ensure that the payload matches the expected address length
+            if (RTA_PAYLOAD(attr) >= addrLength(msg->ifa_family)) {
+                addr.family = msg->ifa_family;
+                addr.prefix = msg->ifa_prefixlen;
+                memcpy(&addr.addr, RTA_DATA(attr), addrLength(addr.family));
+            } else {
+                RLOGE("Invalid address family (%d) and size (%d) combination",
+                      int(msg->ifa_family), int(RTA_PAYLOAD(attr)));
+                continue;
+            }
+
+            auto it = std::find(ifAddrs.begin(), ifAddrs.end(), addr);
+            if (hdr->nlmsg_type == RTM_NEWADDR && it == ifAddrs.end()) {
+                // New address does not exist, add it
+                ifAddrs.push_back(addr);
+                somethingChanged = true;
+            } else if (hdr->nlmsg_type == RTM_DELADDR && it != ifAddrs.end()) {
+                // Address was removed and it exists, remove it
+                ifAddrs.erase(it);
+                somethingChanged = true;
+            }
+        }
+
+        if (somethingChanged) {
+            mOnAddressChangeCallback(msg->ifa_index,
+                                     ifAddrs.data(),
+                                     ifAddrs.size());
+        }
+    }
+
+    ifMonitorCallback mOnAddressChangeCallback;
+    std::unordered_map<unsigned int, std::vector<ifAddress>> mAddresses;
+    std::unique_ptr<std::thread> mThread;
+    std::mutex mThreadMutex;
+    int mSocketFd;
+    int mControlSocket[2];
+};
+
+extern "C"
+struct ifMonitor* ifMonitorCreate() {
+    auto monitor = std::make_unique<InterfaceMonitor>();
+    if (!monitor || !monitor->init()) {
+        return nullptr;
+    }
+    return reinterpret_cast<struct ifMonitor*>(monitor.release());
+}
+
+extern "C"
+void ifMonitorFree(struct ifMonitor* ifMonitor) {
+    InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor);
+    delete monitor;
+}
+
+extern "C"
+void ifMonitorSetCallback(struct ifMonitor* ifMonitor,
+                          ifMonitorCallback callback) {
+    InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor);
+    monitor->setCallback(callback);
+}
+
+extern "C"
+void ifMonitorRunAsync(struct ifMonitor* ifMonitor) {
+    InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor);
+
+    monitor->runAsync();
+}
+
+extern "C"
+void ifMonitorStop(struct ifMonitor* ifMonitor) {
+    InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor);
+
+    monitor->stop();
+}
+
diff --git a/ril/if_monitor.h b/ril/if_monitor.h
new file mode 100644
index 0000000..118bf88
--- /dev/null
+++ b/ril/if_monitor.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ifMonitor;
+
+struct ifAddress {
+    int family;
+    int prefix;
+    unsigned char addr[16];
+};
+
+// A callback for when the addresses on an interface changes
+typedef void (*ifMonitorCallback)(unsigned int /*interface index*/,
+                                  const struct ifAddress* /*addresses*/,
+                                  size_t /*number of addresses */);
+
+struct ifMonitor* ifMonitorCreate();
+void ifMonitorFree(struct ifMonitor* monitor);
+
+void ifMonitorSetCallback(struct ifMonitor* monitor,
+                          ifMonitorCallback callback);
+void ifMonitorRunAsync(struct ifMonitor* monitor);
+void ifMonitorStop(struct ifMonitor* monitor);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
diff --git a/ril/reference-ril.c b/ril/reference-ril.c
index 3bca581..7e52e10 100644
--- a/ril/reference-ril.c
+++ b/ril/reference-ril.c
@@ -41,8 +41,10 @@
 #include <sys/wait.h>
 #include <stdbool.h>
 #include <net/if.h>
+#include <arpa/inet.h>
 #include <netinet/in.h>
 
+#include "if_monitor.h"
 #include "ril.h"
 
 #define LOG_TAG "RIL"
@@ -59,6 +61,11 @@
 // This is used if Wifi is supported to separate radio and wifi interface
 #define PPP_TTY_PATH_RADIO0 "radio0"
 
+// This is the IP address to provide for radio0 when WiFi is enabled
+// When WiFi is not enabled the RIL should provide the address given by
+// the modem.
+#define RADIO0_IPV4_ADDRESS "192.168.200.2/24"
+
 // Default MTU value
 #define DEFAULT_MTU 1500
 
@@ -167,18 +174,24 @@
     SIM_PIN = 3,
     SIM_PUK = 4,
     SIM_NETWORK_PERSONALIZATION = 5,
-    RUIM_ABSENT = 6,
-    RUIM_NOT_READY = 7,
-    RUIM_READY = 8,
-    RUIM_PIN = 9,
-    RUIM_PUK = 10,
-    RUIM_NETWORK_PERSONALIZATION = 11,
-    ISIM_ABSENT = 12,
-    ISIM_NOT_READY = 13,
-    ISIM_READY = 14,
-    ISIM_PIN = 15,
-    ISIM_PUK = 16,
-    ISIM_NETWORK_PERSONALIZATION = 17,
+    SIM_RESTRICTED = 6,
+
+    RUIM_ABSENT = 7,
+    RUIM_NOT_READY = 8,
+    RUIM_READY = 9,
+    RUIM_PIN = 10,
+    RUIM_PUK = 11,
+    RUIM_NETWORK_PERSONALIZATION = 12,
+    RUIM_RESTRICTED = 13,
+
+    ISIM_ABSENT = 14,
+    ISIM_NOT_READY = 15,
+    ISIM_READY = 16,
+    ISIM_PIN = 17,
+    ISIM_PUK = 18,
+    ISIM_NETWORK_PERSONALIZATION = 19,
+    ISIM_RESTRICTED = 20
+
 } SIM_Status;
 
 static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
@@ -260,6 +273,10 @@
 static int s_lac = 0;
 static int s_cid = 0;
 
+// A string containing all the IPv6 addresses of the radio interface
+static char s_ipv6_addresses[8192];
+static pthread_mutex_t s_ipv6_addresses_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 static void pollSIMState (void *param);
 static void setRadioState(RIL_RadioState newState);
 static void setRadioTechnology(ModemInfo *mdm, int newtech);
@@ -410,6 +427,21 @@
     return RIL_E_SUCCESS;
 }
 
+static void parseAuthResponse(char* line, RIL_SIM_IO_Response* response) {
+    // example string +CSIM=number, "<base64string>9000"
+    // get the status first
+    int len = strlen(line);
+    char* first_double_quote = strchr(line, '"');
+    if (first_double_quote == NULL) {
+        RLOGE("%s bad response %s", __func__, line);
+        return;
+    }
+    char* data_ptr = first_double_quote + 1;
+    sscanf(line + (len -5), "%2x%2x", &(response->sw1), &(response->sw2));
+    line[len-5] = '\0';
+    response->simResponse = strdup(data_ptr);
+}
+
 /** do post-AT+CFUN=1 initialization */
 static void onRadioPowerOn()
 {
@@ -695,13 +727,32 @@
         responses[i].ifname = alloca(ifname_size);
         strlcpy(responses[i].ifname, radioInterfaceName, ifname_size);
 
+        // The next token is the IPv4 address provided by the emulator, only use
+        // it if WiFi is not enabled. When WiFi is enabled the network setup is
+        // specific to the system image and the emulator only provides the
+        // IP address for the external interface in the router namespace.
         err = at_tok_nextstr(&line, &out);
         if (err < 0)
             goto error;
 
-        int addresses_size = strlen(out) + 1;
+        pthread_mutex_lock(&s_ipv6_addresses_mutex);
+
+        // Extra space for null terminator and separating space
+        int addresses_size = strlen(out) + strlen(s_ipv6_addresses) + 2;
         responses[i].addresses = alloca(addresses_size);
-        strlcpy(responses[i].addresses, out, addresses_size);
+        if (*s_ipv6_addresses) {
+            // IPv6 addresses exist, add them
+            snprintf(responses[i].addresses, addresses_size,
+                     "%s %s",
+                     hasWifi ? RADIO0_IPV4_ADDRESS : out,
+                     s_ipv6_addresses);
+        } else {
+            // Only provide the IPv4 address
+            strlcpy(responses[i].addresses,
+                    hasWifi ? RADIO0_IPV4_ADDRESS : out,
+                    addresses_size);
+        }
+        pthread_mutex_unlock(&s_ipv6_addresses_mutex);
 
         if (isInEmulator()) {
             /* We are in the emulator - the dns servers are listed
@@ -712,16 +763,16 @@
                 *  - net.eth0.dns3
                 *  - net.eth0.dns4
                 */
-            const int   dnslist_sz = 128;
+            const int   dnslist_sz = 256;
             char*       dnslist = alloca(dnslist_sz);
             const char* separator = "";
             int         nn;
+            char  propName[PROP_NAME_MAX];
+            char  propValue[PROP_VALUE_MAX];
 
             dnslist[0] = 0;
             for (nn = 1; nn <= 4; nn++) {
                 /* Probe net.eth0.dns<n> */
-                char  propName[PROP_NAME_MAX];
-                char  propValue[PROP_VALUE_MAX];
 
                 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
 
@@ -735,6 +786,18 @@
                 strlcat(dnslist, propValue, dnslist_sz);
                 separator = " ";
             }
+            for (nn = 1; nn <= 4; ++nn) {
+                /* Probe net.eth0.ipv6dns<n> for IPv6 DNS servers */
+                snprintf(propName, sizeof propName, "net.eth0.ipv6dns%d", nn);
+                /* Ignore if undefined */
+                if (property_get(propName, propValue, "") <= 0) {
+                    continue;
+                }
+                strlcat(dnslist, separator, dnslist_sz);
+                strlcat(dnslist, propValue, dnslist_sz);
+                separator = " ";
+            }
+
             responses[i].dnses = dnslist;
 
             /* There is only one gateway in the emulator. If WiFi is
@@ -780,6 +843,27 @@
     at_response_free(p_response);
 }
 
+static void setNetworkSelectionAutomatic(RIL_Token t)
+{
+    int err;
+    ATResponse *p_response = NULL;
+
+    if (getSIMStatus() == SIM_ABSENT) {
+        RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+        return;
+    }
+
+    err = at_send_command("AT+COPS=0", &p_response);
+
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    } else {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    }
+
+    at_response_free(p_response);
+}
+
 static void requestQueryNetworkSelectionMode(
                 void *data __unused, size_t datalen __unused, RIL_Token t)
 {
@@ -1857,7 +1941,7 @@
         return;
     }
 
-    RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(&session_id));
+    RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(session_id));
     at_response_free(p_response);
 }
 
@@ -2332,6 +2416,113 @@
    RIL_onRequestComplete(t, RIL_E_SUCCESS, &muteResponse, sizeof(muteResponse));
 }
 
+static void requestGetSimAuthentication(void *data, size_t datalen __unused, RIL_Token t)
+{
+    // TODO - hook this up with real query/info from radio.
+    RIL_SimAuthentication* auth = (RIL_SimAuthentication*)data;
+
+    RIL_SIM_IO_Response auth_response = {
+        0x90,
+        0x00,
+        ""
+    };
+
+    // special case: empty authData, should return empty response
+    if (auth->authData == NULL || strlen(auth->authData) == 0) {
+        char reply[] = "";
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, &auth_response, sizeof(auth_response));
+        RLOGD("%s empty data in", __func__);
+        return;
+    }
+
+    //talk to modem
+    ATResponse *p_response = NULL;
+    memset(&auth_response, 0, sizeof(auth_response));
+    int err;
+    char *cmd = NULL;
+    int auth_len = strlen(auth->authData);
+    int total_len = auth_len + 12;
+    asprintf(&cmd, "AT+CSIM=%d, \"008800%02x%02x%s00\"", total_len, auth->authContext,
+            auth_len, auth->authData);
+
+    err = at_send_command_singleline(cmd, "+CSIM:", &p_response);
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        ALOGE("%s Error %d transmitting CSIM: %d", __func__,
+              err, p_response ? p_response->success : 0);
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+        at_response_free(p_response);
+        return;
+    }
+
+    char* line = p_response->p_intermediates->line;
+
+    parseAuthResponse(line, &auth_response);
+    RIL_onRequestComplete(t, auth_response.sw2, &auth_response, sizeof(auth_response));
+    free(auth_response.simResponse);
+    free(p_response);
+}
+
+static void requestModemActivityInfo(RIL_Token t)
+{
+    int err;
+    char *line;
+    ATResponse *p_response = NULL;
+    RIL_ActivityStatsInfo info;
+
+    err = at_send_command_singleline("AT+MAI", "+MAI:", &p_response);
+    if (err < 0 || p_response == NULL || p_response->success == 0) {
+        ALOGE("Error transmitting AT+MAI, err=%d, success=%d",
+            err, (p_response ? p_response->success : 0));
+        goto error;
+    }
+
+    memset(&info, 0, sizeof(info));
+    if (sscanf(p_response->p_intermediates->line,
+               "+MAI: sleep=%u idle=%u rx=%u tx0=%u tx1=%u tx2=%u tx3=%u tx4=%u",
+               &info.sleep_mode_time_ms,
+               &info.idle_mode_time_ms,
+               &info.rx_mode_time_ms,
+               &info.tx_mode_time_ms[0],
+               &info.tx_mode_time_ms[1],
+               &info.tx_mode_time_ms[2],
+               &info.tx_mode_time_ms[3],
+               &info.tx_mode_time_ms[4]) == 8) {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, &info, sizeof(info));
+        at_response_free(p_response);
+        return;
+    } else {
+        ALOGE("Unexpected response for AT+MAI: '%s'",
+            p_response->p_intermediates->line);
+    }
+
+error:
+    at_response_free(p_response);
+    RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void requestSetCarrierRestrictions(const RIL_CarrierRestrictions *restrictions __unused, RIL_Token t)
+{
+    ATResponse *p_response = NULL;
+    int success;
+    int err;
+    char cmd[32];
+
+    snprintf(cmd, sizeof(cmd), "AT+CRRSTR=%d,%d",
+        restrictions->len_allowed_carriers,
+        restrictions->len_excluded_carriers);
+
+    err = at_send_command_singleline(cmd, "+CRRSTR:", &p_response);
+    success = p_response ? p_response->success : 0;
+    at_response_free(p_response);
+
+    if (err == 0 && success) {
+        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+    } else {
+        ALOGE("'%s' failed with err=%d success=%d", cmd, err, success);
+        RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+    }
+}
+
 /*** Callback methods from the RIL library to us ***/
 
 /**
@@ -2585,11 +2776,7 @@
             break;
 
         case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
-            if (getSIMStatus() == SIM_ABSENT) {
-                RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
-            } else {
-                at_send_command("AT+COPS=0", NULL);
-            }
+            setNetworkSelectionAutomatic(t);
             break;
 
         case RIL_REQUEST_DATA_CALL_LIST:
@@ -2731,6 +2918,10 @@
             RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
             break;
 
+        case RIL_REQUEST_SIM_AUTHENTICATION:
+            requestGetSimAuthentication(data, datalen, t);
+            break;
+
         case RIL_REQUEST_BASEBAND_VERSION:
             requestCdmaBaseBandVersion(request, data, datalen, t);
             break;
@@ -2792,6 +2983,19 @@
             }
             break;
 
+        case RIL_REQUEST_GET_ACTIVITY_INFO:
+            requestModemActivityInfo(t);
+            break;
+
+        case RIL_REQUEST_SET_CARRIER_RESTRICTIONS:
+            if (datalen == sizeof(RIL_CarrierRestrictions)) {
+                requestSetCarrierRestrictions((const RIL_CarrierRestrictions *)data, t);
+            } else {
+                /* unexpected sizeof */
+                RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+            }
+            break;
+
         default:
             RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
             RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
@@ -2984,7 +3188,7 @@
 {
     ATResponse *p_response = NULL;
     int err;
-    int ret;
+    SIM_Status ret;
     char *cpinLine;
     char *cpinResult;
 
@@ -3028,24 +3232,19 @@
 
     if (0 == strcmp (cpinResult, "SIM PIN")) {
         ret = SIM_PIN;
-        goto done;
     } else if (0 == strcmp (cpinResult, "SIM PUK")) {
         ret = SIM_PUK;
-        goto done;
     } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
-        return SIM_NETWORK_PERSONALIZATION;
-    } else if (0 != strcmp (cpinResult, "READY"))  {
+        ret = SIM_NETWORK_PERSONALIZATION;
+    } else if (0 == strcmp (cpinResult, "RESTRICTED"))  {
+        ret = SIM_RESTRICTED;
+    } else if (0 == strcmp (cpinResult, "READY"))  {
+        ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
+    } else {
         /* we're treating unsupported lock types as "sim absent" */
         ret = SIM_ABSENT;
-        goto done;
     }
 
-    at_response_free(p_response);
-    p_response = NULL;
-    cpinResult = NULL;
-
-    ret = (sState == RADIO_STATE_ON) ? SIM_READY : SIM_NOT_READY;
-
 done:
     at_response_free(p_response);
     return ret;
@@ -3059,7 +3258,7 @@
  * @return: On success returns RIL_E_SUCCESS
  */
 static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
-    static RIL_AppStatus app_status_array[] = {
+    static const RIL_AppStatus app_status_array[] = {
         // SIM_ABSENT = 0
         { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
@@ -3078,54 +3277,74 @@
         // SIM_NETWORK_PERSONALIZATION = 5
         { RIL_APPTYPE_USIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
-        // RUIM_ABSENT = 6
+        // SIM_RESTRICTED = 6
         { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // RUIM_NOT_READY = 7
+
+        // RUIM_ABSENT = 7
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // RUIM_NOT_READY = 8
         { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // RUIM_READY = 8
+        // RUIM_READY = 9
         { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // RUIM_PIN = 9
+        // RUIM_PIN = 10
         { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
-        // RUIM_PUK = 10
+        // RUIM_PUK = 11
         { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
-        // RUIM_NETWORK_PERSONALIZATION = 11
+        // RUIM_NETWORK_PERSONALIZATION = 12
         { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
            NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
-        // ISIM_ABSENT = 12
+        // RUIM_RESTRICTED = 13
         { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // ISIM_NOT_READY = 13
+
+        // ISIM_ABSENT = 14
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+        // ISIM_NOT_READY = 15
         { RIL_APPTYPE_ISIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // ISIM_READY = 14
+        // ISIM_READY = 16
         { RIL_APPTYPE_ISIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
           NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
-        // ISIM_PIN = 15
+        // ISIM_PIN = 17
         { RIL_APPTYPE_ISIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
-        // ISIM_PUK = 16
+        // ISIM_PUK = 18
         { RIL_APPTYPE_ISIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
-        // ISIM_NETWORK_PERSONALIZATION = 17
+        // ISIM_NETWORK_PERSONALIZATION = 19
         { RIL_APPTYPE_ISIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
           NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
-
+        // ISIM_RESTRICTED = 20
+        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
     };
+
     RIL_CardState card_state;
     int num_apps;
 
-    int sim_status = getSIMStatus();
-    if (sim_status == SIM_ABSENT) {
-        card_state = RIL_CARDSTATE_ABSENT;
-        num_apps = 0;
-    } else {
-        card_state = RIL_CARDSTATE_PRESENT;
-        num_apps = 3;
+    SIM_Status sim_status = getSIMStatus();
+    switch (sim_status) {
+        case SIM_ABSENT:
+            card_state = RIL_CARDSTATE_ABSENT;
+            num_apps = 0;
+            break;
+
+        case SIM_RESTRICTED:
+            card_state = RIL_CARDSTATE_RESTRICTED;
+            num_apps = 0;
+            break;
+
+        default:
+            card_state = RIL_CARDSTATE_PRESENT;
+            num_apps = 3;
+            break;
     }
 
     // Allocate and initialize base card status.
@@ -3706,16 +3925,79 @@
 #endif
 }
 
+static void onInterfaceAddressChange(unsigned int ifIndex,
+                                     const struct ifAddress* addresses,
+                                     size_t numAddresses) {
+    char ifName[IF_NAMESIZE];
+    size_t i;
+    bool hasWifi = hasWifiCapability();
+    const char* radioIfName = getRadioInterfaceName(hasWifi);
+    char* currentLoc;
+    size_t remaining;
+
+    if (if_indextoname(ifIndex, ifName) == NULL) {
+        RLOGE("Unable to get interface name for interface %u", ifIndex);
+        return;
+    }
+    if (strcmp(radioIfName, ifName) != 0) {
+        // This is not for the radio interface, ignore it
+        return;
+    }
+
+    pthread_mutex_lock(&s_ipv6_addresses_mutex);
+    // Clear out any existing addresses, we receive a full set of addresses
+    // that are going to replace the existing ones.
+    s_ipv6_addresses[0] = '\0';
+    currentLoc = s_ipv6_addresses;
+    remaining = sizeof(s_ipv6_addresses);
+    for (i = 0; i < numAddresses; ++i) {
+        if (addresses[i].family != AF_INET6) {
+            // Only care about IPv6 addresses
+            continue;
+        }
+        char address[INET6_ADDRSTRLEN];
+        if (inet_ntop(addresses[i].family, &addresses[i].addr,
+                      address, sizeof(address))) {
+            int printed = 0;
+            if (s_ipv6_addresses[0]) {
+                // We've already printed something, separate them
+                if (remaining < 1) {
+                    continue;
+                }
+                *currentLoc++ = ' ';
+                --remaining;
+            }
+            printed = snprintf(currentLoc, remaining, "%s/%d",
+                               address, addresses[i].prefix);
+            if (printed > 0) {
+                remaining -= (size_t)printed;
+                currentLoc += printed;
+            }
+        } else {
+            RLOGE("Unable to convert address to string for if %s", ifName);
+        }
+    }
+    pthread_mutex_unlock(&s_ipv6_addresses_mutex);
+
+    // Send unsolicited call list change to notify upper layers about the new
+    // addresses
+    requestOrSendDataCallList(NULL);
+}
+
 static void *
 mainLoop(void *param __unused)
 {
     int fd;
     int ret;
+    struct ifMonitor* monitor = ifMonitorCreate();
 
     AT_DUMP("== ", "entering mainLoop()", -1 );
     at_set_on_reader_closed(onATReaderClosed);
     at_set_on_timeout(onATTimeout);
 
+    ifMonitorSetCallback(monitor, &onInterfaceAddressChange);
+    ifMonitorRunAsync(monitor);
+
     for (;;) {
         fd = -1;
         while  (fd < 0) {
@@ -3739,20 +4021,21 @@
             }
 
             if (fd < 0) {
-                perror ("opening AT interface. retrying...");
+                RLOGE("Error opening AT interface, retrying...");
                 sleep(10);
                 /* never returns */
             }
         }
 
         s_closed = 0;
-        ret = at_open(fd, onUnsolicited);
 
+        ret = at_open(fd, onUnsolicited);
         if (ret < 0) {
             RLOGE ("AT error %d on at_open\n", ret);
-            return 0;
+            break;
         }
 
+
         RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
 
         // Give initializeCallback a chance to dispatched, since
@@ -3762,6 +4045,11 @@
         waitForClose();
         RLOGI("Re-opening after close");
     }
+
+    ifMonitorStop(monitor);
+    ifMonitorFree(monitor);
+
+    return NULL;
 }
 
 #ifdef RIL_SHLIB
diff --git a/sepolicy/common/ipv6proxy.te b/sepolicy/common/ipv6proxy.te
index 22976fe..1defe10 100644
--- a/sepolicy/common/ipv6proxy.te
+++ b/sepolicy/common/ipv6proxy.te
@@ -9,6 +9,7 @@
 domain_auto_trans(execns, ipv6proxy_exec, ipv6proxy);
 allow ipv6proxy execns:fd use;
 
+set_prop(ipv6proxy, net_eth0_prop);
 allow ipv6proxy self:capability { sys_admin sys_module net_admin net_raw };
 allow ipv6proxy self:packet_socket { bind create read };
 allow ipv6proxy self:netlink_route_socket nlmsg_write;
diff --git a/wifi/ipv6proxy/log.h b/wifi/ipv6proxy/log.h
index 527be29..53e8935 100644
--- a/wifi/ipv6proxy/log.h
+++ b/wifi/ipv6proxy/log.h
@@ -18,7 +18,7 @@
 #ifdef ANDROID
 
 #define LOG_TAG "ipv6proxy"
-#include <cutils/log.h>
+#include <log/log.h>
 
 #define loge(...) ALOGE(__VA_ARGS__)
 #define logd(...) ALOGD(__VA_ARGS__)
diff --git a/wifi/ipv6proxy/proxy.cpp b/wifi/ipv6proxy/proxy.cpp
index 08fc0ed..cb19ff7 100644
--- a/wifi/ipv6proxy/proxy.cpp
+++ b/wifi/ipv6proxy/proxy.cpp
@@ -16,11 +16,14 @@
 
 #include "proxy.h"
 
+#include <arpa/inet.h>
 #include <errno.h>
 #include <linux/if_packet.h>
 #include <poll.h>
 #include <signal.h>
 
+#include <cutils/properties.h>
+
 #include "log.h"
 #include "message.h"
 #include "packet.h"
@@ -29,6 +32,7 @@
 // The prefix length for an address of a single unique node
 static const uint8_t kNodePrefixLength = 128;
 static const size_t kLinkAddressSize = 6;
+static const size_t kRecursiveDnsOptHeaderSize = 8;
 
 // Rewrite the link address of a neighbor discovery option to the link address
 // of |interface|. This can be either a source or target link address as
@@ -46,6 +50,45 @@
     }
 }
 
+static void extractRecursiveDnsServers(Packet& packet) {
+    for (nd_opt_hdr* opt = packet.firstOpt(); opt; opt = packet.nextOpt(opt)) {
+        if (opt->nd_opt_type != 25 || opt->nd_opt_len < 1) {
+            // Not a RNDSS option, skip it
+            continue;
+        }
+        size_t numEntries = (opt->nd_opt_len - 1) / 2;
+        //Found number of entries, dump  each address
+        const char* option = reinterpret_cast<const char*>(opt);
+        option += kRecursiveDnsOptHeaderSize;
+        auto dnsServers = reinterpret_cast<const struct in6_addr*>(option);
+
+        std::vector<std::string> validServers;
+        for (size_t i = 0; i < numEntries; ++i) {
+            char buffer[INET6_ADDRSTRLEN];
+            if (inet_ntop(AF_INET6, &dnsServers[i], buffer, sizeof(buffer))) {
+                validServers.push_back(buffer);
+            } else {
+                loge("Failed to convert RDNSS to string\n");
+            }
+        }
+
+        auto server = validServers.begin();
+        char propName[PROP_NAME_MAX];
+        char propValue[PROP_VALUE_MAX];
+        for (int i = 1; i <= 4; ++i) {
+            snprintf(propName, sizeof(propName), "net.eth0.ipv6dns%d", i);
+            if (server != validServers.end()) {
+                property_set(propName, server->c_str());
+                ++server;
+            } else {
+                // Clear the property if it's no longer a valid server, don't
+                // want to leave old servers around
+                property_set(propName, "");
+            }
+        }
+    }
+}
+
 int Proxy::run() {
     sigset_t blockMask, originalMask;
     int status = ::sigfillset(&blockMask);
@@ -128,6 +171,7 @@
     uint32_t options = kForwardOnly;
     switch (packet.type()) {
         case Packet::Type::RouterAdvertisement:
+            extractRecursiveDnsServers(packet);
             options = kRewriteSourceLink | kSetDefaultGateway;
             break;
         case Packet::Type::NeighborSolicitation: