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: