diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2015-03-10 01:36:14 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2015-03-16 20:08:46 +0900 |
commit | c95a87f30d069472302f90a206e229b82bb2316a (patch) | |
tree | 64a88d2b73fdc93a52887280cad2a88e61662ba0 /services | |
parent | 566e0cb692ef8be5ba01c874ebd9d2576be99fe4 (diff) | |
download | frameworks_base-c95a87f30d069472302f90a206e229b82bb2316a.zip frameworks_base-c95a87f30d069472302f90a206e229b82bb2316a.tar.gz frameworks_base-c95a87f30d069472302f90a206e229b82bb2316a.tar.bz2 |
DHCP: Move the packet code to frameworks/base/services.
There's no need for it to be in frameworks/base/core, since it
will only be used by services.
Bug: 19704592
Change-Id: I2f5277eca848b7000ca46db575e8602eacb5c8bd
Diffstat (limited to 'services')
-rw-r--r-- | services/Android.mk | 1 | ||||
-rw-r--r-- | services/net/Android.mk | 10 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpAckPacket.java | 109 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpDeclinePacket.java | 65 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpDiscoverPacket.java | 71 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpInformPacket.java | 76 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpNakPacket.java | 72 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpOfferPacket.java | 100 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpPacket.java | 896 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpRequestPacket.java | 86 | ||||
-rw-r--r-- | services/net/java/android/net/dhcp/DhcpStateMachine.java | 74 |
11 files changed, 1560 insertions, 0 deletions
diff --git a/services/Android.mk b/services/Android.mk index 3c94f43..e4b0cbb 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -24,6 +24,7 @@ services := \ appwidget \ backup \ devicepolicy \ + net \ print \ restrictions \ usage \ diff --git a/services/net/Android.mk b/services/net/Android.mk new file mode 100644 index 0000000..336bc45 --- /dev/null +++ b/services/net/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.net + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java new file mode 100644 index 0000000..7b8be9c --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-ACK packet. + */ +class DhcpAckPacket extends DhcpPacket { + + /** + * The address of the server which sent this packet. + */ + private final InetAddress mSrcIp; + + DhcpAckPacket(int transId, boolean broadcast, InetAddress serverAddress, + InetAddress clientIp, byte[] clientMac) { + super(transId, Inet4Address.ANY, clientIp, serverAddress, + Inet4Address.ANY, clientMac, broadcast); + mBroadcast = broadcast; + mSrcIp = serverAddress; + } + + public String toString() { + String s = super.toString(); + String dnsServers = " DNS servers: "; + + for (InetAddress dnsServer: mDnsServers) { + dnsServers += dnsServer.toString() + " "; + } + + return s + " ACK: your new IP " + mYourIp + + ", netmask " + mSubnetMask + + ", gateway " + mGateway + dnsServers + + ", lease time " + mLeaseTime; + } + + /** + * Fills in a packet with the requested ACK parameters. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + InetAddress destIp = mBroadcast ? Inet4Address.ALL : mYourIp; + InetAddress srcIp = mBroadcast ? Inet4Address.ANY : mSrcIp; + + fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, + DHCP_BOOTREPLY, mBroadcast); + result.flip(); + return result; + } + + /** + * Adds the optional parameters to the client-generated ACK packet. + */ + void finishPacket(ByteBuffer buffer) { + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK); + addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); + addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime); + + // the client should renew at 1/2 the lease-expiry interval + if (mLeaseTime != null) { + addTlv(buffer, DHCP_RENEWAL_TIME, + Integer.valueOf(mLeaseTime.intValue() / 2)); + } + + addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask); + addTlv(buffer, DHCP_ROUTER, mGateway); + addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName); + addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); + addTlv(buffer, DHCP_DNS_SERVER, mDnsServers); + addTlvEnd(buffer); + } + + /** + * Un-boxes an Integer, returning 0 if a null reference is supplied. + */ + private static final int getInt(Integer v) { + if (v == null) { + return 0; + } else { + return v.intValue(); + } + } + + /** + * Notifies the specified state machine of the ACK packet parameters. + */ + public void doNextOp(DhcpStateMachine machine) { + machine.onAckReceived(mYourIp, mSubnetMask, mGateway, mDnsServers, + mServerIdentifier, getInt(mLeaseTime)); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java new file mode 100644 index 0000000..7646eb4 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-DECLINE packet. + */ +class DhcpDeclinePacket extends DhcpPacket { + /** + * Generates a DECLINE packet with the specified parameters. + */ + DhcpDeclinePacket(int transId, InetAddress clientIp, InetAddress yourIp, + InetAddress nextIp, InetAddress relayIp, + byte[] clientMac) { + super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false); + } + + public String toString() { + String s = super.toString(); + return s + " DECLINE"; + } + + /** + * Fills in a packet with the requested DECLINE attributes. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + + fillInPacket(encap, mClientIp, mYourIp, destUdp, srcUdp, result, + DHCP_BOOTREQUEST, false); + result.flip(); + return result; + } + + /** + * Adds optional parameters to the DECLINE packet. + */ + void finishPacket(ByteBuffer buffer) { + // None needed + } + + /** + * Informs the state machine of the arrival of a DECLINE packet. + */ + public void doNextOp(DhcpStateMachine machine) { + machine.onDeclineReceived(mClientMac, mRequestedIp); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java new file mode 100644 index 0000000..0e2d39b --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-DISCOVER packet. + */ +class DhcpDiscoverPacket extends DhcpPacket { + /** + * Generates a DISCOVER packet with the specified parameters. + */ + DhcpDiscoverPacket(int transId, byte[] clientMac, boolean broadcast) { + super(transId, Inet4Address.ANY, Inet4Address.ANY, Inet4Address.ANY, + Inet4Address.ANY, clientMac, broadcast); + } + + public String toString() { + String s = super.toString(); + return s + " DISCOVER " + + (mBroadcast ? "broadcast " : "unicast "); + } + + /** + * Fills in a packet with the requested DISCOVER parameters. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + InetAddress destIp = Inet4Address.ALL; + + fillInPacket(encap, Inet4Address.ALL, Inet4Address.ANY, destUdp, srcUdp, + result, DHCP_BOOTREQUEST, true); + result.flip(); + return result; + } + + /** + * Adds optional parameters to a DISCOVER packet. + */ + void finishPacket(ByteBuffer buffer) { + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DISCOVER); + addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams); + addTlvEnd(buffer); + } + + /** + * Informs the state machine of the arrival of a DISCOVER packet. + */ + public void doNextOp(DhcpStateMachine machine) { + // currently omitted: host name + machine.onDiscoverReceived(mBroadcast, mTransId, mClientMac, + mRequestedParams); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpInformPacket.java b/services/net/java/android/net/dhcp/DhcpInformPacket.java new file mode 100644 index 0000000..da73216 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpInformPacket.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.nio.ByteBuffer; + +/** + * This class implements the (unused) DHCP-INFORM packet. + */ +class DhcpInformPacket extends DhcpPacket { + /** + * Generates an INFORM packet with the specified parameters. + */ + DhcpInformPacket(int transId, InetAddress clientIp, InetAddress yourIp, + InetAddress nextIp, InetAddress relayIp, + byte[] clientMac) { + super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false); + } + + public String toString() { + String s = super.toString(); + return s + " INFORM"; + } + + /** + * Builds an INFORM packet. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + + fillInPacket(encap, mClientIp, mYourIp, destUdp, srcUdp, result, + DHCP_BOOTREQUEST, false); + result.flip(); + return result; + } + + /** + * Adds additional parameters to the INFORM packet. + */ + void finishPacket(ByteBuffer buffer) { + byte[] clientId = new byte[7]; + + clientId[0] = CLIENT_ID_ETHER; + System.arraycopy(mClientMac, 0, clientId, 1, 6); + + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST); + addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams); + addTlvEnd(buffer); + } + + /** + * Informs the state machine of the arrival of an INFORM packet. Not + * used currently. + */ + public void doNextOp(DhcpStateMachine machine) { + InetAddress clientRequest = + mRequestedIp == null ? mClientIp : mRequestedIp; + machine.onInformReceived(mTransId, mClientMac, clientRequest, + mRequestedParams); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java new file mode 100644 index 0000000..1f340ad --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-NAK packet. + */ +class DhcpNakPacket extends DhcpPacket { + /** + * Generates a NAK packet with the specified parameters. + */ + DhcpNakPacket(int transId, InetAddress clientIp, InetAddress yourIp, + InetAddress nextIp, InetAddress relayIp, + byte[] clientMac) { + super(transId, Inet4Address.ANY, Inet4Address.ANY, nextIp, relayIp, + clientMac, false); + } + + public String toString() { + String s = super.toString(); + return s + " NAK, reason " + (mMessage == null ? "(none)" : mMessage); + } + + /** + * Fills in a packet with the requested NAK attributes. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + InetAddress destIp = mClientIp; + InetAddress srcIp = mYourIp; + + fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, + DHCP_BOOTREPLY, mBroadcast); + result.flip(); + return result; + } + + /** + * Adds the optional parameters to the client-generated NAK packet. + */ + void finishPacket(ByteBuffer buffer) { + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_NAK); + addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); + addTlv(buffer, DHCP_MESSAGE, mMessage); + addTlvEnd(buffer); + } + + /** + * Notifies the specified state machine of the newly-arrived NAK packet. + */ + public void doNextOp(DhcpStateMachine machine) { + machine.onNakReceived(); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java new file mode 100644 index 0000000..f1c30e1 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-OFFER packet. + */ +class DhcpOfferPacket extends DhcpPacket { + /** + * The IP address of the server which sent this packet. + */ + private final InetAddress mSrcIp; + + /** + * Generates a OFFER packet with the specified parameters. + */ + DhcpOfferPacket(int transId, boolean broadcast, InetAddress serverAddress, + InetAddress clientIp, byte[] clientMac) { + super(transId, Inet4Address.ANY, clientIp, Inet4Address.ANY, + Inet4Address.ANY, clientMac, broadcast); + mSrcIp = serverAddress; + } + + public String toString() { + String s = super.toString(); + String dnsServers = ", DNS servers: "; + + if (mDnsServers != null) { + for (InetAddress dnsServer: mDnsServers) { + dnsServers += dnsServer + " "; + } + } + + return s + " OFFER, ip " + mYourIp + ", mask " + mSubnetMask + + dnsServers + ", gateway " + mGateway + + " lease time " + mLeaseTime + ", domain " + mDomainName; + } + + /** + * Fills in a packet with the specified OFFER attributes. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + InetAddress destIp = mBroadcast ? Inet4Address.ALL : mYourIp; + InetAddress srcIp = mBroadcast ? Inet4Address.ANY : mSrcIp; + + fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, + DHCP_BOOTREPLY, mBroadcast); + result.flip(); + return result; + } + + /** + * Adds the optional parameters to the server-generated OFFER packet. + */ + void finishPacket(ByteBuffer buffer) { + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_OFFER); + addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); + addTlv(buffer, DHCP_LEASE_TIME, mLeaseTime); + + // the client should renew at 1/2 the lease-expiry interval + if (mLeaseTime != null) { + addTlv(buffer, DHCP_RENEWAL_TIME, + Integer.valueOf(mLeaseTime.intValue() / 2)); + } + + addTlv(buffer, DHCP_SUBNET_MASK, mSubnetMask); + addTlv(buffer, DHCP_ROUTER, mGateway); + addTlv(buffer, DHCP_DOMAIN_NAME, mDomainName); + addTlv(buffer, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); + addTlv(buffer, DHCP_DNS_SERVER, mDnsServers); + addTlvEnd(buffer); + } + + /** + * Notifies the state machine of the OFFER packet parameters. + */ + public void doNextOp(DhcpStateMachine machine) { + machine.onOfferReceived(mBroadcast, mTransId, mClientMac, mYourIp, + mServerIdentifier); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java new file mode 100644 index 0000000..68108fe --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -0,0 +1,896 @@ +package android.net.dhcp; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.nio.ShortBuffer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Defines basic data and operations needed to build and use packets for the + * DHCP protocol. Subclasses create the specific packets used at each + * stage of the negotiation. + */ +abstract class DhcpPacket { + protected static final String TAG = "DhcpPacket"; + + /** + * Packet encapsulations. + */ + public static final int ENCAP_L2 = 0; // EthernetII header included + public static final int ENCAP_L3 = 1; // IP/UDP header included + public static final int ENCAP_BOOTP = 2; // BOOTP contents only + + /** + * IP layer definitions. + */ + private static final byte IP_TYPE_UDP = (byte) 0x11; + + /** + * IP: Version 4, Header Length 20 bytes + */ + private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45; + + /** + * IP: Flags 0, Fragment Offset 0, Don't Fragment + */ + private static final short IP_FLAGS_OFFSET = (short) 0x4000; + + /** + * IP: TOS + */ + private static final byte IP_TOS_LOWDELAY = (byte) 0x10; + + /** + * IP: TTL -- use default 64 from RFC1340 + */ + private static final byte IP_TTL = (byte) 0x40; + + /** + * The client DHCP port. + */ + static final short DHCP_CLIENT = (short) 68; + + /** + * The server DHCP port. + */ + static final short DHCP_SERVER = (short) 67; + + /** + * The message op code indicating a request from a client. + */ + protected static final byte DHCP_BOOTREQUEST = (byte) 1; + + /** + * The message op code indicating a response from the server. + */ + protected static final byte DHCP_BOOTREPLY = (byte) 2; + + /** + * The code type used to identify an Ethernet MAC address in the + * Client-ID field. + */ + protected static final byte CLIENT_ID_ETHER = (byte) 1; + + /** + * The maximum length of a packet that can be constructed. + */ + protected static final int MAX_LENGTH = 1500; + + /** + * DHCP Optional Type: DHCP Subnet Mask + */ + protected static final byte DHCP_SUBNET_MASK = 1; + protected InetAddress mSubnetMask; + + /** + * DHCP Optional Type: DHCP Router + */ + protected static final byte DHCP_ROUTER = 3; + protected InetAddress mGateway; + + /** + * DHCP Optional Type: DHCP DNS Server + */ + protected static final byte DHCP_DNS_SERVER = 6; + protected List<InetAddress> mDnsServers; + + /** + * DHCP Optional Type: DHCP Host Name + */ + protected static final byte DHCP_HOST_NAME = 12; + protected String mHostName; + + /** + * DHCP Optional Type: DHCP DOMAIN NAME + */ + protected static final byte DHCP_DOMAIN_NAME = 15; + protected String mDomainName; + + /** + * DHCP Optional Type: DHCP BROADCAST ADDRESS + */ + protected static final byte DHCP_BROADCAST_ADDRESS = 28; + protected InetAddress mBroadcastAddress; + + /** + * DHCP Optional Type: DHCP Requested IP Address + */ + protected static final byte DHCP_REQUESTED_IP = 50; + protected InetAddress mRequestedIp; + + /** + * DHCP Optional Type: DHCP Lease Time + */ + protected static final byte DHCP_LEASE_TIME = 51; + protected Integer mLeaseTime; + + /** + * DHCP Optional Type: DHCP Message Type + */ + protected static final byte DHCP_MESSAGE_TYPE = 53; + // the actual type values + protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1; + protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2; + protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3; + protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; + protected static final byte DHCP_MESSAGE_TYPE_ACK = 5; + protected static final byte DHCP_MESSAGE_TYPE_NAK = 6; + protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8; + + /** + * DHCP Optional Type: DHCP Server Identifier + */ + protected static final byte DHCP_SERVER_IDENTIFIER = 54; + protected InetAddress mServerIdentifier; + + /** + * DHCP Optional Type: DHCP Parameter List + */ + protected static final byte DHCP_PARAMETER_LIST = 55; + protected byte[] mRequestedParams; + + /** + * DHCP Optional Type: DHCP MESSAGE + */ + protected static final byte DHCP_MESSAGE = 56; + protected String mMessage; + + /** + * DHCP Optional Type: DHCP Renewal Time Value + */ + protected static final byte DHCP_RENEWAL_TIME = 58; + + /** + * DHCP Optional Type: Vendor Class Identifier + */ + protected static final byte DHCP_VENDOR_CLASS_ID = 60; + + /** + * DHCP Optional Type: DHCP Client Identifier + */ + protected static final byte DHCP_CLIENT_IDENTIFIER = 61; + + /** + * The transaction identifier used in this particular DHCP negotiation + */ + protected final int mTransId; + + /** + * The IP address of the client host. This address is typically + * proposed by the client (from an earlier DHCP negotiation) or + * supplied by the server. + */ + protected final InetAddress mClientIp; + protected final InetAddress mYourIp; + private final InetAddress mNextIp; + private final InetAddress mRelayIp; + + /** + * Does the client request a broadcast response? + */ + protected boolean mBroadcast; + + /** + * The six-octet MAC of the client. + */ + protected final byte[] mClientMac; + + /** + * Asks the packet object to signal the next operation in the DHCP + * protocol. The available actions are methods defined in the + * DhcpStateMachine interface. + */ + public abstract void doNextOp(DhcpStateMachine stateMachine); + + /** + * Asks the packet object to create a ByteBuffer serialization of + * the packet for transmission. + */ + public abstract ByteBuffer buildPacket(int encap, short destUdp, + short srcUdp); + + /** + * Allows the concrete class to fill in packet-type-specific details, + * typically optional parameters at the end of the packet. + */ + abstract void finishPacket(ByteBuffer buffer); + + protected DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp, + InetAddress nextIp, InetAddress relayIp, + byte[] clientMac, boolean broadcast) { + mTransId = transId; + mClientIp = clientIp; + mYourIp = yourIp; + mNextIp = nextIp; + mRelayIp = relayIp; + mClientMac = clientMac; + mBroadcast = broadcast; + } + + /** + * Returns the transaction ID. + */ + public int getTransactionId() { + return mTransId; + } + + /** + * Creates a new L3 packet (including IP header) containing the + * DHCP udp packet. This method relies upon the delegated method + * finishPacket() to insert the per-packet contents. + */ + protected void fillInPacket(int encap, InetAddress destIp, + InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf, + byte requestCode, boolean broadcast) { + byte[] destIpArray = destIp.getAddress(); + byte[] srcIpArray = srcIp.getAddress(); + int ipLengthOffset = 0; + int ipChecksumOffset = 0; + int endIpHeader = 0; + int udpHeaderOffset = 0; + int udpLengthOffset = 0; + int udpChecksumOffset = 0; + + buf.clear(); + buf.order(ByteOrder.BIG_ENDIAN); + + // if a full IP packet needs to be generated, put the IP & UDP + // headers in place, and pre-populate with artificial values + // needed to seed the IP checksum. + if (encap == ENCAP_L3) { + // fake IP header, used in the IP-header checksum + buf.put(IP_VERSION_HEADER_LEN); + buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY + ipLengthOffset = buf.position(); + buf.putShort((short)0); // length + buf.putShort((short)0); // id + buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment + buf.put(IP_TTL); // TTL: use default 64 from RFC1340 + buf.put(IP_TYPE_UDP); + ipChecksumOffset = buf.position(); + buf.putShort((short) 0); // checksum + + buf.put(srcIpArray); + buf.put(destIpArray); + endIpHeader = buf.position(); + + // UDP header + udpHeaderOffset = buf.position(); + buf.putShort(srcUdp); + buf.putShort(destUdp); + udpLengthOffset = buf.position(); + buf.putShort((short) 0); // length + udpChecksumOffset = buf.position(); + buf.putShort((short) 0); // UDP checksum -- initially zero + } + + // DHCP payload + buf.put(requestCode); + buf.put((byte) 1); // Hardware Type: Ethernet + buf.put((byte) mClientMac.length); // Hardware Address Length + buf.put((byte) 0); // Hop Count + buf.putInt(mTransId); // Transaction ID + buf.putShort((short) 0); // Elapsed Seconds + + if (broadcast) { + buf.putShort((short) 0x8000); // Flags + } else { + buf.putShort((short) 0x0000); // Flags + } + + buf.put(mClientIp.getAddress()); + buf.put(mYourIp.getAddress()); + buf.put(mNextIp.getAddress()); + buf.put(mRelayIp.getAddress()); + buf.put(mClientMac); + buf.position(buf.position() + + (16 - mClientMac.length) // pad addr to 16 bytes + + 64 // empty server host name (64 bytes) + + 128); // empty boot file name (128 bytes) + buf.putInt(0x63825363); // magic number + finishPacket(buf); + + // round up to an even number of octets + if ((buf.position() & 1) == 1) { + buf.put((byte) 0); + } + + // If an IP packet is being built, the IP & UDP checksums must be + // computed. + if (encap == ENCAP_L3) { + // fix UDP header: insert length + short udpLen = (short)(buf.position() - udpHeaderOffset); + buf.putShort(udpLengthOffset, udpLen); + // fix UDP header: checksum + // checksum for UDP at udpChecksumOffset + int udpSeed = 0; + + // apply IPv4 pseudo-header. Read IP address src and destination + // values from the IP header and accumulate checksum. + udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2)); + udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4)); + udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6)); + udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8)); + + // accumulate extra data for the pseudo-header + udpSeed += IP_TYPE_UDP; + udpSeed += udpLen; + // and compute UDP checksum + buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed, + udpHeaderOffset, + buf.position())); + // fix IP header: insert length + buf.putShort(ipLengthOffset, (short)buf.position()); + // fixup IP-header checksum + buf.putShort(ipChecksumOffset, + (short) checksum(buf, 0, 0, endIpHeader)); + } + } + + /** + * Converts a signed short value to an unsigned int value. Needed + * because Java does not have unsigned types. + */ + private int intAbs(short v) { + if (v < 0) { + int r = v + 65536; + return r; + } else { + return(v); + } + } + + /** + * Performs an IP checksum (used in IP header and across UDP + * payload) on the specified portion of a ByteBuffer. The seed + * allows the checksum to commence with a specified value. + */ + private int checksum(ByteBuffer buf, int seed, int start, int end) { + int sum = seed; + int bufPosition = buf.position(); + + // set position of original ByteBuffer, so that the ShortBuffer + // will be correctly initialized + buf.position(start); + ShortBuffer shortBuf = buf.asShortBuffer(); + + // re-set ByteBuffer position + buf.position(bufPosition); + + short[] shortArray = new short[(end - start) / 2]; + shortBuf.get(shortArray); + + for (short s : shortArray) { + sum += intAbs(s); + } + + start += shortArray.length * 2; + + // see if a singleton byte remains + if (end != start) { + short b = buf.get(start); + + // make it unsigned + if (b < 0) { + b += 256; + } + + sum += b * 256; + } + + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); + sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); + int negated = ~sum; + return intAbs((short) negated); + } + + /** + * Adds an optional parameter containing a single byte value. + */ + protected void addTlv(ByteBuffer buf, byte type, byte value) { + buf.put(type); + buf.put((byte) 1); + buf.put(value); + } + + /** + * Adds an optional parameter containing an array of bytes. + */ + protected void addTlv(ByteBuffer buf, byte type, byte[] payload) { + if (payload != null) { + buf.put(type); + buf.put((byte) payload.length); + buf.put(payload); + } + } + + /** + * Adds an optional parameter containing an IP address. + */ + protected void addTlv(ByteBuffer buf, byte type, InetAddress addr) { + if (addr != null) { + addTlv(buf, type, addr.getAddress()); + } + } + + /** + * Adds an optional parameter containing a list of IP addresses. + */ + protected void addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs) { + if (addrs != null && addrs.size() > 0) { + buf.put(type); + buf.put((byte)(4 * addrs.size())); + + for (InetAddress addr : addrs) { + buf.put(addr.getAddress()); + } + } + } + + /** + * Adds an optional parameter containing a simple integer + */ + protected void addTlv(ByteBuffer buf, byte type, Integer value) { + if (value != null) { + buf.put(type); + buf.put((byte) 4); + buf.putInt(value.intValue()); + } + } + + /** + * Adds an optional parameter containing and ASCII string. + */ + protected void addTlv(ByteBuffer buf, byte type, String str) { + if (str != null) { + buf.put(type); + buf.put((byte) str.length()); + + for (int i = 0; i < str.length(); i++) { + buf.put((byte) str.charAt(i)); + } + } + } + + /** + * Adds the special end-of-optional-parameters indicator. + */ + protected void addTlvEnd(ByteBuffer buf) { + buf.put((byte) 0xFF); + } + + /** + * Converts a MAC from an array of octets to an ASCII string. + */ + public static String macToString(byte[] mac) { + String macAddr = ""; + + for (int i = 0; i < mac.length; i++) { + String hexString = "0" + Integer.toHexString(mac[i]); + + // substring operation grabs the last 2 digits: this + // allows signed bytes to be converted correctly. + macAddr += hexString.substring(hexString.length() - 2); + + if (i != (mac.length - 1)) { + macAddr += ":"; + } + } + + return macAddr; + } + + public String toString() { + String macAddr = macToString(mClientMac); + + return macAddr; + } + + /** + * Reads a four-octet value from a ByteBuffer and construct + * an IPv4 address from that value. + */ + private static InetAddress readIpAddress(ByteBuffer packet) { + InetAddress result = null; + byte[] ipAddr = new byte[4]; + packet.get(ipAddr); + + try { + result = InetAddress.getByAddress(ipAddr); + } catch (UnknownHostException ex) { + // ipAddr is numeric, so this should not be + // triggered. However, if it is, just nullify + result = null; + } + + return result; + } + + /** + * Reads a string of specified length from the buffer. + */ + private static String readAsciiString(ByteBuffer buf, int byteCount) { + byte[] bytes = new byte[byteCount]; + buf.get(bytes); + return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII); + } + + /** + * Creates a concrete DhcpPacket from the supplied ByteBuffer. The + * buffer may have an L2 encapsulation (which is the full EthernetII + * format starting with the source-address MAC) or an L3 encapsulation + * (which starts with the IP header). + * <br> + * A subset of the optional parameters are parsed and are stored + * in object fields. + */ + public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) + { + // bootp parameters + int transactionId; + InetAddress clientIp; + InetAddress yourIp; + InetAddress nextIp; + InetAddress relayIp; + byte[] clientMac; + List<InetAddress> dnsServers = new ArrayList<InetAddress>(); + InetAddress gateway = null; // aka router + Integer leaseTime = null; + InetAddress serverIdentifier = null; + InetAddress netMask = null; + String message = null; + String vendorId = null; + byte[] expectedParams = null; + String hostName = null; + String domainName = null; + InetAddress ipSrc = null; + InetAddress ipDst = null; + InetAddress bcAddr = null; + InetAddress requestedIp = null; + + // dhcp options + byte dhcpType = (byte) 0xFF; + + packet.order(ByteOrder.BIG_ENDIAN); + + // check to see if we need to parse L2, IP, and UDP encaps + if (pktType == ENCAP_L2) { + // System.out.println("buffer len " + packet.limit()); + byte[] l2dst = new byte[6]; + byte[] l2src = new byte[6]; + + packet.get(l2dst); + packet.get(l2src); + + short l2type = packet.getShort(); + + if (l2type != 0x0800) + return null; + } + + if ((pktType == ENCAP_L2) || (pktType == ENCAP_L3)) { + // assume l2type is 0x0800, i.e. IP + byte ipType = packet.get(); + // System.out.println("ipType is " + ipType); + byte ipDiffServicesField = packet.get(); + short ipTotalLength = packet.getShort(); + short ipIdentification = packet.getShort(); + byte ipFlags = packet.get(); + byte ipFragOffset = packet.get(); + byte ipTTL = packet.get(); + byte ipProto = packet.get(); + short ipChksm = packet.getShort(); + + ipSrc = readIpAddress(packet); + ipDst = readIpAddress(packet); + + if (ipProto != IP_TYPE_UDP) // UDP + return null; + + // assume UDP + short udpSrcPort = packet.getShort(); + short udpDstPort = packet.getShort(); + short udpLen = packet.getShort(); + short udpChkSum = packet.getShort(); + + if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT)) + return null; + } + + // assume bootp + byte type = packet.get(); + byte hwType = packet.get(); + byte addrLen = packet.get(); + byte hops = packet.get(); + transactionId = packet.getInt(); + short elapsed = packet.getShort(); + short bootpFlags = packet.getShort(); + boolean broadcast = (bootpFlags & 0x8000) != 0; + byte[] ipv4addr = new byte[4]; + + try { + packet.get(ipv4addr); + clientIp = InetAddress.getByAddress(ipv4addr); + packet.get(ipv4addr); + yourIp = InetAddress.getByAddress(ipv4addr); + packet.get(ipv4addr); + nextIp = InetAddress.getByAddress(ipv4addr); + packet.get(ipv4addr); + relayIp = InetAddress.getByAddress(ipv4addr); + } catch (UnknownHostException ex) { + return null; + } + + clientMac = new byte[addrLen]; + packet.get(clientMac); + + // skip over address padding (16 octets allocated) + packet.position(packet.position() + (16 - addrLen) + + 64 // skip server host name (64 chars) + + 128); // skip boot file name (128 chars) + + int dhcpMagicCookie = packet.getInt(); + + if (dhcpMagicCookie != 0x63825363) + return null; + + // parse options + boolean notFinishedOptions = true; + + while ((packet.position() < packet.limit()) && notFinishedOptions) { + byte optionType = packet.get(); + + if (optionType == (byte) 0xFF) { + notFinishedOptions = false; + } else { + byte optionLen = packet.get(); + int expectedLen = 0; + + switch(optionType) { + case DHCP_SUBNET_MASK: + netMask = readIpAddress(packet); + expectedLen = 4; + break; + case DHCP_ROUTER: + gateway = readIpAddress(packet); + expectedLen = 4; + break; + case DHCP_DNS_SERVER: + expectedLen = 0; + + for (expectedLen = 0; expectedLen < optionLen; + expectedLen += 4) { + dnsServers.add(readIpAddress(packet)); + } + break; + case DHCP_HOST_NAME: + expectedLen = optionLen; + hostName = readAsciiString(packet, optionLen); + break; + case DHCP_DOMAIN_NAME: + expectedLen = optionLen; + domainName = readAsciiString(packet, optionLen); + break; + case DHCP_BROADCAST_ADDRESS: + bcAddr = readIpAddress(packet); + expectedLen = 4; + break; + case DHCP_REQUESTED_IP: + requestedIp = readIpAddress(packet); + expectedLen = 4; + break; + case DHCP_LEASE_TIME: + leaseTime = Integer.valueOf(packet.getInt()); + expectedLen = 4; + break; + case DHCP_MESSAGE_TYPE: + dhcpType = packet.get(); + expectedLen = 1; + break; + case DHCP_SERVER_IDENTIFIER: + serverIdentifier = readIpAddress(packet); + expectedLen = 4; + break; + case DHCP_PARAMETER_LIST: + expectedParams = new byte[optionLen]; + packet.get(expectedParams); + expectedLen = optionLen; + break; + case DHCP_MESSAGE: + expectedLen = optionLen; + message = readAsciiString(packet, optionLen); + break; + case DHCP_VENDOR_CLASS_ID: + expectedLen = optionLen; + vendorId = readAsciiString(packet, optionLen); + break; + case DHCP_CLIENT_IDENTIFIER: { // Client identifier + byte[] id = new byte[optionLen]; + packet.get(id); + expectedLen = optionLen; + } break; + default: + // ignore any other parameters + for (int i = 0; i < optionLen; i++) { + expectedLen++; + byte throwaway = packet.get(); + } + } + + if (expectedLen != optionLen) { + return null; + } + } + } + + DhcpPacket newPacket; + + switch(dhcpType) { + case -1: return null; + case DHCP_MESSAGE_TYPE_DISCOVER: + newPacket = new DhcpDiscoverPacket( + transactionId, clientMac, broadcast); + break; + case DHCP_MESSAGE_TYPE_OFFER: + newPacket = new DhcpOfferPacket( + transactionId, broadcast, ipSrc, yourIp, clientMac); + break; + case DHCP_MESSAGE_TYPE_REQUEST: + newPacket = new DhcpRequestPacket( + transactionId, clientIp, clientMac, broadcast); + break; + case DHCP_MESSAGE_TYPE_DECLINE: + newPacket = new DhcpDeclinePacket( + transactionId, clientIp, yourIp, nextIp, relayIp, + clientMac); + break; + case DHCP_MESSAGE_TYPE_ACK: + newPacket = new DhcpAckPacket( + transactionId, broadcast, ipSrc, yourIp, clientMac); + break; + case DHCP_MESSAGE_TYPE_NAK: + newPacket = new DhcpNakPacket( + transactionId, clientIp, yourIp, nextIp, relayIp, + clientMac); + break; + case DHCP_MESSAGE_TYPE_INFORM: + newPacket = new DhcpInformPacket( + transactionId, clientIp, yourIp, nextIp, relayIp, + clientMac); + break; + default: + System.out.println("Unimplemented type: " + dhcpType); + return null; + } + + newPacket.mBroadcastAddress = bcAddr; + newPacket.mDnsServers = dnsServers; + newPacket.mDomainName = domainName; + newPacket.mGateway = gateway; + newPacket.mHostName = hostName; + newPacket.mLeaseTime = leaseTime; + newPacket.mMessage = message; + newPacket.mRequestedIp = requestedIp; + newPacket.mRequestedParams = expectedParams; + newPacket.mServerIdentifier = serverIdentifier; + newPacket.mSubnetMask = netMask; + return newPacket; + } + + /** + * Parse a packet from an array of bytes. + */ + public static DhcpPacket decodeFullPacket(byte[] packet, int pktType) + { + ByteBuffer buffer = ByteBuffer.wrap(packet).order(ByteOrder.BIG_ENDIAN); + return decodeFullPacket(buffer, pktType); + } + + /** + * Builds a DHCP-DISCOVER packet from the required specified + * parameters. + */ + public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, + byte[] clientMac, boolean broadcast, byte[] expectedParams) { + DhcpPacket pkt = new DhcpDiscoverPacket( + transactionId, clientMac, broadcast); + pkt.mRequestedParams = expectedParams; + return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); + } + + /** + * Builds a DHCP-OFFER packet from the required specified + * parameters. + */ + public static ByteBuffer buildOfferPacket(int encap, int transactionId, + boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, + byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, + InetAddress gateway, List<InetAddress> dnsServers, + InetAddress dhcpServerIdentifier, String domainName) { + DhcpPacket pkt = new DhcpOfferPacket( + transactionId, broadcast, serverIpAddr, clientIpAddr, mac); + pkt.mGateway = gateway; + pkt.mDnsServers = dnsServers; + pkt.mLeaseTime = timeout; + pkt.mDomainName = domainName; + pkt.mServerIdentifier = dhcpServerIdentifier; + pkt.mSubnetMask = netMask; + pkt.mBroadcastAddress = bcAddr; + return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); + } + + /** + * Builds a DHCP-ACK packet from the required specified parameters. + */ + public static ByteBuffer buildAckPacket(int encap, int transactionId, + boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, + byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, + InetAddress gateway, List<InetAddress> dnsServers, + InetAddress dhcpServerIdentifier, String domainName) { + DhcpPacket pkt = new DhcpAckPacket( + transactionId, broadcast, serverIpAddr, clientIpAddr, mac); + pkt.mGateway = gateway; + pkt.mDnsServers = dnsServers; + pkt.mLeaseTime = timeout; + pkt.mDomainName = domainName; + pkt.mSubnetMask = netMask; + pkt.mServerIdentifier = dhcpServerIdentifier; + pkt.mBroadcastAddress = bcAddr; + return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); + } + + /** + * Builds a DHCP-NAK packet from the required specified parameters. + */ + public static ByteBuffer buildNakPacket(int encap, int transactionId, + InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac) { + DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr, + serverIpAddr, serverIpAddr, serverIpAddr, mac); + pkt.mMessage = "requested address not available"; + pkt.mRequestedIp = clientIpAddr; + return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); + } + + /** + * Builds a DHCP-REQUEST packet from the required specified parameters. + */ + public static ByteBuffer buildRequestPacket(int encap, + int transactionId, InetAddress clientIp, boolean broadcast, + byte[] clientMac, InetAddress requestedIpAddress, + InetAddress serverIdentifier, byte[] requestedParams, String hostName) { + DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp, + clientMac, broadcast); + pkt.mRequestedIp = requestedIpAddress; + pkt.mServerIdentifier = serverIdentifier; + pkt.mHostName = hostName; + pkt.mRequestedParams = requestedParams; + ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); + return result; + } +} diff --git a/services/net/java/android/net/dhcp/DhcpRequestPacket.java b/services/net/java/android/net/dhcp/DhcpRequestPacket.java new file mode 100644 index 0000000..cf32957 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import android.util.Log; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * This class implements the DHCP-REQUEST packet. + */ +class DhcpRequestPacket extends DhcpPacket { + /** + * Generates a REQUEST packet with the specified parameters. + */ + DhcpRequestPacket(int transId, InetAddress clientIp, byte[] clientMac, + boolean broadcast) { + super(transId, clientIp, Inet4Address.ANY, Inet4Address.ANY, + Inet4Address.ANY, clientMac, broadcast); + } + + public String toString() { + String s = super.toString(); + return s + " REQUEST, desired IP " + mRequestedIp + " from host '" + + mHostName + "', param list length " + + (mRequestedParams == null ? 0 : mRequestedParams.length); + } + + /** + * Fills in a packet with the requested REQUEST attributes. + */ + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + + fillInPacket(encap, Inet4Address.ALL, Inet4Address.ANY, destUdp, srcUdp, + result, DHCP_BOOTREQUEST, mBroadcast); + result.flip(); + return result; + } + + /** + * Adds the optional parameters to the client-generated REQUEST packet. + */ + void finishPacket(ByteBuffer buffer) { + byte[] clientId = new byte[7]; + + // assemble client identifier + clientId[0] = CLIENT_ID_ETHER; + System.arraycopy(mClientMac, 0, clientId, 1, 6); + + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST); + addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams); + addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp); + addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); + addTlv(buffer, DHCP_CLIENT_IDENTIFIER, clientId); + addTlvEnd(buffer); + } + + /** + * Notifies the specified state machine of the REQUEST packet parameters. + */ + public void doNextOp(DhcpStateMachine machine) { + InetAddress clientRequest = + mRequestedIp == null ? mClientIp : mRequestedIp; + Log.v(TAG, "requested IP is " + mRequestedIp + " and client IP is " + + mClientIp); + machine.onRequestReceived(mBroadcast, mTransId, mClientMac, + clientRequest, mRequestedParams, mHostName); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpStateMachine.java b/services/net/java/android/net/dhcp/DhcpStateMachine.java new file mode 100644 index 0000000..bc9a798 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpStateMachine.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 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. + */ + +package android.net.dhcp; + +import java.net.InetAddress; +import java.util.List; + +/** + * This class defines the "next steps" which occur after a given DHCP + * packet has been received. + */ +interface DhcpStateMachine { + /** + * Signals that an offer packet has been received with the specified + * parameters. + */ + public void onOfferReceived(boolean broadcast, int transactionId, + byte[] myMac, InetAddress offeredIpAddress, + InetAddress serverIpAddress); + + /** + * Signals that a NAK packet has been received. + */ + public void onNakReceived(); + + /** + * Signals that the final ACK has been received from the server. + */ + public void onAckReceived(InetAddress myIpAddress, InetAddress myNetMask, + InetAddress myGateway, List<InetAddress> myDnsServers, + InetAddress myDhcpServer, int leaseTime); + + /** + * Signals that a client's DISCOVER packet has been received with the + * specified parameters. + */ + public void onDiscoverReceived(boolean broadcast, int transactionId, + byte[] clientMac, byte[] requestedParameterList); + + /** + * Signals that a client's REQUEST packet has been received with the + * specified parameters. + */ + public void onRequestReceived(boolean broadcast, int transactionId, + byte[] clientMac, InetAddress requestedIp, byte[] requestedParams, + String clientHostName); + + /** + * Signals that a client's INFORM packet has been received with the + * specified parameters. + */ + public void onInformReceived(int transactionId, byte[] clientMac, + InetAddress preassignedIp, byte[] requestedParams); + + /** + * Signals that a client's DECLINE packet has been received with the + * specified parameters. + */ + public void onDeclineReceived(byte[] clientMac, InetAddress declinedIp); +} |