• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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