1 /*
2  * Copyright 2020 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;
18 
19 import android.net.ipsec.ike.exceptions.IkeIOException;
20 import android.net.ipsec.ike.exceptions.IkeInternalException;
21 import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
22 import android.net.ipsec.ike.exceptions.IkeProtocolException;
23 import android.support.annotation.IntDef;
24 import android.support.annotation.NonNull;
25 
26 import java.io.IOException;
27 import java.util.Map;
28 
29 public class IwlanError {
30 
31     // error types
32     public static final int NO_ERROR = 0;
33 
34     // IKE lib related
35     public static final int IKE_PROTOCOL_EXCEPTION = 1;
36     public static final int IKE_INTERNAL_IO_EXCEPTION = 2;
37     public static final int IKE_GENERIC_EXCEPTION = 3; // catch all
38 
39     // Known internal types
40     public static final int EPDG_SELECTOR_SERVER_SELECTION_FAILED = 4;
41     public static final int TUNNEL_TRANSFORM_FAILED = 5;
42     public static final int SIM_NOT_READY_EXCEPTION = 6;
43     public static final int IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED = 7;
44     public static final int IKE_NETWORK_LOST_EXCEPTION = 8;
45     public static final int TUNNEL_NOT_FOUND = 9;
46     public static final int EPDG_ADDRESS_ONLY_IPV4_ALLOWED = 10;
47     public static final int EPDG_ADDRESS_ONLY_IPV6_ALLOWED = 11;
48     public static final int IKE_INIT_TIMEOUT = 12;
49     public static final int IKE_MOBILITY_TIMEOUT = 13;
50     public static final int IKE_DPD_TIMEOUT = 14;
51 
52     @IntDef({
53         NO_ERROR,
54         IKE_PROTOCOL_EXCEPTION,
55         IKE_INTERNAL_IO_EXCEPTION,
56         IKE_GENERIC_EXCEPTION,
57         EPDG_SELECTOR_SERVER_SELECTION_FAILED,
58         TUNNEL_TRANSFORM_FAILED,
59         SIM_NOT_READY_EXCEPTION,
60         IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED,
61         IKE_NETWORK_LOST_EXCEPTION,
62         TUNNEL_NOT_FOUND,
63         EPDG_ADDRESS_ONLY_IPV4_ALLOWED,
64         EPDG_ADDRESS_ONLY_IPV6_ALLOWED,
65         IKE_INIT_TIMEOUT,
66         IKE_MOBILITY_TIMEOUT,
67         IKE_DPD_TIMEOUT
68     })
69     @interface IwlanErrorType {}
70 
71     private static final Map<Integer, String> sErrorTypeStrings =
72             Map.ofEntries(
73                     Map.entry(NO_ERROR, "IWLAN_NO_ERROR"),
74                     Map.entry(IKE_PROTOCOL_EXCEPTION, "IWLAN_IKE_PROTOCOL_EXCEPTION"),
75                     Map.entry(IKE_INTERNAL_IO_EXCEPTION, "IWLAN_IKE_INTERNAL_IO_EXCEPTION"),
76                     Map.entry(IKE_GENERIC_EXCEPTION, "IWLAN_IKE_GENERIC_EXCEPTION"),
77                     Map.entry(
78                             EPDG_SELECTOR_SERVER_SELECTION_FAILED,
79                             "IWLAN_EPDG_SELECTOR_SERVER_SELECTION_FAILED"),
80                     Map.entry(TUNNEL_TRANSFORM_FAILED, "IWLAN_TUNNEL_TRANSFORM_FAILED"),
81                     Map.entry(SIM_NOT_READY_EXCEPTION, "IWLAN_SIM_NOT_READY_EXCEPTION"),
82                     Map.entry(
83                             IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED,
84                             "IKE_SESSION_CLOSED_BEFORE_CHILD_SESSION_OPENED"),
85                     Map.entry(IKE_NETWORK_LOST_EXCEPTION, "IWLAN_IKE_NETWORK_LOST_EXCEPTION"),
86                     Map.entry(TUNNEL_NOT_FOUND, "IWLAN_TUNNEL_NOT_FOUND"),
87                     Map.entry(IKE_INIT_TIMEOUT, "IKE_INIT_TIMEOUT"),
88                     Map.entry(IKE_MOBILITY_TIMEOUT, "IKE_MOBILITY_TIMEOUT"),
89                     Map.entry(IKE_DPD_TIMEOUT, "IKE_DPD_TIMEOUT"),
90                     Map.entry(EPDG_ADDRESS_ONLY_IPV4_ALLOWED, "EPDG_ADDRESS_ONLY_IPV4_ALLOWED"),
91                     Map.entry(EPDG_ADDRESS_ONLY_IPV6_ALLOWED, "EPDG_ADDRESS_ONLY_IPV6_ALLOWED"));
92     private int mErrorType;
93     private Exception mException;
94 
IwlanError(@wlanErrorType int err)95     public IwlanError(@IwlanErrorType int err) {
96         mErrorType = err;
97     }
98 
IwlanError(@wlanErrorType int err, @NonNull Exception exception)99     public IwlanError(@IwlanErrorType int err, @NonNull Exception exception) {
100         mErrorType = err;
101         mException = exception;
102     }
103 
104     /**
105      * Sets the IwlanError based on the Exception: 1. IkeException is base the class for all IKE
106      * exception ErrorType: IKE_GENERIC_EXCEPTION. 2. IkeProtocolException is for specific protocol
107      * errors (like IKE notify error codes) ErrorType: IKE_PROTOCOL_EXCEPTION 3.
108      * IkeInternalException is just a wrapper for various exceptions that IKE lib may encounter
109      * ErrorType: IKE_INTERNAL_IO_EXCEPTION if the Exception is instance of IOException ErrorType:
110      * IKE_GENERIC_EXCEPTION for all the other.
111      */
IwlanError(@onNull Exception exception)112     public IwlanError(@NonNull Exception exception) {
113         // resolve into specific types if possible
114         if (exception instanceof IkeProtocolException) {
115             IwlanErrorIkeProtocolException((IkeProtocolException) exception);
116         } else if (exception instanceof IkeIOException) {
117             IwlanErrorIkeIOException((IkeIOException) exception);
118         } else if (exception instanceof IkeInternalException) {
119             IwlanErrorIkeInternalException((IkeInternalException) exception);
120         } else if (exception instanceof IkeNetworkLostException) {
121             IwlanErrorIkeNetworkLostException((IkeNetworkLostException) exception);
122         } else {
123             mErrorType = IKE_GENERIC_EXCEPTION;
124             mException = exception;
125         }
126     }
127 
IwlanErrorIkeProtocolException(@onNull IkeProtocolException exception)128     private void IwlanErrorIkeProtocolException(@NonNull IkeProtocolException exception) {
129         mErrorType = IKE_PROTOCOL_EXCEPTION;
130         mException = exception;
131     }
132 
IwlanErrorIkeInternalException(@onNull IkeInternalException exception)133     private void IwlanErrorIkeInternalException(@NonNull IkeInternalException exception) {
134         if (exception.getCause() instanceof IOException) {
135             mErrorType = IKE_INTERNAL_IO_EXCEPTION;
136         } else {
137             mErrorType = IKE_GENERIC_EXCEPTION;
138         }
139         mException = exception;
140     }
141 
IwlanErrorIkeIOException(@onNull IkeIOException exception)142     private void IwlanErrorIkeIOException(@NonNull IkeIOException exception) {
143         mErrorType = IKE_INTERNAL_IO_EXCEPTION;
144         mException = exception;
145     }
146 
IwlanErrorIkeNetworkLostException(@onNull IkeNetworkLostException exception)147     private void IwlanErrorIkeNetworkLostException(@NonNull IkeNetworkLostException exception) {
148         mErrorType = IKE_NETWORK_LOST_EXCEPTION;
149         mException = exception;
150     }
151 
getErrorType()152     public @IwlanErrorType int getErrorType() {
153         return mErrorType;
154     }
155 
getException()156     public Exception getException() {
157         return mException;
158     }
159 
getErrorTypeString(@wlanErrorType int error)160     private static @NonNull String getErrorTypeString(@IwlanErrorType int error) {
161         String s = sErrorTypeStrings.get(error);
162         return (s == null ? "IWLAN_UNKNOWN_ERROR_TYPE" : s);
163     }
164 
165     @Override
toString()166     public String toString() {
167         return ("TYPE: " + getErrorTypeString(mErrorType) + " " + errorDetailsString());
168     }
169 
errorDetailsString()170     private String errorDetailsString() {
171         StringBuilder sb = new StringBuilder();
172 
173         if (mException == null) {
174             return "";
175         }
176 
177         switch (mErrorType) {
178             case IKE_GENERIC_EXCEPTION:
179                 sb.append("MSG: ").append(mException.getMessage()).append("\n CAUSE: ");
180                 sb.append(mException.getCause());
181                 break;
182             case IKE_PROTOCOL_EXCEPTION:
183                 sb.append("ERR: ")
184                         .append(((IkeProtocolException) mException).getErrorType())
185                         .append("\nDATA:");
186                 for (byte b : ((IkeProtocolException) mException).getErrorData()) {
187                     sb.append(String.format("%02x ", b));
188                 }
189                 break;
190             case IKE_NETWORK_LOST_EXCEPTION:
191                 sb.append("ERR: ")
192                         .append(mException.getMessage())
193                         .append("\n CAUSE: ")
194                         .append(mException.getCause())
195                         .append("\n NETWORK: ")
196                         .append(((IkeNetworkLostException) mException).getNetwork());
197                 break;
198             default:
199                 sb.append("-No Details-");
200         }
201         return sb.toString();
202     }
203 
204     @Override
equals(Object o)205     public boolean equals(Object o) {
206         if (!(o instanceof IwlanError error)) {
207             return false;
208         }
209         boolean ret = false;
210         if (mErrorType == error.getErrorType()) {
211             if (mException != null && error.getException() != null) {
212                 ret = mException.getClass().equals(error.getException().getClass());
213                 if (ret && mException instanceof IkeProtocolException) {
214                     ret =
215                             (((IkeProtocolException) mException).getErrorType()
216                                     == ((IkeProtocolException) error.getException())
217                                             .getErrorType());
218                 }
219             } else if (mException == null && error.getException() == null) {
220                 ret = true;
221             }
222         }
223         return ret;
224     }
225 }
226