本文旨在为android wifi热点添加黑白名单管理机制,提供针对应用程序的相关接口,可以通过用户界面拉黑连到AP的终端或洗白设备终端。
软件环境:Android4.4.3
硬件平台:Marvell
我们的设备端是效仿google原生的便携式热点添加了第二套热点,即我们的设备是双SSID。这样的话我们的设备是用来支持两种AP的连接模式,google原生的作为AP1,当启动此热点的时候,外围终端设备不需要输入密码即可连接;当开启我们添加的AP2的时候,是走热点名和密码的验证形式。然而添加AP2不在本文所要添加功能之列,遂针对本文提到的黑白名单,我们只做在原生AP上的分析说明。
不在赘述,上代码:
第一部分,是framework部分的修改:
1,提供应用程序获取连接到当前热点的设备终端列表接口
--- a/services/java/com/android/server/wifi/WifiApService.java
+++ b/services/java/com/android/server/wifi/WifiApService.java
@@ -78,6 +78,10 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
import com.android.server.am.BatteryStatsService;
+
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+
import static com.android.server.wifi.WifiApController.CMD_AIRPLANE_TOGGLED;
import static com.android.server.wifi.WifiApController.CMD_BATTERY_CHANGED;
import static com.android.server.wifi.WifiApController.CMD_EMERGENCY_MODE_CHANGED;
@@ -1044,13 +1048,21 @@ public final class WifiApService extends IWifiApManager.Stub {
}
/**
- * see {@link android.net.wifi.WifiApManager#addToBlacklist}
+ * see {@link android.net.wifi.WifiApManager#modifyBlacklist}
*
*/
- public void addToBlacklist(String bssid) {
+ public void modifyBlacklist(String bssid, int option) {
enforceChangePermission();
+ mWifiStateMachine.modifyBlacklist(bssid, option);
+ }
- mWifiStateMachine.addToBlacklist(bssid);
+ /**
+ * see {@link android.net.wifi.WifiApManager#getApDeviceList}
+ *
+ */
+ public WifiP2pDeviceList getApDeviceList() {
+ enforceChangePermission();
+ return mWifiStateMachine.getApDeviceList();
2,修改wifiapmanager接口语言部分,
--- a/wifi/java/android/net/wifi/IWifiApManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiApManager.aidl
@@ -27,6 +27,10 @@ import android.net.DhcpInfo;
import android.os.Messenger;
import android.os.WorkSource;
+
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+
/**
* Interface that allows controlling and querying Wi-Fi connectivity.
*
@@ -44,6 +48,8 @@ interface IWifiApManager
boolean disableNetwork(int netId);
+ WifiP2pDeviceList getApDeviceList();
+
boolean pingSupplicant();
void startScan(in WorkSource ws);
@@ -104,7 +110,7 @@ interface IWifiApManager
void stopWifi();
- void addToBlacklist(String bssid);
+ void modifyBlacklist(String bssid, int option);
3,修改WifiApManager,添加相关接口,
--- a/wifi/java/android/net/wifi/WifiApManager.java
+++ b/wifi/java/android/net/wifi/WifiApManager.java
@@ -41,6 +41,9 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import java.util.List;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+
/**
* This class provides the primary API for managing all aspects of Wi-Fi
@@ -1235,16 +1238,22 @@ public class WifiApManager {
}
/**
- * Add a bssid to the supplicant blacklist
+ * Add , deltet a bssid to the supplicant blacklist
*
* This API is used by WifiWatchdogService
+ *
+ * bssid: a mac address
+ *
+ * option: 0 : add a bssid to the blacklist
+ * 1 : delete a bssid from balcklist
+ * 2 : clear blacklist
*
* @return {@code true} if the operation succeeds else {@code false}
- * @hide
+ *
*/
- public boolean addToBlacklist(String bssid) {
+ public boolean modifyBlacklist(String bssid, int option) {
try {
- mService.addToBlacklist(bssid);
+ mService.modifyBlacklist(bssid, option);
return true;
} catch (RemoteException e) {
return false;
@@ -1252,6 +1261,21 @@ public class WifiApManager {
}
/**
+ * get device list to connected the ap
+ *
+ * @return {@code result} if the operation succeeds else {@code null}
+ *
+ **/
+ public WifiP2pDeviceList getApDeviceList() {
+ try {
+ return mService.getApDeviceList();
+ } catch (RemoteException e) {
+ return null;
+ }
+
+ }
+
+ /**
* Clear the supplicant blacklist
*
* This API is used by WifiWatchdogService
4,修改WifiApStateMachine,是上层应用通过wifiapservice实现相应功能接口的实体函数实现:
--- a/wifi/java/android/net/wifi/WifiApStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiApStateMachine.java
@@ -452,6 +452,11 @@ public class WifiApStateMachine extends StateMachine {
private static final int SUCCESS = 1;
private static final int FAILURE = -1;
+ public static final int ADD_BLACKLIST = 0;
+ public static final int DELETE_BLACKLIST = 1;
+ public static final int CLEAR_BLACKLIST = 2;
+
+
/**
* The maximum number of times we will retry a connection to an access point
* for which we have failed in acquiring an IP address from DHCP. A value of
@@ -1562,10 +1567,16 @@ public class WifiApStateMachine extends StateMachine {
*
* @param bssid BSSID of the network
*/
- public void addToBlacklist(String bssid) {
- sendMessage(CMD_BLACKLIST_NETWORK, bssid);
+ public void modifyBlacklist(String bssid, int option ) {
+ if(option == ADD_BLACKLIST )
+ sendMessage(CMD_BLACKLIST_NETWORK, "add" + bssid);
+ if(option == DELETE_BLACKLIST )
+ sendMessage(CMD_BLACKLIST_NETWORK, "delete" + bssid);
+ if(option == CLEAR_BLACKLIST )
+ sendMessage(CMD_BLACKLIST_NETWORK, "clear" + bssid);
}
/**
* Clear the blacklist list
*
@@ -1574,6 +1585,10 @@ public class WifiApStateMachine extends StateMachine {
sendMessage(CMD_CLEAR_BLACKLIST);
}
+ public WifiP2pDeviceList getApDeviceList() {
+ return mPeers;
+ }
+
public void enableRssiPolling(boolean enabled) {
sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
}
@@ -4567,6 +4582,9 @@ public class WifiApStateMachine extends StateMachine {
sendWifiApClientChangedBroadcast();
}
break;
+ case CMD_BLACKLIST_NETWORK:
+ mWifiNative.modifyApBlacklist((String)message.obj);
+ break;
default:
return NOT_HANDLED;
}
通过代码我们发现,这里调用了WifiNative类的相关方法,接下看看此类当中的实现。
5,WifiNative的实现:
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -666,6 +666,15 @@ public class WifiNative {
return doBooleanCommand("BLACKLIST " + bssid);
}
+ public boolean modifyApBlacklist(String mac) {
+ if (TextUtils.isEmpty(mac)) return false;
+ return doApBooleanCommand("APBLACKLIST " + mac);
+ }
public boolean clearBlacklist() {
return doBooleanCommand("BLACKLIST clear");
}
6,获取设备连接的列表方法:
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -40,6 +40,10 @@ public class WifiP2pDeviceList implements Parcelable {
public WifiP2pDeviceList() {
}
+ public HashMap
+ return mDevices;
+ }
+
/** copy constructor */
public WifiP2pDeviceList(WifiP2pDeviceList source) {
if (source != null) {
应用程序可以通过getDevices()获取设备连接的列表,通过modifyBlacklist来添加或移除设备黑名单。至此framework部分改动大功告成。那么framework下发操作MSG是在哪一层实现的呢?毫无疑问,wpa_supplicant层,后边开始这部分修改分析。
第二部分,wap_supplicant层的修改。
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -82,6 +82,8 @@ endif
OBJS = main.c
OBJS += config_file.c
+OBJS += src/ap/hostap_blacklist.c
+
OBJS += src/ap/hostapd.c
OBJS += src/ap/wpa_auth_glue.c
OBJS += src/ap/drv_callbacks.c
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index eabfda3..d670794 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -34,6 +34,8 @@
#include "wps/wps.h"
#include "config_file.h"
#include "ctrl_iface.h"
+#include "src/ap/hostap_blacklist.h"
+#include "src/utils/common.h"
struct wpa_ctrl_dst {
@@ -505,6 +507,74 @@ static const char * pbc_status_str(enum pbc_status status)
}
}
//以下为wpa层从名单列表中删除相关SSID的接口函数。
+static int hostapd_ctrl_iface_blacklist(struct hostapd_data *hapd_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 bssid[ETH_ALEN];
+ struct hostap_blacklist *e;
+ char *pos, *end, *mac;
+ int ret;
+
+ /* cmd: "BLACKLIST [
+ if (*cmd == '\0') {
+ pos = buf;
+ end = buf + buflen;
+ e = hapd_s->blacklist;
+ while (e) {
+ ret = os_snprintf(pos, end - pos, MACSTR "\n",
+ MAC2STR(e->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ e = e->next;
+ }
+ return pos - buf;
+ }
+
+ cmd++;
+ if (os_strncmp(cmd, "clear", 5) == 0) {
+ wpa_printf(MSG_DEBUG, "clear blacklist\n");
+ hostap_blacklist_clear(hapd_s);
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+ } else if (os_strncmp(cmd, "delete", 6) == 0) {
+ mac = cmd + 6;
+ wpa_printf(MSG_DEBUG, "delete mac: %s\n", mac);
+ if (hwaddr_aton(mac, bssid)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: delete invalid BSSID '%s'", mac);
+ return -1;
+ }
+ hostap_blacklist_del(hapd_s, bssid);
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+ } else if (os_strncmp(cmd, "add", 3) == 0) {
+
+ mac = cmd + 3;
+ wpa_printf(MSG_DEBUG, "add mac: %s\n", mac);
+ if (hostapd_ctrl_iface_disassociate(hapd_s, mac)){
+ wpa_printf(MSG_ERROR, "hostapd_ctrl_iface_disassociate\n");
+ return -1;
+ }
+
+ if (hwaddr_aton(mac, bssid)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", mac);
+ return -1;
+ }
+
+ /*
+ * Add the BSSID twice, so its count will be 2, causing it to be
+ * skipped when processing scan results.
+ */
+ ret = hostap_blacklist_add(hapd_s, bssid);
+ if (ret < 0)
+ return -1;
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+ } else {
+ return -1;
+ }
+}
static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
char *buf, size_t buflen)
@@ -1212,6 +1282,12 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
reply_len = hostapd_ctrl_iface_log_level(
hapd, buf + 9, reply, reply_size);
+ } else if (os_strncmp(buf, "IFNAME=uap1 AP2BLACKLIST", 24) == 0) {
+ reply_len = hostapd_ctrl_iface_blacklist(hapd, buf + 24, reply, reply_size);
+
+ } else if (os_strncmp(buf, "IFNAME=uap0 APBLACKLIST", 23) == 0) {
+ reply_len = hostapd_ctrl_iface_blacklist(hapd, buf + 23, reply, reply_size);
+
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index d6bc98d..0209569 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -29,6 +29,7 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
+#include "hostap_blacklist.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -96,12 +97,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->timeout_next = STA_NULLFUNC;
} else {
sta = ap_sta_add(hapd, addr);
if (sta == NULL) {
hostapd_drv_sta_disassoc(hapd, addr,
WLAN_REASON_DISASSOC_AP_BUSY);
return -1;
}
+
+ if ( NULL != hostap_blacklist_get(hapd, addr)) {
+ hostapd_drv_sta_disassoc(hapd, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return -1;
+ }
}
+
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
#ifdef CONFIG_P2P
diff --git a/src/ap/hostap_blacklist.c b/src/ap/hostap_blacklist.c
new file mode 100644
index 0000000..3716542
--- /dev/null
+++ b/src/ap/hostap_blacklist.c
@@ -0,0 +1,141 @@
+/*
+ * hostap_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "src/ap/hostapd.h"
+#include "hostap_blacklist.h"
+
+/**
+ * hostap_blacklist_get - Get the blacklist entry for a BSSID
+ * @hostap_s: Pointer to hostap_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ */
//匹配要操作的SSID是否已经在黑名单中,已经有返回入口,没有则返回空。
+struct hostap_blacklist * hostap_blacklist_get(struct hostapd_data *hostap_s,
+ const u8 *bssid)
+{
+ struct hostap_blacklist *e;
+
+ if (hostap_s == NULL || bssid == NULL)
+ return NULL;
+
+ e = hostap_s->blacklist;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * hostap_blacklist_add - Add an BSSID to the blacklist
+ * @hostap_s: Pointer to hostap_supplicant data
+ * @bssid: BSSID to be added to the blacklist
+ * Returns: Current blacklist count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the blacklist or increases the
+ * blacklist count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This blacklist is used to force %hostap_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
//添加要拉黑的SSID至黑名单链表。
+int hostap_blacklist_add(struct hostapd_data *hostap_s, const u8 *bssid)
+{
+ struct hostap_blacklist *e;
+
+ if (hostap_s == NULL || bssid == NULL)
+ return -1;
+
+ e = hostap_blacklist_get(hostap_s, bssid);
+ if (e) {
+ e->count++;
+ wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
+ "incremented to %d",
+ MAC2STR(bssid), e->count);
+ return e->count;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ os_memcpy(e->bssid, bssid, ETH_ALEN);
+ e->count = 1;
+ e->next = hostap_s->blacklist;
+ hostap_s->blacklist = e;
+ wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into apblacklist",
+ MAC2STR(e->bssid));
+
+ return e->count;
+}
+
+
+/**
+ * hostap_blacklist_del - Remove an BSSID from the blacklist
+ * @hostap_s: Pointer to hostap_supplicant data
+ * @bssid: BSSID to be removed from the blacklist
+ * Returns: 0 on success, -1 on failure
+ */
//移除黑名单
+int hostap_blacklist_del(struct hostapd_data *hostap_s, const u8 *bssid)
+{
+ struct hostap_blacklist *e, *prev = NULL;
+
+ if (hostap_s == NULL || bssid == NULL)
+ return -1;
+
+ e = hostap_s->blacklist;
+ while (e) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+ if (prev == NULL) {
+ hostap_s->blacklist = e->next;
+ } else {
+ prev->next = e->next;
+ }
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+ "apblacklist", MAC2STR(bssid));
+ os_free(e);
+ return 0;
+ }
+ prev = e;
+ e = e->next;
+ }
+ return -1;
+}
+
+
+/**
+ * hostap_blacklist_clear - Clear the blacklist of all entries
+ * @hostap_s: Pointer to hostap_supplicant data
+ */
//一次性清除黑名单所有设备。
+void hostap_blacklist_clear(struct hostapd_data *hostap_s)
+{
+ struct hostap_blacklist *e, *prev;
+ int max_count = 0;
+
+ e = hostap_s->blacklist;
+ hostap_s->blacklist = NULL;
+ while (e) {
+ if (e->count > max_count)
+ max_count = e->count;
+ prev = e;
+ e = e->next;
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+ "apblacklist (clear)", MAC2STR(prev->bssid));
+ os_free(prev);
+ }
+
+ //hostap_s->extra_blacklist_count += max_count;
+}
//最后是一些相关的数据结构的定义以及相关makefile的修改。
diff --git a/src/ap/hostap_blacklist.h b/src/ap/hostap_blacklist.h
new file mode 100644
index 0000000..aac26bd
--- /dev/null
+++ b/src/ap/hostap_blacklist.h
@@ -0,0 +1,24 @@
+/*
+ * hostap_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_BLACKLIST_H
+#define AP_BLACKLIST_H
+
+struct hostap_blacklist {
+ struct hostap_blacklist *next;
+ u8 bssid[ETH_ALEN];
+ int count;
+};
+
+struct hostap_blacklist * hostap_blacklist_get(struct hostapd_data *hostap_s,
+ const u8 *bssid);
+int hostap_blacklist_add(struct hostapd_data *hostap_s, const u8 *bssid);
+int hostap_blacklist_del(struct hostapd_data *hostap_s, const u8 *bssid);
+void hostap_blacklist_clear(struct hostapd_data *hostap_s);
+
+#endif /* BLACKLIST_H */
index 0000000..aac26bd
--- /dev/null
+++ b/src/ap/hostap_blacklist.h
@@ -0,0 +1,24 @@
+/*
+ * hostap_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_BLACKLIST_H
+#define AP_BLACKLIST_H
+
+struct hostap_blacklist {
+ struct hostap_blacklist *next;
+ u8 bssid[ETH_ALEN];
+ int count;
+};
+
+struct hostap_blacklist * hostap_blacklist_get(struct hostapd_data *hostap_s,
+ const u8 *bssid);
+int hostap_blacklist_add(struct hostapd_data *hostap_s, const u8 *bssid);
+int hostap_blacklist_del(struct hostapd_data *hostap_s, const u8 *bssid);
+void hostap_blacklist_clear(struct hostapd_data *hostap_s);
+
+#endif /* BLACKLIST_H */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52..59ad0ae 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -156,6 +156,11 @@ struct hostapd_data {
u8 time_update_counter;
struct wpabuf *time_adv;
+
+ struct hostap_blacklist *blacklist;
+
+ int extra_blacklist_count;
+
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan *full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 96f4b80..262fb4e 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -782,6 +782,7 @@ OBJS += src/eapol_auth/eapol_auth_sm.c
OBJS += src/ap/ieee802_11_auth.c
OBJS += src/ap/ieee802_11_shared.c
OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/hostap_blacklist.c
OBJS += src/ap/ap_drv_ops.c
OBJS += src/ap/beacon.c
OBJS += src/ap/eap_user_db.c
综上两部分,我们得知,此功能的修改权杖两个层面,一个是framework层面,该层面在相应的service和manager中添加开放给应用程序的接口,这个接口在往下操作是通过给wpa层发送命令字,通过socket实现;其二是wpa层,这里的改动才是最实质的通过解析framework层接口下发的命令字串添加或删除链表的设备数据。
后续根据需求,可能会写一篇关于双SSID的文章,感兴趣的同仁敬请期待!O(∩_∩)O哈哈哈~