1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.dhcp6; 18 19 import static android.system.OsConstants.AF_INET6; 20 import static android.system.OsConstants.IPPROTO_UDP; 21 import static android.system.OsConstants.SOCK_DGRAM; 22 import static android.system.OsConstants.SOCK_NONBLOCK; 23 24 import static com.android.net.module.util.NetworkStackConstants.ALL_DHCP_RELAY_AGENTS_AND_SERVERS; 25 import static com.android.net.module.util.NetworkStackConstants.DHCP6_CLIENT_PORT; 26 import static com.android.net.module.util.NetworkStackConstants.DHCP6_SERVER_PORT; 27 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; 28 29 import android.content.Context; 30 import android.net.ip.IpClient; 31 import android.net.util.SocketUtils; 32 import android.os.Handler; 33 import android.system.ErrnoException; 34 import android.system.Os; 35 import android.util.Log; 36 37 import androidx.annotation.NonNull; 38 39 import com.android.internal.util.StateMachine; 40 import com.android.net.module.util.InterfaceParams; 41 import com.android.net.module.util.PacketReader; 42 43 import java.io.FileDescriptor; 44 import java.io.IOException; 45 import java.net.SocketException; 46 import java.nio.ByteBuffer; 47 48 /** 49 * A DHCPv6 client. 50 * 51 * So far only support IA_PD (prefix delegation), not for IA_NA/IA_TA yet. 52 * 53 * @hide 54 */ 55 public class Dhcp6Client extends StateMachine { 56 private static final String TAG = Dhcp6Client.class.getSimpleName(); 57 private static final boolean DBG = true; 58 59 // Internal messages. 60 // Dhcp6Client shares the same handler with IpClient, define the base command range for 61 // both public and private messages used in Dhcp6Client, to avoid commands overlap. 62 private static final int PRIVATE_BASE = IpClient.DHCP6CLIENT_CMD_BASE + 100; 63 private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 1; 64 65 @NonNull private final Context mContext; 66 67 // State variables. 68 @NonNull private final StateMachine mController; 69 @NonNull private final String mIfaceName; 70 Dhcp6Client(@onNull final Context context, @NonNull final StateMachine controller, @NonNull final InterfaceParams iface)71 private Dhcp6Client(@NonNull final Context context, @NonNull final StateMachine controller, 72 @NonNull final InterfaceParams iface) { 73 super(TAG, controller.getHandler()); 74 75 mContext = context; 76 mController = controller; 77 mIfaceName = iface.name; 78 79 // TODO: add state machine initialization. 80 } 81 82 private class Dhcp6PacketHandler extends PacketReader { 83 private FileDescriptor mUdpSock; 84 Dhcp6PacketHandler(Handler handler)85 Dhcp6PacketHandler(Handler handler) { 86 super(handler); 87 } 88 89 @Override handlePacket(byte[] recvbuf, int length)90 protected void handlePacket(byte[] recvbuf, int length) { 91 try { 92 final Dhcp6Packet packet = Dhcp6Packet.decodePacket(recvbuf, length); 93 if (DBG) Log.d(TAG, "Received packet: " + packet); 94 sendMessage(CMD_RECEIVED_PACKET, packet); 95 } catch (Dhcp6Packet.ParseException e) { 96 Log.e(TAG, "Can't parse DHCPv6 packet: " + e.getMessage()); 97 } 98 } 99 100 @Override createFd()101 protected FileDescriptor createFd() { 102 try { 103 mUdpSock = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); 104 SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName); 105 Os.bind(mUdpSock, IPV6_ADDR_ANY, DHCP6_CLIENT_PORT); 106 } catch (SocketException | ErrnoException e) { 107 Log.e(TAG, "Error creating udp socket", e); 108 closeFd(mUdpSock); 109 mUdpSock = null; 110 return null; 111 } 112 return mUdpSock; 113 } 114 115 @Override readPacket(FileDescriptor fd, byte[] packetBuffer)116 protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception { 117 try { 118 return Os.read(fd, packetBuffer, 0, packetBuffer.length); 119 } catch (IOException | ErrnoException e) { 120 Log.e(TAG, "Fail to read packet"); 121 throw e; 122 } 123 } 124 transmitPacket(final ByteBuffer buf)125 public int transmitPacket(final ByteBuffer buf) throws ErrnoException, SocketException { 126 int ret = Os.sendto(mUdpSock, buf.array(), 0 /* byteOffset */, 127 buf.limit() /* byteCount */, 0 /* flags */, ALL_DHCP_RELAY_AGENTS_AND_SERVERS, 128 DHCP6_SERVER_PORT); 129 return ret; 130 } 131 } 132 } 133