summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2015-03-06 19:57:39 +0900
committerLorenzo Colitti <lorenzo@google.com>2015-03-16 20:08:45 +0900
commit566e0cb692ef8be5ba01c874ebd9d2576be99fe4 (patch)
tree4ce4fe9cd8e0e025b351e64a8a6ab7d0fc89b8df /core
parent5671eedda0e8e5acf63697bd9f4d8c3027440184 (diff)
downloadframeworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.zip
frameworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.tar.gz
frameworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.tar.bz2
DHCP: Add a native method for making a DHCP socket.
Bug: 19704592 Change-Id: Iadd60d39c93aaabd2917e76791101a7d313b34be
Diffstat (limited to 'core')
-rw-r--r--core/java/android/net/NetworkUtils.java7
-rw-r--r--core/jni/android_net_NetUtils.cpp50
2 files changed, 57 insertions, 0 deletions
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4f35a22..01704e5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,9 +16,11 @@
package android.net;
+import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
+import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Locale;
@@ -139,6 +141,11 @@ public class NetworkUtils {
public native static String getDhcpError();
/**
+ * Attaches a socket filter that accepts DHCP packets to the given socket.
+ */
+ public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
+
+ /**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
* {@link Network#getSocketFactory}) will be bound to this network. Note that if this
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index e64f1de..2ba8e8c 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -24,6 +24,14 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/filter.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <net/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
#include <cutils/properties.h>
extern "C" {
@@ -53,6 +61,8 @@ char *dhcp_get_errmsg();
namespace android {
+static const uint16_t kDhcpClientPort = 68;
+
/*
* The following remembers the jfieldID's of the fields
* of the DhcpInfo Java object, so that we don't have
@@ -215,6 +225,44 @@ static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
return env->NewStringUTF(::dhcp_get_errmsg());
}
+static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ uint32_t ip_offset = sizeof(ether_header);
+ uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
+ uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
+ uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
+ struct sock_filter filter_code[] = {
+ // Check the protocol is UDP.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, proto_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
+
+ // Check this is not a fragment.
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, flags_offset),
+ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, 0x1fff, 4, 0),
+
+ // Get the IP header length.
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, ip_offset),
+
+ // Check the destination port.
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, dport_indirect_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ struct sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
{
return (jboolean) !setNetworkForProcess(netId);
@@ -242,6 +290,7 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint
return (jboolean) !protectFromVpn(socket);
}
+
// ----------------------------------------------------------------------------
/*
@@ -261,6 +310,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
+ { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
};
int register_android_net_NetworkUtils(JNIEnv* env)