本文旨在为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<String, WifiP2pDevice> getDevices (){
 +        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 [<BSSID>]" */
 +       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 <j@w1.fi>
 + *
 + * 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 <j@w1.fi>
 + *
 + * 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 <j@w1.fi>
 + *
 + * 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层接口下发的命令字串添加或删除链表的设备数据。