get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2232214/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2232214,
    "url": "http://patchwork.ozlabs.org/api/patches/2232214/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openwrt/patch/20260503231728.135249-2-andcov23@gmail.com/",
    "project": {
        "id": 45,
        "url": "http://patchwork.ozlabs.org/api/projects/45/?format=api",
        "name": "OpenWrt development",
        "link_name": "openwrt",
        "list_id": "openwrt-devel.lists.openwrt.org",
        "list_email": "openwrt-devel@lists.openwrt.org",
        "web_url": "http://openwrt.org/",
        "scm_url": "git://git.openwrt.org/openwrt.git",
        "webscm_url": "https://dev.openwrt.org/browser",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260503231728.135249-2-andcov23@gmail.com>",
    "list_archive_url": null,
    "date": "2026-05-03T23:17:28",
    "name": "[usteer,2/2] policy: add station policy exemption list",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "030cc0ff9c7f6c17f5f1e5fb137671bf10044acf",
    "submitter": {
        "id": 93316,
        "url": "http://patchwork.ozlabs.org/api/people/93316/?format=api",
        "name": "AndreaCovelli",
        "email": "andcov23@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openwrt/patch/20260503231728.135249-2-andcov23@gmail.com/mbox/",
    "series": [
        {
            "id": 502590,
            "url": "http://patchwork.ozlabs.org/api/series/502590/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openwrt/list/?series=502590",
            "date": "2026-05-03T23:17:27",
            "name": "[usteer,1/2] build: use apk-compatible package date version",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/502590/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2232214/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2232214/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=lists.infradead.org header.i=@lists.infradead.org\n header.a=rsa-sha256 header.s=bombadil.20210309 header.b=UX6uZw2f;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=b0eti7O2;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org\n (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org;\n envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from bombadil.infradead.org (bombadil.infradead.org\n [IPv6:2607:7c80:54:3::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g811R2Cr1z1yJ9\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 04 May 2026 09:18:51 +1000 (AEST)",
            "from localhost ([::1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1wJg4J-0000000Bvqu-0fBf;\n\tSun, 03 May 2026 23:17:47 +0000",
            "from mail-wm1-x330.google.com ([2a00:1450:4864:20::330])\n\tby bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1wJg4H-0000000Bvpz-0c2v\n\tfor openwrt-devel@lists.openwrt.org;\n\tSun, 03 May 2026 23:17:46 +0000",
            "by mail-wm1-x330.google.com with SMTP id\n 5b1f17b1804b1-4836d9d54f6so4874995e9.1\n        for <openwrt-devel@lists.openwrt.org>;\n Sun, 03 May 2026 16:17:44 -0700 (PDT)",
            "from DESKTOP-IA698K7.localdomain\n (host-95-234-201-26.retail.telecomitalia.it. [95.234.201.26])\n        by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a8fe3cd18sm64976325e9.0.2026.05.03.16.17.41\n        for <openwrt-devel@lists.openwrt.org>\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Sun, 03 May 2026 16:17:41 -0700 (PDT)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20210309; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=szRqNoJE+0URJarrofcuJvrJgA2Zlr7jTBooBBtK6fo=; b=UX6uZw2fQBw/96\n\tjcdpxsoiRwSIptGAb60GTwNUDy2kgPX+QabyW+8i+cvPrU2Wfyip4AL/6RFzgPpfb8RlMOeOjFqFM\n\tEW3DvJRjQWAkEgktv/oNCjwx0cKaqBYUGiiCWncuZ5iwnwN416xVXbU+h4oBJ2rWfajUA4clqLstF\n\tZtnreZkELYYzIXFbClc0FVLQ6+5N0+STT6XS3UQmzswV1xC56erwPdj3YPreveCBtJ0YYsPEUBlz1\n\tHTSE6B7aQiSLVzgCPcMncwjcTZNuCHmcB3fhno5an+O3T6YFh6QWTUtQaJMHumWt9oK31DdvIoZ9b\n\tvkPUw9H2AAk4D9JCjzqw==;",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1777850262; x=1778455062;\n darn=lists.openwrt.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n         :reply-to;\n        bh=P8Xnt/xXbLuFL3S/NkJx5IEeSFZ6+0pD+NivqOb5opA=;\n        b=b0eti7O2SJB91z7sv4SZjT19t4AEwh49Ky3eSgfv10L2t9LkQdZ0yf8iLvYnprOuZL\n         8P0XkRxTzXbLV2zIFe0FVYa6U2+syImnLLCB/h1qpv4ADoQ6E5oj01tCVwgujTy1f/bE\n         lJl18RNa1vU6gmVwEOLJisX7pX8PsN3JP0uzAU/itQdteFSfQ18OSimUvoA770JYvTmx\n         lw8EAkZ80HL/YcJfa2IUoovsaYbWAzWVnECLR8YqM7WpHBI5pGwL7VXyf4TWXGCOlaAQ\n         ZaCWnNxZhU9vndc2JnoJhw3421Ga8xMNapfOY34vJzOjyBNxtt/8I6IO9TRTmZKJsfd7\n         CCJQ=="
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1777850262; x=1778455062;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n         :cc:subject:date:message-id:reply-to;\n        bh=P8Xnt/xXbLuFL3S/NkJx5IEeSFZ6+0pD+NivqOb5opA=;\n        b=QpJ9vFh9qvc87Ud8MHSTufbDFsFAa+bKzgRYqlKnLVD4+m6MyAh/CqisOE5kAaZ7Bi\n         vypNGuoqtUgdHsJRXjX92jBXXrflo9RJEGTMrq/EpwdW0MbTXDbuO9JcmgWPAQvxjbdz\n         PD3OTBSVsrEhAyab34SR3kKpJ90nj0gh+p0UJTpIwyp+tnMXVkr3Nzgw1ehtkpcam311\n         cIG9ghU4UXOsgMXn++R6KMTLCzoVhpWNpTOz8+fkPTcmYa8V2YglZRFGvbtsAgu/QdBR\n         C26C5OKLPJ0fdGSloBilNsotWdsaThNbtwlykB/t5nlZiX0Vvu13wAAtWu+Bcib6g391\n         Oeww==",
        "X-Gm-Message-State": "AOJu0YxcTBuDQJbMAl6mCRNwZiFl93BWcCZtnwtveWVZiuii1+HwfUS+\n\thp0eVOFASsTsHjCG3zibRlCIYUNCeWa+mRkA0x4UkN+YpBNC4L1W2m0HNx1ChE2/",
        "X-Gm-Gg": "AeBDieua0+Lvq6W/o0PNv+YL6+i9rRfSXdeAzig7J12iKfaUMleT5JPWlS7m0rPQWO4\n\tH12SRfJAsDEr3RGVszGtl0wkDxr3MtbfCjWEy/X3010SNm+OrQq1pvufXTn0s0AkBPDtt45z5ig\n\tdl/uUOfSgewHCI3fepMokHiCVFFi18cSyh5zCy7io0sbi5CojKeGjXTQdc39SgEWBksd01TzK4G\n\tEzVvq7qFx/0/sBnwgXq7g5BglcdjPU2qZLBUIas5vOvXnCgFymW2/0mRj0SISRJ7WJNZLaiIl9q\n\tH9GA+nwIQHWa7qz7GQ60G7P1R8JzPhIiZGirhjOIas5/2LMM5HpR2BBFgRw3q/vPQRyrmSFFQcj\n\tMeEFQYdnZD+7puGyd0G2UTtdS1DLYxr7CeIlpjz47gOAgKD8wuwFYvNWsawIzvX2PIdtlRucB+x\n\tIuDD0t6dNiu9e2f75swMTMSArbMkfeeFQl75bmbeTzWx8gGOzVTrWyqNXyE6DdojSgDP9MySMHY\n\tERwQAq0dgyFIcFtxBpSXMyh2fj+l4K2swbUkIf6yKOg5m+IEbdoqxmlGIg=",
        "X-Received": "by 2002:a05:600c:8b27:b0:48d:1021:e5d1 with SMTP id\n 5b1f17b1804b1-48d1021e782mr1280125e9.3.1777850262282;\n        Sun, 03 May 2026 16:17:42 -0700 (PDT)",
        "From": "AndreaCovelli <andcov23@gmail.com>",
        "To": "openwrt-devel@lists.openwrt.org",
        "Subject": "[PATCH usteer 2/2] policy: add station policy exemption list",
        "Date": "Mon,  4 May 2026 01:17:28 +0200",
        "Message-ID": "<20260503231728.135249-2-andcov23@gmail.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20260503231728.135249-1-andcov23@gmail.com>",
        "References": "<20260503231728.135249-1-andcov23@gmail.com>",
        "MIME-Version": "1.0",
        "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ",
        "X-CRM114-CacheID": "sfid-20260503_161745_297139_62380DD9 ",
        "X-CRM114-Status": "GOOD (  20.53  )",
        "X-Spam-Score": "-1.8 (-)",
        "X-Spam-Report": "Spam detection software,\n running on the system \"bombadil.infradead.org\",\n has NOT identified this incoming email as spam.  The original\n message has been attached to this so you can view it or label\n similar future email.  If you have any questions, see\n the administrator of that system for details.\n Content preview:  Allow users to configure station MAC addresses that should\n    be exempt from steering policy decisions. Infrastructure links such as WDS\n    or Multi-AP backhaul stations can be associated to the same ESS as normal\n    clients. Steering or kicking those stations can disrupt downstream AP\n connectivity,\n    while spl [...]\n Content analysis details:   (-1.8 points, 5.0 required)\n  pts rule name              description\n ---- ----------------------\n --------------------------------------------------\n -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/, no\n                             trust\n                             [2a00:1450:4864:20:0:0:0:330 listed in]\n                             [list.dnswl.org]\n  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record\n -0.0 SPF_PASS               SPF: sender matches SPF record\n -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from\n                             envelope-from domain\n -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from\n author's\n                             domain\n -0.1 DKIM_VALID             Message has at least one valid DKIM or DK\n signature\n  0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n not necessarily valid\n -1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n                             [score: 0.0000]\n  0.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends in\n                             digit\n                             [andcov23(at)gmail.com]\n  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail\n provider\n                             [andcov23(at)gmail.com]",
        "X-BeenThere": "openwrt-devel@lists.openwrt.org",
        "X-Mailman-Version": "2.1.34",
        "Precedence": "list",
        "List-Id": "OpenWrt Development List <openwrt-devel.lists.openwrt.org>",
        "List-Unsubscribe": "<https://lists.openwrt.org/mailman/options/openwrt-devel>,\n <mailto:openwrt-devel-request@lists.openwrt.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.openwrt.org/pipermail/openwrt-devel/>",
        "List-Post": "<mailto:openwrt-devel@lists.openwrt.org>",
        "List-Help": "<mailto:openwrt-devel-request@lists.openwrt.org?subject=help>",
        "List-Subscribe": "<https://lists.openwrt.org/mailman/listinfo/openwrt-devel>,\n <mailto:openwrt-devel-request@lists.openwrt.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "\"openwrt-devel\" <openwrt-devel-bounces@lists.openwrt.org>",
        "Errors-To": "\n openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org"
    },
    "content": "Allow users to configure station MAC addresses that should be exempt\nfrom steering policy decisions.\n\nInfrastructure links such as WDS or Multi-AP backhaul stations can\nbe associated to the same ESS as normal clients. Steering or kicking\nthose stations can disrupt downstream AP connectivity, while splitting\nthe backhaul SSID is not always desirable.\n\nAdd a policy_exempt_sta_list config array and skip matching stations\nin request steering, roam transitions, delayed kicks, SNR/load kicks,\nlink measurement requests and BSS transition query handling. Keep exempt\nstations tracked and visible in ubus status output.\n\nSigned-off-by: AndreaCovelli <andcov23@gmail.com>\n---\nBuild-tested with CMake against locally built libubox/ubus dependencies.\nBuild-tested with OpenWrt SDK 25.12.2 mediatek/filogic for Cudy WR3000P\ntogether with patch 1/2.\nRuntime-tested on a Cudy WR3000P v1 with a WDS station in\npolicy_exempt_sta_list. Under aggressive roam scan settings, ubus reported\npolicy_exempt=true for the WDS station and no rrm_beacon_req was sent to it,\nwhile non-exempt clients still received beacon requests.\nRelated to GitHub PR #11, but keeps policy checks at the ubus action layer\nas a final guard for exempt stations.\n\n local_node.c                           |  6 ++++\n openwrt/usteer/files/etc/config/usteer |  4 +++\n openwrt/usteer/files/etc/init.d/usteer |  1 +\n policy.c                               | 19 ++++++++++\n sta.c                                  | 45 +++++++++++++++++++++++\n ubus.c                                 | 50 ++++++++++++++++++++++----\n usteer.h                               |  5 +++\n 7 files changed, 124 insertions(+), 6 deletions(-)",
    "diff": "diff --git a/local_node.c b/local_node.c\nindex e74d945..e89e843 100644\n--- a/local_node.c\n+++ b/local_node.c\n@@ -694,6 +694,9 @@ usteer_local_node_request_link_measurement(struct usteer_local_node *ln)\n \t\tif (si->connected != STA_CONNECTED)\n \t\t\tcontinue;\n \n+\t\tif (usteer_sta_is_policy_exempt(si->sta->addr))\n+\t\t\tcontinue;\n+\n \t\tusteer_ubus_trigger_link_measurement(si);\n \t}\n }\n@@ -744,6 +747,9 @@ usteer_local_node_process_bss_tm_queries(struct uloop_timeout *timeout)\n \t\tif (!sta)\n \t\t\tcontinue;\n \n+\t\tif (usteer_sta_is_policy_exempt(sta->addr))\n+\t\t\tcontinue;\n+\n \t\tsi = usteer_sta_info_get(sta, node, false);\n \t\tif (!si)\n \t\t\tcontinue;\ndiff --git a/openwrt/usteer/files/etc/config/usteer b/openwrt/usteer/files/etc/config/usteer\nindex f53c338..43f414f 100644\n--- a/openwrt/usteer/files/etc/config/usteer\n+++ b/openwrt/usteer/files/etc/config/usteer\n@@ -153,3 +153,7 @@ config usteer\n \n \t# List of SSIDs to enable steering on\n \t#list ssid_list ''\n+\n+\t# List of station MAC addresses to exempt from steering policy decisions,\n+\t# including automated kicks\n+\t#list policy_exempt_sta_list ''\ndiff --git a/openwrt/usteer/files/etc/init.d/usteer b/openwrt/usteer/files/etc/init.d/usteer\nindex 07fd99e..05a3f91 100755\n--- a/openwrt/usteer/files/etc/init.d/usteer\n+++ b/openwrt/usteer/files/etc/init.d/usteer\n@@ -71,6 +71,7 @@ uci_usteer() {\n \tuci_option_to_json_bool \"$cfg\" assoc_steering\n \tuci_option_to_json_string \"$cfg\" node_up_script\n \tuci_option_to_json_string_array \"$cfg\" ssid_list\n+\tuci_option_to_json_string_array \"$cfg\" policy_exempt_sta_list\n \tuci_option_to_json_string_array \"$cfg\" event_log_types\n \n \tfor opt in \\\ndiff --git a/policy.c b/policy.c\nindex 8c5d244..d047106 100644\n--- a/policy.c\n+++ b/policy.c\n@@ -176,6 +176,9 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type)\n \tint min_signal;\n \tbool ret = true;\n \n+\tif (usteer_sta_is_policy_exempt(si->sta->addr))\n+\t\tgoto out;\n+\n \tif (type == EVENT_TYPE_PROBE && !config.probe_steering)\n \t\tgoto out;\n \n@@ -381,6 +384,9 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si)\n \n bool usteer_policy_can_perform_roam(struct sta_info *si)\n {\n+\tif (usteer_sta_is_policy_exempt(si->sta->addr))\n+\t\treturn false;\n+\n \t/* Only trigger for connected STAs */\n \tif (si->connected != STA_CONNECTED)\n \t\treturn false;\n@@ -465,6 +471,11 @@ usteer_local_node_snr_kick(struct usteer_local_node *ln)\n \tev.threshold.ref = min_signal;\n \n \tlist_for_each_entry(si, &ln->node.sta_info, node_list) {\n+\t\tif (usteer_sta_is_policy_exempt(si->sta->addr)) {\n+\t\t\tsi->below_min_snr = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\tif (si->connected != STA_CONNECTED)\n \t\t\tcontinue;\n \n@@ -536,6 +547,9 @@ usteer_local_node_load_kick(struct usteer_local_node *ln)\n \tlist_for_each_entry(si, &ln->node.sta_info, node_list) {\n \t\tstruct sta_info *tmp;\n \n+\t\tif (usteer_sta_is_policy_exempt(si->sta->addr))\n+\t\t\tcontinue;\n+\n \t\tif (si->connected != STA_CONNECTED)\n \t\t\tcontinue;\n \n@@ -582,6 +596,11 @@ usteer_local_node_perform_kick(struct usteer_local_node *ln)\n \t\tif (!si->kick_time || si->kick_time > current_time)\n \t\t\tcontinue;\n \n+\t\tif (usteer_sta_is_policy_exempt(si->sta->addr)) {\n+\t\t\tsi->kick_time = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\tusteer_ubus_kick_client(si);\n \t}\n }\ndiff --git a/sta.c b/sta.c\nindex ed7e40e..9b53c87 100644\n--- a/sta.c\n+++ b/sta.c\n@@ -17,6 +17,13 @@\n  *   Copyright (C) 2020 John Crispin <john@phrozen.org> \n  */\n \n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <net/ethernet.h>\n+#ifdef linux\n+#include <netinet/ether.h>\n+#endif\n+\n #include \"usteer.h\"\n \n static int\n@@ -28,6 +35,44 @@ avl_macaddr_cmp(const void *k1, const void *k2, void *ptr)\n AVL_TREE(stations, avl_macaddr_cmp, false, NULL);\n static struct usteer_timeout_queue tq;\n \n+void config_set_policy_exempt_sta_list(struct blob_attr *data)\n+{\n+\tfree(config.policy_exempt_sta_list);\n+\n+\tif (data && blobmsg_len(data) &&\n+\t    blobmsg_check_attr_list(data, BLOBMSG_TYPE_STRING))\n+\t\tconfig.policy_exempt_sta_list = blob_memdup(data);\n+\telse\n+\t\tconfig.policy_exempt_sta_list = NULL;\n+}\n+\n+void config_get_policy_exempt_sta_list(struct blob_buf *buf)\n+{\n+\tif (config.policy_exempt_sta_list)\n+\t\tblobmsg_add_blob(buf, config.policy_exempt_sta_list);\n+}\n+\n+bool usteer_sta_is_policy_exempt(const uint8_t *addr)\n+{\n+\tstruct blob_attr *cur;\n+\tint rem;\n+\n+\tif (!addr || !config.policy_exempt_sta_list)\n+\t\treturn false;\n+\n+\tblobmsg_for_each_attr(cur, config.policy_exempt_sta_list, rem) {\n+\t\tuint8_t *exempt = (uint8_t *) ether_aton(blobmsg_get_string(cur));\n+\n+\t\tif (!exempt)\n+\t\t\tcontinue;\n+\n+\t\tif (!memcmp(exempt, addr, 6))\n+\t\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n static void\n usteer_sta_del(struct sta *sta)\n {\ndiff --git a/ubus.c b/ubus.c\nindex 40daf74..285a9ba 100644\n--- a/ubus.c\n+++ b/ubus.c\n@@ -39,6 +39,12 @@ blobmsg_open_table_mac(struct blob_buf *buf, uint8_t *addr)\n \treturn blobmsg_open_table(buf, str);\n }\n \n+static bool\n+usteer_ubus_sta_policy_exempt(struct sta_info *si)\n+{\n+\treturn si && si->sta && usteer_sta_is_policy_exempt(si->sta->addr);\n+}\n+\n static int\n usteer_ubus_get_clients(struct ubus_context *ctx, struct ubus_object *obj,\n \t\t       struct ubus_request_data *req, const char *method,\n@@ -55,6 +61,8 @@ usteer_ubus_get_clients(struct ubus_context *ctx, struct ubus_object *obj,\n \t\t\t_cur_n = blobmsg_open_table(&b, usteer_node_name(si->node));\n \t\t\tblobmsg_add_u8(&b, \"connected\", si->connected);\n \t\t\tblobmsg_add_u32(&b, \"signal\", si->signal);\n+\t\t\tblobmsg_add_u8(&b, \"policy_exempt\",\n+\t\t\t\t\tusteer_sta_is_policy_exempt(sta->addr));\n \t\t\tblobmsg_close_table(&b, _cur_n);\n \t\t}\n \t\tblobmsg_close_table(&b, _s);\n@@ -111,6 +119,8 @@ usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj,\n \t\t_cur_n = blobmsg_open_table(&b, usteer_node_name(si->node));\n \t\tblobmsg_add_u8(&b, \"connected\", si->connected);\n \t\tblobmsg_add_u32(&b, \"signal\", si->signal);\n+\t\tblobmsg_add_u8(&b, \"policy_exempt\",\n+\t\t\t\tusteer_sta_is_policy_exempt(sta->addr));\n \t\t_s = blobmsg_open_table(&b, \"stats\");\n \t\tfor (i = 0; i < __EVENT_TYPE_MAX; i++)\n \t\t\tusteer_ubus_add_stats(&si->stats[EVENT_TYPE_PROBE], event_types[i]);\n@@ -187,7 +197,8 @@ struct cfg_item {\n \t_cfg(ARRAY_CB, interfaces), \\\n \t_cfg(STRING_CB, node_up_script), \\\n \t_cfg(ARRAY_CB, event_log_types), \\\n-\t_cfg(ARRAY_CB, ssid_list)\n+\t_cfg(ARRAY_CB, ssid_list), \\\n+\t_cfg(ARRAY_CB, policy_exempt_sta_list)\n \n enum cfg_items {\n #define _cfg(_type, _name) CFG_##_name\n@@ -415,6 +426,8 @@ usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object *\n \n \t\t\ts = blobmsg_open_table_mac(&b, si->sta->addr);\n \t\t\tblobmsg_add_u32(&b, \"signal\", si->signal);\n+\t\t\tblobmsg_add_u8(&b, \"policy_exempt\",\n+\t\t\t\t\tusteer_sta_is_policy_exempt(si->sta->addr));\n \t\t\tblobmsg_add_u64(&b, \"created\", current_time - si->created);\n \t\t\tblobmsg_add_u64(&b, \"connected\", current_time - si->connected_since);\n \n@@ -674,7 +687,12 @@ int usteer_ubus_bss_transition_request(struct sta_info *si,\n \t\t\t\t       uint8_t validity_period,\n \t\t\t\t       struct usteer_node *target_node)\n {\n-\tstruct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);\n+\tstruct usteer_local_node *ln;\n+\n+\tif (usteer_ubus_sta_policy_exempt(si))\n+\t\treturn 0;\n+\n+\tln = container_of(si->node, struct usteer_local_node, node);\n \n \tblob_buf_init(&b, 0);\n \tblobmsg_printf(&b, \"addr\", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));\n@@ -692,10 +710,15 @@ int usteer_ubus_bss_transition_request(struct sta_info *si,\n \n int usteer_ubus_band_steering_request(struct sta_info *si)\n {\n-\tstruct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);\n+\tstruct usteer_local_node *ln;\n \tstruct usteer_node *node;\n \tvoid *c;\n \n+\tif (usteer_ubus_sta_policy_exempt(si))\n+\t\treturn 0;\n+\n+\tln = container_of(si->node, struct usteer_local_node, node);\n+\n \tblob_buf_init(&b, 0);\n \tblobmsg_printf(&b, \"addr\", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));\n \tblobmsg_add_u32(&b, \"dialog_token\", 0);\n@@ -717,7 +740,12 @@ int usteer_ubus_band_steering_request(struct sta_info *si)\n \n int usteer_ubus_trigger_link_measurement(struct sta_info *si)\n {\n-\tstruct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);\n+\tstruct usteer_local_node *ln;\n+\n+\tif (usteer_ubus_sta_policy_exempt(si))\n+\t\treturn 0;\n+\n+\tln = container_of(si->node, struct usteer_local_node, node);\n \n \tif (!usteer_sta_supports_link_measurement(si))\n \t\treturn 0;\n@@ -731,7 +759,12 @@ int usteer_ubus_trigger_link_measurement(struct sta_info *si)\n \n int usteer_ubus_trigger_client_scan(struct sta_info *si)\n {\n-\tstruct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);\n+\tstruct usteer_local_node *ln;\n+\n+\tif (usteer_ubus_sta_policy_exempt(si))\n+\t\treturn 0;\n+\n+\tln = container_of(si->node, struct usteer_local_node, node);\n \n \tif (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) {\n \t\tMSG(DEBUG, \"STA does not support beacon measurement sta=\" MAC_ADDR_FMT \"\\n\", MAC_ADDR_DATA(si->sta->addr));\n@@ -752,7 +785,12 @@ int usteer_ubus_trigger_client_scan(struct sta_info *si)\n \n void usteer_ubus_kick_client(struct sta_info *si)\n {\n-\tstruct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);\n+\tstruct usteer_local_node *ln;\n+\n+\tif (usteer_ubus_sta_policy_exempt(si))\n+\t\treturn;\n+\n+\tln = container_of(si->node, struct usteer_local_node, node);\n \n \tblob_buf_init(&b, 0);\n \tblobmsg_printf(&b, \"addr\", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));\ndiff --git a/usteer.h b/usteer.h\nindex f692fb8..8f7736c 100644\n--- a/usteer.h\n+++ b/usteer.h\n@@ -206,6 +206,7 @@ struct usteer_config {\n \tuint32_t event_log_mask;\n \n \tstruct blob_attr *ssid_list;\n+\tstruct blob_attr *policy_exempt_sta_list;\n };\n \n struct usteer_bss_tm_query {\n@@ -349,6 +350,7 @@ struct sta_info *usteer_sta_info_get(struct sta *sta, struct usteer_node *node,\n \n bool usteer_sta_supports_beacon_measurement_mode(struct sta_info *si, enum usteer_beacon_measurement_mode mode);\n bool usteer_sta_supports_link_measurement(struct sta_info *si);\n+bool usteer_sta_is_policy_exempt(const uint8_t *addr);\n \n void usteer_sta_disconnected(struct sta_info *si);\n void usteer_sta_info_update_timeout(struct sta_info *si, int timeout);\n@@ -376,6 +378,9 @@ void config_get_node_up_script(struct blob_buf *buf);\n void config_set_ssid_list(struct blob_attr *data);\n void config_get_ssid_list(struct blob_buf *buf);\n \n+void config_set_policy_exempt_sta_list(struct blob_attr *data);\n+void config_get_policy_exempt_sta_list(struct blob_buf *buf);\n+\n int usteer_interface_init(void);\n void usteer_interface_add(const char *name);\n void usteer_sta_node_cleanup(struct usteer_node *node);\n",
    "prefixes": [
        "usteer",
        "2/2"
    ]
}