1/*
2 * Copyright (C) 2006 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
17package com.android.internal.telephony.gsm;
18
19import android.os.Message;
20import android.util.Log;
21import android.util.Patterns;
22
23import com.android.internal.telephony.DataConnection;
24import com.android.internal.telephony.Phone;
25import com.android.internal.telephony.RILConstants;
26
27/**
28 * {@hide}
29 */
30public class GsmDataConnection extends DataConnection {
31
32    private static final String LOG_TAG = "GSM";
33
34    /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
35    private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
36    private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
37    private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
38    private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
39    private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
40    private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
41    private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
42    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
43    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
44    private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
45    private static final int PDP_FAIL_NSAPI_IN_USE      = 0x23;
46    private static final int PDP_FAIL_PROTOCOL_ERRORS   = 0x6F;
47    private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
48
49    private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
50    private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
51
52    //***** Instance Variables
53    private ApnSetting apn;
54
55    //***** Constructor
56    private GsmDataConnection(GSMPhone phone, String name) {
57        super(phone, name);
58    }
59
60    /**
61     * Create the connection object
62     *
63     * @param phone
64     * @return GsmDataConnection that was created.
65     */
66    static GsmDataConnection makeDataConnection(GSMPhone phone) {
67        synchronized (mCountLock) {
68            mCount += 1;
69        }
70        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount);
71        gsmDc.start();
72        if (DBG) gsmDc.log("Made " + gsmDc.getName());
73        return gsmDc;
74    }
75
76    /**
77     * Begin setting up a data connection, calls setupDataCall
78     * and the ConnectionParams will be returned with the
79     * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
80     *
81     * @param cp is the connection parameters
82     */
83    @Override
84    protected
85    void onConnect(ConnectionParams cp) {
86        apn = cp.apn;
87
88        if (DBG) log("Connecting to carrier: '" + apn.carrier
89                + "' APN: '" + apn.apn
90                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
91
92        setHttpProxy (apn.proxy, apn.port);
93
94        createTime = -1;
95        lastFailTime = -1;
96        lastFailCause = FailCause.NONE;
97
98        // msg.obj will be returned in AsyncResult.userObj;
99        Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
100        msg.obj = cp;
101
102        int authType = apn.authType;
103        if (authType == -1) {
104            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
105                RILConstants.SETUP_DATA_AUTH_NONE;
106        }
107
108        String protocol;
109        if (phone.getServiceState().getRoaming()) {
110            protocol = apn.roamingProtocol;
111        } else {
112            protocol = apn.protocol;
113        }
114
115        phone.mCM.setupDataCall(
116                Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
117                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT),
118                apn.apn, apn.user, apn.password, Integer.toString(authType),
119                protocol, msg);
120    }
121
122    @Override
123    protected void clearSettings() {
124        super.clearSettings();
125        apn = null;
126    }
127
128    @Override
129    public String toString() {
130        return "State=" + getCurrentState().getName() + " Apn=" + apn +
131               " create=" + createTime + " lastFail=" + lastFailTime +
132               " lastFailCause=" + lastFailCause;
133    }
134
135    @Override
136    protected FailCause getFailCauseFromRequest(int rilCause) {
137        FailCause cause;
138
139        switch (rilCause) {
140            case PDP_FAIL_OPERATOR_BARRED:
141                cause = FailCause.OPERATOR_BARRED;
142                break;
143            case PDP_FAIL_INSUFFICIENT_RESOURCES:
144                cause = FailCause.INSUFFICIENT_RESOURCES;
145                break;
146            case PDP_FAIL_MISSING_UKNOWN_APN:
147                cause = FailCause.MISSING_UNKNOWN_APN;
148                break;
149            case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
150                cause = FailCause.UNKNOWN_PDP_ADDRESS;
151                break;
152            case PDP_FAIL_USER_AUTHENTICATION:
153                cause = FailCause.USER_AUTHENTICATION;
154                break;
155            case PDP_FAIL_ACTIVATION_REJECT_GGSN:
156                cause = FailCause.ACTIVATION_REJECT_GGSN;
157                break;
158            case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
159                cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
160                break;
161            case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
162                cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
163                break;
164            case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
165                cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
166                break;
167            case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
168                cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
169                break;
170            case PDP_FAIL_NSAPI_IN_USE:
171                cause = FailCause.NSAPI_IN_USE;
172                break;
173            case PDP_FAIL_PROTOCOL_ERRORS:
174                cause = FailCause.PROTOCOL_ERRORS;
175                break;
176            case PDP_FAIL_ERROR_UNSPECIFIED:
177                cause = FailCause.UNKNOWN;
178                break;
179            case PDP_FAIL_REGISTRATION_FAIL:
180                cause = FailCause.REGISTRATION_FAIL;
181                break;
182            case PDP_FAIL_GPRS_REGISTRATION_FAIL:
183                cause = FailCause.GPRS_REGISTRATION_FAIL;
184                break;
185            default:
186                cause = FailCause.UNKNOWN;
187        }
188        return cause;
189    }
190
191    @Override
192    protected boolean isDnsOk(String[] domainNameServers) {
193        if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
194                    && !((GSMPhone) phone).isDnsCheckDisabled()) {
195            // Work around a race condition where QMI does not fill in DNS:
196            // Deactivate PDP and let DataConnectionTracker retry.
197            // Do not apply the race condition workaround for MMS APN
198            // if Proxy is an IP-address.
199            // Otherwise, the default APN will not be restored anymore.
200            if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
201                || !isIpAddress(apn.mmsProxy)) {
202                return false;
203            }
204        }
205        return true;
206    }
207
208    @Override
209    protected void log(String s) {
210        Log.d(LOG_TAG, "[" + getName() + "] " + s);
211    }
212
213    public ApnSetting getApn() {
214        return this.apn;
215    }
216
217    private void setHttpProxy(String httpProxy, String httpPort) {
218        if (httpProxy == null || httpProxy.length() == 0) {
219            phone.setSystemProperty("net.gprs.http-proxy", null);
220            return;
221        }
222
223        if (httpPort == null || httpPort.length() == 0) {
224            httpPort = "8080";     // Default to port 8080
225        }
226
227        phone.setSystemProperty("net.gprs.http-proxy",
228                "http://" + httpProxy + ":" + httpPort + "/");
229    }
230
231    private boolean isIpAddress(String address) {
232        if (address == null) return false;
233
234        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
235    }
236}
237