diff --git a/src/agent.c b/src/agent.c
index daeaa1b1d42e90cce38f26d402468557041a8c28..e9627e061a66468d52d04b2fb5a45823fd4a4c8c 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -778,26 +778,10 @@ void agent_link_ap_to_cfg(struct agent *a)
 
 static void agent_config_load_post_action(struct agent *a)
 {
-	struct wifi_radio_element *re = NULL;
-
 	agent_link_ap_to_cfg(a);
 
 	if (a->cfg.pcfg)
 		a->pvid = a->cfg.pcfg->pvid;
-
-	/* Update restrict_stalist from assoc_ctrllist */
-	list_for_each_entry(re, &a->radiolist, list) {
-		struct netif_ap *p = NULL;
-
-		list_for_each_entry(p, &re->aplist, list) {
-
-			/* Copy restrictions from cfg to runtime */
-			assoc_ctrl_sync_from_config(a, p);
-
-			/* Block STAs in WiFi */
-			assoc_ctrl_apply_restriction(a, p);
-		}
-	}
 }
 
 int agent_config_reload(struct agent *a)
@@ -6586,6 +6570,9 @@ void agent_init_interfaces_post_actions(struct agent *a)
 		list_for_each_entry(ap, &re->aplist, list) {
 			int num_sta = ap->max_sta ? ap->max_sta : 128;
 
+			/* Block STas in WiFi if wifi is restarted at run-time */
+			assoc_ctrl_apply_restriction(a, ap);
+
 #if (EASYMESH_VERSION >= 6)
 			if (ap->is_affiliated_ap) {
 				struct wifi_mlsta mlsta[128] = {0};
@@ -6610,9 +6597,6 @@ void agent_init_interfaces_post_actions(struct agent *a)
 					wifi_add_sta(a, ap->ifname, &sta[i * 6]);
 			}
 
-			/* Block STas in WiFi if wifi is restarted at run-time */
-			assoc_ctrl_apply_restriction(a, ap);
-
 			/* Notify ctrl once upon start if adding STA is allowed */
 			if (ap->max_sta && !ap->sent_assocnotif) {
 				agent_notify_assoc_status(a, ap->bssid, num_sta >= ap->max_sta ? false : true);
@@ -6748,6 +6732,9 @@ int agent_init_interfaces(struct agent *a)
 				strncpy(fn->radio_name, re->name, IFNAMSIZ-1);
 				fn->sent_assocnotif = false;
 
+				/* Copy STA restrictions from file to runtime */
+				assoc_ctrl_sync_from_file(a, fn);
+
 				list_add(&fn->list, &re->aplist);
 			} else
 				continue;
diff --git a/src/assoc_ctrl.c b/src/assoc_ctrl.c
index 3fd867c201c75b05f56c00787bc55f3975431093..54ec5aef439d511a759f45c3bfccaff0aa6319a1 100644
--- a/src/assoc_ctrl.c
+++ b/src/assoc_ctrl.c
@@ -4,6 +4,9 @@
  * Copyright (C) 2025 IOPSYS Software Solutions AB. All rights reserved.
  *
  */
+#include <json-c/json.h>
+#include <libubox/blobmsg_json.h>
+
 #include <easymesh.h>
 
 #include "agent.h"
@@ -17,18 +20,328 @@
 #include "utils/debug.h"
 #include "utils/utils.h"
 
-static void assoc_ctrl_update_config(struct agent *a, uint8_t *mac,
-		struct netif_apcfg *cfg, int add)
+static void assoc_ctrl_remove_client(struct json_object *arr, uint8_t *macaddr)
+{
+	int len, i;
+
+	len = json_object_array_length(arr);
+	for (i = 0; i < len; i++) {
+		struct json_object *t;
+		const char *p;
+		uint8_t mac[6];
+
+		t = json_object_array_get_idx(arr, i);
+		if (!t) {
+			warn("%s: couldn't get entry:%d from restriction array",
+			     __func__, i);
+			continue;
+		}
+
+		p = json_get_string(t, "macaddr");
+		if (!p) {
+			warn("%s: couldn't get macaddr from entry:%d",
+			     __func__, i);
+			continue;
+		}
+
+		if (hwaddr_aton(p, mac) < 0) {
+			warn("%s: couldn't convert macaddr from entry:%d",
+			     __func__, i);
+			continue;
+		}
+
+		if (!memcmp(mac, macaddr, 6)) {
+			if (json_object_array_del_idx(arr, i, 1) < 0) {
+				warn("%s: couldn't remove entry:%d from restriction array",
+					 __func__, i);
+				return;
+			}
+			break;
+		}
+	}
+}
+
+static void assoc_ctrl_write_client(struct json_object *arr, uint8_t *macaddr,
+			uint16_t validity, uint8_t mode)
 {
-	char stastr[18] = {0};
+	struct json_object *val, *new;
+	char macstr[18] = {0};
+	char time_str[64] = {0};
+
+	if (!arr)
+		return;
+
+	if (!json_object_is_type(arr, json_type_array)) {
+		warn("%s: clients is not an array\n", __func__);
+		return;
+	}
+
+	/* remove client if it already exists */
+	assoc_ctrl_remove_client(arr, macaddr);
+
+	if (mode == ASSOC_CTRL_UNBLOCK)
+		/* client is unblocked, no need to add */
+		return;
+
+	new = json_object_new_object();
+	if (!new)
+		return;
+
+	/* macaddr */
+	snprintf(macstr, sizeof(macstr), MACFMT, MAC2STR(macaddr)); /* Flawfinder: ignore */
+	val = json_object_new_string(macstr);
+	if (!val)
+		return;
+	json_object_object_add(new, "macaddr", val);
+
+	/* start_time */
+	time_to_timestr(NULL, time_str);
+	val = json_object_new_string(time_str);
+	if (!val)
+		return;
+	json_object_object_add(new, "start_time", val);
+
+	/* duration */
+	val = json_object_new_int(validity);
+	if (!val)
+		return;
+	json_object_object_add(new, "duration", val);
 
-	hwaddr_ntoa(mac, stastr);
-	config_update2("mapagent", &a->cfg, "ap",
-		"ifname", cfg->name,
-		"assoc_ctrl", add, stastr, 18);
+	/* mode */
+	val = json_object_new_int(mode);
+	if (!val)
+		return;
+	json_object_object_add(new, "mode", val);
 
-	add ? stax_add_entry(&cfg->assoc_ctrllist, mac)
-		: stax_del_entry(&cfg->assoc_ctrllist, mac);
+	json_object_array_add(arr, new);
+}
+
+/* generate a restricted client entry if it does not exist */
+static int assoc_ctrl_update_restrict_file(uint8_t *bssid, uint8_t *macaddr,
+			uint16_t validity, uint8_t mode)
+{
+	struct json_object *restr_json;
+	struct json_object *bssids, *bssid_obj = NULL;
+	struct json_object *clients;
+	json_bool ret;
+	int len, i;
+
+	dbg("%s: file:%s\n", __func__, ASSOC_CTRL_FILE);
+
+	/* Get the json object from the file */
+	restr_json = json_object_from_file(ASSOC_CTRL_FILE);
+	if (!restr_json) {
+		dbg("%s: failed to read json:%s, error:%s. "\
+		     "Try to generate new\n", __func__,
+		     ASSOC_CTRL_FILE, json_util_get_last_err());
+
+		restr_json = json_object_new_object();
+		if (!restr_json) {
+			warn("%s: failed to create json obj, error:%s. ",
+			     __func__, json_util_get_last_err());
+			goto out;
+		}
+	}
+
+	/* Get the bssids array */
+	ret = json_object_object_get_ex(restr_json, "bssids", &bssids);
+	if (!ret) {
+		/* Create bssids array if not found */
+		bssids = json_object_new_array();
+		if (!bssids) {
+			warn("%s: failed to add bssid array, error:%s. ",
+			     __func__, json_util_get_last_err());
+			goto out_bssid;
+		}
+		json_object_object_add(restr_json, "bssids", bssids);
+	} else if (!json_object_is_type(bssids, json_type_array)) {
+		warn("%s: file: %s has wrong format\n",
+		     __func__, ASSOC_CTRL_FILE);
+		goto out_bssid;
+	}
+
+	/* Check if bssid already exists in bssid array */
+	len = json_object_array_length(bssids);
+	for (i = 0; i < len; i++) {
+		struct json_object *t;
+		uint8_t t_bssid[6];
+		const char *p;
+
+		t = json_object_array_get_idx(bssids, i);
+		if (!t) {
+			warn("%s: couldn't get entry:%d from bssid array", __func__, i);
+			continue;
+		}
+
+		p = json_get_string(t, "bssid");
+		if (!p) {
+			warn("%s: couldn't get bssid from entry:%d", __func__, i);
+			continue;
+		}
+
+		if (hwaddr_aton(p, t_bssid) < 0) {
+			warn("%s: couldn't convert bssid from entry:%d", __func__, i);
+			continue;
+		}
+
+		if (!memcmp(bssid, t_bssid, ETH_ALEN)) {
+			/* bssid already exists in file */
+			bssid_obj = t;
+			break;
+		}
+	}
+
+	/* Create new bssid object if not found */
+	if (!bssid_obj) {
+		char bssidstr[18] = {0};
+		struct json_object *val;
+
+		bssid_obj = json_object_new_object();
+		if (WARN_ON(!bssid_obj))
+			goto out_bssid;
+
+		/* bssid */
+		hwaddr_ntoa(bssid, bssidstr);
+		val = json_object_new_string(bssidstr);
+		if (!val) {
+			json_object_put(bssid_obj);
+			goto out_bssid;
+		}
+		json_object_object_add(bssid_obj, "bssid", val);
+
+		/* Add bssid object to bssids array */
+		json_object_array_add(bssids, bssid_obj);
+	}
+
+	/* Get the clients array */
+	ret = json_object_object_get_ex(bssid_obj, "clients", &clients);
+	if (!ret) {
+		/* Create client array if not found */
+		clients = json_object_new_array();
+		if (!clients) {
+			json_object_put(bssid_obj);
+			goto out_bssid;
+		}
+		json_object_object_add(bssid_obj, "clients", clients);
+	} else {
+		if (!json_object_is_type(clients, json_type_array)) {
+			warn("|%s:%d| file:%s is not expected format\n", __func__,
+			     __LINE__, ASSOC_CTRL_FILE);
+			json_object_put(bssid_obj);
+			goto out_bssid;
+		}
+	}
+
+	/* Add (or remove) the client entry */
+	assoc_ctrl_write_client(clients, macaddr, validity, mode);
+
+	/* Update restricted clients file */
+	json_object_to_file(ASSOC_CTRL_FILE, restr_json);
+
+out_bssid:
+	json_object_put(restr_json);
+out:
+	return 0;
+}
+
+struct rsta {
+	uint8_t macaddr[6];
+	uint8_t mode;
+	uint16_t validity;
+};
+
+int assoc_ctrl_read_restrictions(struct agent *a, uint8_t *bssid,
+			struct rsta *fr, int *num_fr)
+{
+	struct blob_buf bssids = { 0 };
+	struct blob_attr *b;
+	static const struct blobmsg_policy attr[] = {
+		[0] = { .name = "bssids", .type = BLOBMSG_TYPE_ARRAY },
+	};
+	struct blob_attr *tb[ARRAY_SIZE(attr)];
+	int rem;
+	int ret = 0;
+
+	blob_buf_init(&bssids, 0);
+
+	if (!blobmsg_add_json_from_file(&bssids, ASSOC_CTRL_FILE)) {
+		warn("Failed to parse %s\n", ASSOC_CTRL_FILE);
+		ret = -1;
+		goto out;
+	}
+
+	blobmsg_parse(attr, ARRAY_SIZE(attr), tb, blob_data(bssids.head), blob_len(bssids.head));
+
+	if (!tb[0])
+		goto out;
+
+	blobmsg_for_each_attr(b, tb[0], rem) {
+		static const struct blobmsg_policy bssid_attr[2] = {
+			[0] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+			[1] = { .name = "clients", .type = BLOBMSG_TYPE_ARRAY },
+		};
+		struct blob_attr *tb1[ARRAY_SIZE(bssid_attr)];
+		char bssid_str[18] = {0};
+		uint8_t bssid_mac[6] = {0};
+		struct blob_attr *client;
+		int rem1;
+
+		blobmsg_parse(bssid_attr, ARRAY_SIZE(bssid_attr), tb1, blobmsg_data(b), blob_len(b));
+		if (!tb1[0] || !tb1[1])
+			continue;
+
+		strncpy(bssid_str, blobmsg_data(tb1[0]), sizeof(bssid_str) - 1);
+		if (hwaddr_aton(bssid_str, bssid_mac) < 0) {
+			warn("Failed to convert macaddr %s\n", bssid_str);
+			continue;
+		}
+
+		if (memcmp(bssid, bssid_mac, ETH_ALEN))
+			continue;
+
+		blobmsg_for_each_attr(client, tb1[1], rem1) {
+			static const struct blobmsg_policy client_attr[4] = {
+				[0] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+				[1] = { .name = "start_time", .type = BLOBMSG_TYPE_STRING },
+				[2] = { .name = "duration", .type = BLOBMSG_TYPE_INT32 },
+				[3] = { .name = "mode", .type = BLOBMSG_TYPE_INT32 },
+			};
+			struct blob_attr *tb2[ARRAY_SIZE(client_attr)];
+			char mac_str[18] = {0};
+			uint8_t macaddr[6] = {0};
+			int32_t duration, elapsed;
+			time_t start, now = time(NULL);
+
+			blobmsg_parse(client_attr, ARRAY_SIZE(client_attr), tb2, blobmsg_data(client), blob_len(client));
+			if (!tb2[0] || !tb2[1] || !tb2[2] || !tb2[3])
+				continue;
+
+			strncpy(mac_str, blobmsg_data(tb2[0]), sizeof(mac_str) - 1);
+			if (hwaddr_aton(mac_str, macaddr) < 0) {
+				warn("Failed to convert macaddr %s\n", mac_str);
+				continue;
+			}
+
+			memcpy(fr[*num_fr].macaddr, macaddr, ETH_ALEN);
+			fr[*num_fr].mode = blobmsg_get_u32(tb2[3]);
+			start = timestr_to_time(blobmsg_get_string(tb2[1]));
+			duration = blobmsg_get_u32(tb2[2]);
+			elapsed = (int32_t)difftime(now, start);
+			if (elapsed < 0 || elapsed > duration) {
+				fr[*num_fr].validity = 0;
+			} else {
+				fr[*num_fr].validity = duration - elapsed;
+				/* TODO: remove outdated entry from file */
+			}
+
+			(*num_fr)++;
+		}
+	}
+
+out:
+	blob_buf_free(&bssids);
+
+	return ret;
 }
 
 static void agent_disconnect_stas(struct agent *a, int num_sta,
@@ -110,6 +423,7 @@ static void wifi_sta_restrict_timeout_cb(atimer_t *t)
 
 	/* Unblock STA */
 	wifi_restrict_sta(ap, s->macaddr, false);
+	assoc_ctrl_update_restrict_file(ap->bssid, s->macaddr, 0, ASSOC_CTRL_UNBLOCK);
 	list_del(&s->list);
 	free(s);
 }
@@ -126,47 +440,49 @@ static struct restrict_sta_entry *find_restricted_sta(struct netif_ap *ap, uint8
 }
 
 int assoc_ctrl_add_sta(struct agent *a, struct netif_ap *ap,
-		uint32_t num_sta, uint8_t sta_list[][6],
-		uint16_t validity_period, uint8_t mode,
+		uint32_t num_fr, struct rsta fr[],
 		bool update_config)
 {
 	trace("agent: %s: --->\n", __func__);
 
 	int i = 0;
 
-	if (!sta_list)
+	if (!fr)
 		return -1;
 
-	for (i = 0; i < num_sta; i++) {
+	for (i = 0; i < num_fr; i++) {
 		struct restrict_sta_entry *s;
 
-		s = find_restricted_sta(ap, sta_list[i]);
+		s = find_restricted_sta(ap, fr[i].macaddr);
 		if (!s) {
 			/* Add new entry to restricted list */
 			s = calloc(1, sizeof(struct restrict_sta_entry));
 			if (!s)
 				return -1;
 
-			memcpy(s->macaddr, sta_list[i], 6);
+			memcpy(s->macaddr, fr[i].macaddr, 6);
 			memcpy(s->bssid, ap->bssid, 6);
 			s->agent = a;
-			s->mode = mode;
+			s->mode = fr[i].mode;
 			list_add_tail(&s->list, &ap->restrict_stalist);
 
 			timer_init(&s->restrict_timer, wifi_sta_restrict_timeout_cb);
 		}
 
-		if (validity_period > 0)
-			/* If timeout is positive, create a timed sta assoc-control
-			 * entry but don't update config. At the timer expiry, remove
-			 * sta from assoc-control list.
-			 */
-			timer_set(&s->restrict_timer, validity_period * 1000);
-		else if (update_config)
-			/* If timeout is 0 or negative, permanently add sta to the
-			 * AP's assoc control list by creating a config entry.
-			 */
-			assoc_ctrl_update_config(a, sta_list[i], ap->cfg, 1);
+		/* Update validity timer */
+		if ((s->mode == ASSOC_CTRL_TIMED_BLOCK || s->mode == ASSOC_CTRL_BLOCK)) {
+			if (fr[i].validity > 0)
+				timer_set(&s->restrict_timer, fr[i].validity * 1000);
+			else {
+				/* error */
+				continue;
+			}
+		}
+
+		/* Update restriction file */
+		if (update_config)
+			assoc_ctrl_update_restrict_file(ap->bssid,
+					fr[i].macaddr, fr[i].validity, fr[i].mode);
 	}
 
 	return 0;
@@ -177,13 +493,27 @@ int assoc_ctrl_block_sta(struct agent *a, struct netif_ap *ap,
 		uint32_t num_sta, uint8_t sta_list[][6])
 {
 	trace("agent: %s: --->\n", __func__);
+
+	struct rsta fr[ASSOC_CTRL_MAX_STA];
+	int num_fr = 0;
 	int ret = 0;
 
-	/* Add STA to restricted list */
-	ret = assoc_ctrl_add_sta(a, ap, num_sta, sta_list,
-			validity_period, mode, true);
+	if (num_sta > ASSOC_CTRL_MAX_STA) {
+		err("[%s:%d] Invalid number of STAs\n", __func__, __LINE__);
+		return -1;
+	}
+
+	for (int i = 0; i < num_sta; i++) {
+		memcpy(fr[num_fr].macaddr, sta_list[i], ETH_ALEN);
+		fr[num_fr].mode = mode;
+		fr[num_fr].validity = validity_period;
+		num_fr++;
+	}
+
+	/* Add STAs to runtime & file lists */
+	ret = assoc_ctrl_add_sta(a, ap, num_fr, fr, true);
 	if (!ret)
-		/* Block STA in WiFi */
+		/* Block STAs in WiFi */
 		ret = assoc_ctrl_restrict_sta(a, num_sta, sta_list, ap, mode);
 
 	return ret;
@@ -201,18 +531,21 @@ int assoc_ctrl_del_sta(struct agent *a, struct netif_ap *ap,
 		return -1;
 
 	for (i = 0; i < num_sta; i++) {
-		/* Stop validity timer and remove entry from restricted list */
+
+		/* Stop validity timer and remove entry from runtime list */
 		list_for_each_entry_safe(s, tmp, &ap->restrict_stalist, list) {
 			if (!memcmp(s->macaddr, sta_list[i], 6)) {
-				if (update_config)
-					/* Update config to remove the STA */
-					assoc_ctrl_update_config(a, sta_list[i], ap->cfg, 0);
-
 				timer_del(&s->restrict_timer);
 				list_del(&s->list);
 				free(s);
 			}
 		}
+
+		/* Remove STA from restriction file */
+		if (update_config) {
+			assoc_ctrl_update_restrict_file(ap->bssid,
+					sta_list[i], 0, ASSOC_CTRL_UNBLOCK);
+		}
 	}
 
 	return 0;
@@ -224,52 +557,52 @@ int assoc_ctrl_unblock_sta(struct agent *a, struct netif_ap *ap,
 	trace("agent: %s: --->\n", __func__);
 	int ret = 0;
 
-	/* Remove STA from restricted list */
+	/* Remove STAs from runtime and file lists */
 	ret = assoc_ctrl_del_sta(a, ap, num_sta, sta_list, true);
 	if (!ret)
-		/* Unblock STA in WiFi */
+		/* Unblock STAs in WiFi */
 		ret = assoc_ctrl_restrict_sta(a, num_sta, sta_list, ap, ASSOC_CTRL_UNBLOCK);
 
 	return ret;
 }
 
-int assoc_ctrl_sync_from_config(struct agent *a, struct netif_ap *ap)
+/* Sync runtime list from file list only - do not apply restriction */
+int assoc_ctrl_sync_from_file(struct agent *a, struct netif_ap *ap)
 {
 	trace("agent: %s: --->\n", __func__);
 
-	struct stax *x = NULL;
+	struct rsta fr[ASSOC_CTRL_MAX_STA];
+	int num_fr = 0;
 	struct restrict_sta_entry *s = NULL;
-	uint8_t stalist[MAX_STA][6] = {0};
-	int num_sta = 0;
 	int ret = 0;
 
-	/* 1. Add STAs missing in runtime list */
-	list_for_each_entry(x, &ap->cfg->assoc_ctrllist, list) {
-		memcpy(stalist[num_sta++], x->macaddr, 6);
-	}
+	/* Read STA restrictions from file list */
+	ret = assoc_ctrl_read_restrictions(a, ap->bssid, fr, &num_fr);
+	if (ret)
+		return ret;
 
-	if (num_sta > 0)
-		/* Update the runtime list and restart timer */
-		ret |= assoc_ctrl_add_sta(a, ap, num_sta, stalist,
-				0 /* FIXME tmo from cfg */,
-				ASSOC_CTRL_INDEF_BLOCK /* FIXME mode from cfg */,
-				false);
+	/* 1. Add/Update STAs: file list -> runtime list */
+	if (num_fr > 0)
+		ret |= assoc_ctrl_add_sta(a, ap, num_fr, fr, false);
 
-	/* 2. Remove STAs that are not in config list */
+	/* 2. Remove STAs from runtime if not present in file */
 	list_for_each_entry(s, &ap->restrict_stalist, list) {
 		bool found = false;
 		int i = 0;
 
-		for (i = 0; i < num_sta; i++) {
-			if (!memcmp(stalist[i], x->macaddr, 6)) {
+		for (i = 0; i < num_fr; i++) {
+			if (!memcmp(fr[i].macaddr, s->macaddr, 6)) {
 				found = true;
 				break;
 			}
 		}
 
 		if (!found) {
+			uint8_t sta_list[1][6];
+
 			/* Remove STA from runtime list */
-			ret |= assoc_ctrl_del_sta(a, ap, 1, &x->macaddr, false);
+			memcpy(sta_list[0], s->macaddr, 6);
+			ret |= assoc_ctrl_del_sta(a, ap, 1, sta_list, false);
 		}
 	}
 
@@ -284,7 +617,6 @@ int assoc_ctrl_apply_restriction(struct agent *a, struct netif_ap *ap)
 	uint8_t wifi_res_stas[ASSOC_CTRL_MAX_STA * 6] = {0};
 	int num_wifi_res_stas = ASSOC_CTRL_MAX_STA;
 	struct restrict_sta_entry *s = NULL;
-	int i;
 	int ret = 0;
 
 	if (list_empty(&ap->restrict_stalist))
@@ -297,24 +629,44 @@ int assoc_ctrl_apply_restriction(struct agent *a, struct netif_ap *ap)
 		return -1;
 	}
 
-	/* Invoke block_sta for STAs that are in runtime list but not in blocked_stas */
+	/* Invoke block_sta for STAs on runtime list not blocked in Wi-Fi */
 	list_for_each_entry(s, &ap->restrict_stalist, list) {
+		bool blocked = false;
+		int i;
 
 		for (i = 0; i < num_wifi_res_stas; i++) {
+			if (!memcmp(&wifi_res_stas[i * 6], s->macaddr, 6)) {
+				/* STA blocked in WiFi */
+				blocked = true;
+				break;
+			}
+		}
 
-			if (!memcmp(&wifi_res_stas[i * 6], s->macaddr, 6))
-				/* STA already blocked in WiFi */
-				continue;
+		if (blocked) {
+			/* STA already blocked in WiFi */
+			dbg("%s: STA already blocked in WiFi\n", __func__);
+			continue;
+		}
 
-			assoc_ctrl_restrict_sta(a, 1, &s->macaddr, ap, s->mode);
+		if ((s->mode == ASSOC_CTRL_TIMED_BLOCK || s->mode == ASSOC_CTRL_BLOCK)
+				&& !timer_pending(&s->restrict_timer)) {
+			/* Timer expired: do not block in WiFi */
+			dbg("%s: Timer expired for " MACFMT " - won't block in WiFi\n",
+			    __func__, MAC2STR(s->macaddr));
+			continue;
 		}
+
+		dbg("%s: Block STA: " MACFMT " in %s\n",
+		    __func__, MAC2STR(s->macaddr), ap->ifname);
+		assoc_ctrl_restrict_sta(a, 1, &s->macaddr, ap, s->mode);
 	}
 
-	/* Theoretically, it could be blocked for other reasons, i.e. network admin-issued block
-	 * manually or via webGUI. Uncomment this part if we want to unblock STAs anyway.
+	/* Theoretically, it could be blocked for other reasons,
+	 * i.e. network admin-issued block, manually or via webGUI.
+	 * Uncomment following code if we want to unblock STAs anyway.
 	 */
 #if 0
-	/* Invoke unblock_sta for STAs that are in blocked_stas but not in runtime list */
+	/* Unblock STAs in Wi-FI if not found on runtime list */
 	for (i = 0; i < num_wifi_res_stas; i++) {
 		bool found = false;
 
@@ -398,7 +750,7 @@ int assoc_ctrl_process_request(void *agent, uint8_t *p,
 	}
 
 	switch (data->control) {
-	case ASSOC_CTRL_BLOCK:
+	case ASSOC_CTRL_BLOCK: /* Client Blocking */
 		/* Block - check for an Error Scenario:
 		 * Send an error TLV in case STA is already associated
 		 * with the BSSID for which the 'Block' mode is being set.
@@ -425,8 +777,8 @@ int assoc_ctrl_process_request(void *agent, uint8_t *p,
 			goto send_ack;
 		}
 		/* no break - checkpatch ignore */
-	case ASSOC_CTRL_TIMED_BLOCK:
-		/* tmo needed for block and timed block modes */
+	case ASSOC_CTRL_TIMED_BLOCK: /* Timed Block */
+		/* Validity Period mandatory for Client Blocking and Timed Block */
 		validity_period = BUF_GET_BE16(data->validity_period);
 		if (!validity_period) {
 			warn("Validity period unset, while expected!\n");
@@ -434,12 +786,12 @@ int assoc_ctrl_process_request(void *agent, uint8_t *p,
 			goto send_ack;
 		}
 		/* no break - checkpatch ignore */
-	case ASSOC_CTRL_INDEF_BLOCK:
+	case ASSOC_CTRL_INDEF_BLOCK: /* Indefinite Block */
 		/* Add STA to blocking list for block/timed block/indef block */
 		WARN_ON(assoc_ctrl_block_sta(a, ap, validity_period, data->control,
 					data->num_sta, sta_list));
 		break;
-	case ASSOC_CTRL_UNBLOCK:
+	case ASSOC_CTRL_UNBLOCK: /* Client Unblocking */
 		/* Rem STA from blocking list and stop the restrict timer */
 		WARN_ON(assoc_ctrl_unblock_sta(a, ap, data->num_sta, sta_list));
 		break;
diff --git a/src/assoc_ctrl.h b/src/assoc_ctrl.h
index b16e0e68c11562f93aadd8f7d59c73bba1bfc723..575e7ff66ba732f546ae5df2a540f15e253db31a 100644
--- a/src/assoc_ctrl.h
+++ b/src/assoc_ctrl.h
@@ -7,16 +7,21 @@
 struct agent;
 struct netif_ap;
 
+#if defined MAX_STA && MAX_STA > 0 && MAX_STA <= 32
+#define ASSOC_CTRL_MAX_STA MAX_STA
+#else
 #define ASSOC_CTRL_MAX_STA 32
+#endif
+
+#define ASSOC_CTRL_FILE "/etc/multiap/assoc_ctrl.json"
 
 int assoc_ctrl_block_sta(struct agent *a, struct netif_ap *ap,
 		uint16_t validity_period, uint8_t mode,
 		uint32_t sta_count, uint8_t stalist[][6]);
 int assoc_ctrl_unblock_sta(struct agent *a, struct netif_ap *ap,
 		uint32_t sta_count, uint8_t stalist[][6]);
-int assoc_ctrl_sync_from_config(struct agent *a, struct netif_ap *ap);
+int assoc_ctrl_sync_from_file(struct agent *a, struct netif_ap *ap);
 int assoc_ctrl_apply_restriction(struct agent *a, struct netif_ap *ap);
 int assoc_ctrl_process_request(void *agent, uint8_t *p, struct cmdu_buff *cmdu);
 int assoc_ctrl_reapply(struct netif_ap *ap);
-
 #endif