summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@digia.com>2014-05-08 17:36:52 +0200
committerGatis Paeglis <gatis.paeglis@digia.com>2014-06-13 09:39:35 +0300
commite30a8e704c129315225368de6cf41bd31df62d64 (patch)
treec2f1e69abb9c642499585470d2cbcf290992b71d /src
parent84cb69dd5af6d2e44cce7bbef2536706d781f799 (diff)
Fix Wifi issues on Android 4.4.2
- Reload Wi-Fi firmware on a device startup (initializes wlan0 interface). - Android version 4.4 (and above) requires IFNAME=wlan0 prefix to the wpa_supplicant calls, without this all calls to the wpa_supplicant fail. - Fix "broken pipe" issue - a message in the logcat when trying to access a broken network. This seems to be a generic message whenever something is wrong with a network configuration (broken routing table, firewall issues, DNS issues etc.). Android uses Connectivity and NetworkManagement JAVA services to handle network configuration - we can use qconnectivity daemon for this. Task-number: QTEE-562 Change-Id: Ib5a93c677439a0e9bf92ede532667542d2bc4bed Reviewed-by: Eirik Aavitsland <eirik.aavitsland@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/imports/wifi/qwifimanager.cpp9
-rw-r--r--src/qconnectivity/main.cpp79
2 files changed, 63 insertions, 25 deletions
diff --git a/src/imports/wifi/qwifimanager.cpp b/src/imports/wifi/qwifimanager.cpp
index 65073f1..dd395c0 100644
--- a/src/imports/wifi/qwifimanager.cpp
+++ b/src/imports/wifi/qwifimanager.cpp
@@ -618,8 +618,13 @@ QByteArray QWifiManager::call(const char *command) const
{
char data[2048];
size_t len = sizeof(data) - 1; // -1: room to add a 0-terminator
- if (q_wifi_command(m_interface.constData(), command, data, &len) < 0) {
- qWarning("QWifiManager: call failed: %s", command);
+ QByteArray cmd;
+#if !(Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 4)
+ cmd.append("IFNAME=").append(m_interface).append(" ");
+#endif
+ cmd.append(command);
+ if (q_wifi_command(m_interface.constData(), cmd.constData(), data, &len) < 0) {
+ qWarning("QWifiManager: call failed: %s", cmd.constData());
return QByteArray();
}
if (len < sizeof(data))
diff --git a/src/qconnectivity/main.cpp b/src/qconnectivity/main.cpp
index 6f01021..97f9582 100644
--- a/src/qconnectivity/main.cpp
+++ b/src/qconnectivity/main.cpp
@@ -65,7 +65,8 @@ static int q_dhcp_do_request(bool renew,
char *dns2,
char *server,
uint32_t *lease,
- char *vendorInfo)
+ char *vendorInfo,
+ char *domain)
{
#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 3
if (!renew)
@@ -73,7 +74,6 @@ static int q_dhcp_do_request(bool renew,
return dhcp_do_request_renew(ifname, ipaddr, gateway, prefixLength, dns1, dns2, server, lease, vendorInfo);
#else
char *dns[3] = {dns1, dns2, 0};
- char domain[PROPERTY_VALUE_MAX];
char mtu[PROPERTY_VALUE_MAX];
#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 4
if (!renew)
@@ -123,6 +123,11 @@ private:
LeaseTimer *m_leaseTimer;
bool m_isEmulator;
QByteArray m_ethInterface;
+ // android initializes services in a separate threads, therefore it is
+ // not guaranteed that the netd socket will be ready at the time when qconnectivity
+ // is starting up - we try to reconnect again after 2 second intervals. This
+ // variable holds the maximum attempt count (chosen arbitrarily).
+ int m_attemptCount;
};
class LeaseTimer : public QTimer
@@ -153,7 +158,12 @@ private:
};
QConnectivityDaemon::QConnectivityDaemon()
- : m_netdSocket(0), m_serverSocket(0), m_linkUp(false), m_leaseTimer(0), m_isEmulator(isEmulator())
+ : m_netdSocket(0),
+ m_serverSocket(0),
+ m_linkUp(false),
+ m_leaseTimer(0),
+ m_isEmulator(isEmulator()),
+ m_attemptCount(12)
{
qDebug() << "starting QConnectivityDaemon...";
if (!m_isEmulator) {
@@ -194,26 +204,34 @@ bool QConnectivityDaemon::isEmulator() const
void QConnectivityDaemon::initNetdConnection()
{
+ int netdFd = socket_local_client("netd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+ if (netdFd != -1) {
+ qDebug() << "QConnectivityDaemon: connected to netd socket";
+ m_netdSocket = new QLocalSocket(this);
+ m_netdSocket->setSocketDescriptor(netdFd);
+ connect(m_netdSocket, SIGNAL(readyRead()), this, SLOT(handleNetdEvent()));
+ connect(m_netdSocket, SIGNAL(error(QLocalSocket::LocalSocketError)),
+ this, SLOT(handleError(QLocalSocket::LocalSocketError)));
+ } else {
+ qWarning() << "QConnectivityDaemon: failed to connect to netd socket";
+ if (--m_attemptCount != 0)
+ QTimer::singleShot(2000, this, SLOT(initNetdConnection()));
+ return;
+ }
if (ethernetSupported()) {
- static int attemptCount = 12;
- int netdFd = socket_local_client("netd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
- if (netdFd != -1) {
- qDebug() << "QConnectivityDaemon: connected to netd socket";
- m_netdSocket = new QLocalSocket(this);
- m_netdSocket->setSocketDescriptor(netdFd);
- connect(m_netdSocket, SIGNAL(readyRead()), this, SLOT(handleNetdEvent()));
- connect(m_netdSocket, SIGNAL(error(QLocalSocket::LocalSocketError)),
- this, SLOT(handleError(QLocalSocket::LocalSocketError)));
- // down-up sequence generates "linkstate" events, which we can use to setup
- // our daemon on initial startup or on daemon restarts
- sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" down").constData());
- sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" up").constData());
- } else {
- qWarning() << "QConnectivityDaemon: failed to connect to netd socket";
- if (--attemptCount != 0)
- QTimer::singleShot(2000, this, SLOT(initNetdConnection()));
- }
+ // down-up sequence generates "linkstate" events, which we can use to setup
+ // our daemon on initial startup (device boot) or on daemon restarts
+ sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" down").constData());
+ sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" up").constData());
}
+ char wifiInterface[PROPERTY_VALUE_MAX];
+ property_get("wifi.interface", wifiInterface, NULL);
+ if (wifiInterface)
+ // reload wifi firmware
+ sendCommand(QByteArray("0 softap fwreload ").append(wifiInterface).append(" STA").constData());
+ // disable firewall - this setting seems to be enabled only when using "Always-on VPN"
+ // mode on Android phones, see setLockdownTracker() in ConnectivityService.java
+ sendCommand("0 firewall disable");
}
void QConnectivityDaemon::setHostnamePropery(const char *interface) const
@@ -240,6 +258,10 @@ void QConnectivityDaemon::setHostnamePropery(const char *interface) const
void QConnectivityDaemon::sendCommand(const char *command) const
{
+ if (!m_netdSocket) {
+ qDebug() << "QConnectivityDaemon: netd socket is not ready!";
+ return;
+ }
qDebug() << "QConnectivityDaemon: sending command - " << command;
// netd expects "\0" terminated commands...
m_netdSocket->write(command, qstrlen(command) + 1);
@@ -286,10 +308,11 @@ bool QConnectivityDaemon::startDhcp(bool renew, const char *interface)
char server[PROPERTY_VALUE_MAX];
quint32 lease = 0;
char vendorInfo[PROPERTY_VALUE_MAX];
+ char domain[PROPERTY_VALUE_MAX] = {0};
if (renew) {
result = q_dhcp_do_request(true, interface, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease, vendorInfo);
+ dns1, dns2, server, &lease, vendorInfo, domain);
} else {
// stop any existing DHCP daemon before starting new
dhcp_stop(interface);
@@ -298,7 +321,7 @@ bool QConnectivityDaemon::startDhcp(bool renew, const char *interface)
// we are responsible for renewing a lease before it expires
ifc_clear_addresses(interface);
result = q_dhcp_do_request(false, interface, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease, vendorInfo);
+ dns1, dns2, server, &lease, vendorInfo, domain);
}
bool success = (result == 0) ? true : false;
@@ -316,6 +339,16 @@ bool QConnectivityDaemon::startDhcp(bool renew, const char *interface)
ifc_configure(interface, _ipaddr.s_addr, prefixLength,
_gateway.s_addr, _dns1.s_addr, _dns2.s_addr);
+ // set DNS servers for interface - see NetworkManagementService.java
+ if (domain[0]) {
+ QByteArray dnsForInterface("0 resolver setifdns ");
+ dnsForInterface.append(interface).append(" ").append(domain).append(" ");
+ dnsForInterface.append(dns1).append(" ").append(dns2);
+ sendCommand(dnsForInterface.constData());
+ }
+ // set default interface for DNS - see NetworkManagementService.java
+ sendCommand(QByteArray("0 resolver setdefaultif ").append(interface).constData());
+
property_set("net.dns1", dns1);
property_set("net.dns2", dns2);
}