1 /*
2  * Copyright 2024 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 com.google.android.iwlan.epdg;
18 
19 import android.annotation.NonNull;
20 
21 import java.net.InetAddress;
22 import java.util.HashSet;
23 import java.util.Set;
24 
25 public class EpdgMonitor {
26     private InetAddress mEpdgAddressForNormalSession;
27     private InetAddress mSeparateEpdgAddressForEmergencySession;
28     private Set<String> mApnConnectToNormalEpdg = new HashSet<>();
29     private final Set<String> mApnConnectToEmergencyEpdg = new HashSet<>();
30     private boolean mHasEmergencyPdnFailedWithConnectedEpdg = false;
31 
EpdgMonitor()32     public EpdgMonitor() {}
33 
34     /**
35      * Called when an APN connects to an ePDG. Tracks the ePDG address and associated APN.
36      *
37      * @param apnName The name of the Access Point Name (APN).
38      * @param address The InetAddress of the connected ePDG.
39      */
onApnConnectToEpdg(@onNull String apnName, @NonNull InetAddress address)40     public void onApnConnectToEpdg(@NonNull String apnName, @NonNull InetAddress address) {
41         if (address.equals(getEpdgAddressForEmergencySession())) {
42             mApnConnectToEmergencyEpdg.add(apnName);
43             return;
44         }
45 
46         if (address.equals(getEpdgAddressForNormalSession())) {
47             mApnConnectToNormalEpdg.add(apnName);
48             return;
49         }
50 
51         if (!hasEpdgConnectedForNormalSession()) {
52             mEpdgAddressForNormalSession = address;
53             mApnConnectToNormalEpdg.clear();
54             mApnConnectToNormalEpdg.add(apnName);
55         } else {
56             mSeparateEpdgAddressForEmergencySession = address;
57             mApnConnectToEmergencyEpdg.clear();
58             mApnConnectToEmergencyEpdg.add(apnName);
59         }
60     }
61 
62     /**
63      * Called when an APN disconnects from an ePDG. Updates internal tracking of APN connections to
64      * ePDGs.
65      *
66      * @param apnName The name of the Access Point Name (APN) that disconnected.
67      */
onApnDisconnectFromEpdg(String apnName)68     public void onApnDisconnectFromEpdg(String apnName) {
69         if (mApnConnectToNormalEpdg.contains(apnName)) {
70             mApnConnectToNormalEpdg.remove(apnName);
71             if (mApnConnectToNormalEpdg.isEmpty()) {
72                 mEpdgAddressForNormalSession = null;
73                 if (hasSeparateEpdgConnectedForEmergencySession()) {
74                     // If ePDG for normal session has no PDN and emergency PDN established on an
75                     // separate ePDG, mark the ePDG for emergency as ePDG for normal session.
76                     mEpdgAddressForNormalSession = mSeparateEpdgAddressForEmergencySession;
77                     mApnConnectToNormalEpdg = mApnConnectToEmergencyEpdg;
78                     mSeparateEpdgAddressForEmergencySession = null;
79                     mApnConnectToEmergencyEpdg.clear();
80                     mHasEmergencyPdnFailedWithConnectedEpdg = false;
81                 }
82             }
83         } else if (mApnConnectToEmergencyEpdg.contains(apnName)) {
84             mApnConnectToEmergencyEpdg.remove(apnName);
85             if (mApnConnectToEmergencyEpdg.isEmpty()) {
86                 mSeparateEpdgAddressForEmergencySession = null;
87             }
88         }
89 
90         if (!hasEpdgConnectedForNormalSession()) {
91             mHasEmergencyPdnFailedWithConnectedEpdg = false;
92         }
93     }
94 
95     /**
96      * Returns the ePDG address currently associated with normal PDN sessions.
97      *
98      * @return The InetAddress of the ePDG for normal sessions, or null if not connected.
99      */
getEpdgAddressForNormalSession()100     public InetAddress getEpdgAddressForNormalSession() {
101         return mEpdgAddressForNormalSession;
102     }
103 
104     /**
105      * Returns the ePDG address currently associated with emergency PDN sessions.
106      *
107      * @return The InetAddress of the ePDG for emergency sessions, or null if not connected.
108      */
getEpdgAddressForEmergencySession()109     public InetAddress getEpdgAddressForEmergencySession() {
110         return mSeparateEpdgAddressForEmergencySession;
111     }
112 
113     /**
114      * Checks whether an ePDG connection is established for normal PDN sessions.
115      *
116      * @return True if an ePDG is connected for normal sessions, false otherwise.
117      */
hasEpdgConnectedForNormalSession()118     public boolean hasEpdgConnectedForNormalSession() {
119         return mEpdgAddressForNormalSession != null;
120     }
121 
122     /**
123      * Checks whether an separate ePDG connection is established for emergency PDN sessions.
124      *
125      * @return True if an separate ePDG is connected for emergency sessions, false otherwise.
126      */
hasSeparateEpdgConnectedForEmergencySession()127     public boolean hasSeparateEpdgConnectedForEmergencySession() {
128         return mSeparateEpdgAddressForEmergencySession != null;
129     }
130 
131     /**
132      * Checks whether ePDG connection is established.
133      *
134      * @return True if ePDG is connected, false otherwise.
135      */
hasEpdgConnected()136     public boolean hasEpdgConnected() {
137         return hasEpdgConnectedForNormalSession() || hasSeparateEpdgConnectedForEmergencySession();
138     }
139 
140     /**
141      * Indicates whether an attempt to establish an emergency PDN has failed while a normal PDN
142      * session is active on the same ePDG.
143      *
144      * @return True if an emergency PDN establishment has failed on the connected ePDG, false
145      *     otherwise.
146      */
hasEmergencyPdnFailedWithConnectedEpdg()147     public boolean hasEmergencyPdnFailedWithConnectedEpdg() {
148         return mHasEmergencyPdnFailedWithConnectedEpdg;
149     }
150 
151     /**
152      * Called when a connection to an ePDG fails. Updates internal tracking and flags if an
153      * emergency PDN failure occurred on a previously connected ePDG.
154      *
155      * @param isEmergency Indicates whether the failed ePDG connection was for an emergency session.
156      * @param epdgAddress The InetAddress of the ePDG where the connection failed.
157      */
onEpdgConnectionFailed(boolean isEmergency, InetAddress epdgAddress)158     public void onEpdgConnectionFailed(boolean isEmergency, InetAddress epdgAddress) {
159         if (isEmergency
160                 && hasEpdgConnectedForNormalSession()
161                 && epdgAddress.equals(getEpdgAddressForNormalSession())) {
162             mHasEmergencyPdnFailedWithConnectedEpdg = true;
163         }
164     }
165 
166     /**
167      * Determines if the provided EPDG address represents a connected EPDG (i.e., is the EPDG
168      * address used for normal or emergency sessions).
169      *
170      * @param epdgAddress The EPDG address to check.
171      * @return `true` if the provided EPDG address is a connected EPDG address, `false` otherwise.
172      */
isConnectedEpdg(InetAddress epdgAddress)173     public boolean isConnectedEpdg(InetAddress epdgAddress) {
174         return epdgAddress.equals(getEpdgAddressForNormalSession())
175                 || epdgAddress.equals(getEpdgAddressForEmergencySession());
176     }
177 }
178