diff --git a/feeds/wlan-ap/nft-qos/Makefile b/feeds/wlan-ap/nft-qos/Makefile index 7129219cd..68eccba01 100644 --- a/feeds/wlan-ap/nft-qos/Makefile +++ b/feeds/wlan-ap/nft-qos/Makefile @@ -48,13 +48,8 @@ define Package/nft-qos/install $(INSTALL_DIR) $(1)/lib/nft-qos $(INSTALL_DATA) ./files/lib/* $(1)/lib/nft-qos/ chmod 0700 $(1)/lib/nft-qos/mac-rate.sh - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./files/nft-qos.config $(1)/etc/config/nft-qos $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/nft-qos.init $(1)/etc/init.d/nft-qos - $(INSTALL_DIR) $(1)/etc/hotplug.d/dhcp - $(INSTALL_BIN) ./files/nft-qos-monitor.hotplug $(1)/etc/hotplug.d/dhcp/00-nft-qos-monitor - $(INSTALL_BIN) ./files/nft-qos-dynamic.hotplug $(1)/etc/hotplug.d/dhcp/01-nft-qos-dynamic endef $(eval $(call BuildPackage,nft-qos)) diff --git a/feeds/wlan-ap/nft-qos/files/lib/mac-rate.sh b/feeds/wlan-ap/nft-qos/files/lib/mac-rate.sh index 59dfc5d31..ecbbf6721 100755 --- a/feeds/wlan-ap/nft-qos/files/lib/mac-rate.sh +++ b/feeds/wlan-ap/nft-qos/files/lib/mac-rate.sh @@ -27,23 +27,31 @@ if [ -z "$1" -o -z "$2" -o -z "$3" ]; then exit 1 fi -logger -t "$1 $2 $3" +logger -t "mac-rate" "$1 $2 $3" + +bridge=`uci get wireless.$iface.network` +if [ "$bridge" == "lan" ]; then + dlchain="download_nat" + ulchain="upload_nat" +else + dlchain="download" + ulchain="upload" +fi if [ "$1" == "add" ]; then config_load wireless config_foreach handle_interface wifi-iface download - - exists=`nft list chain bridge nft-qos-ssid-lan-bridge download -a | grep -ic $3` + exists=`nft list chain bridge nft-qos-ssid-lan-bridge $dlchain -a | grep -ic $3` logger -t "mac-rate" "exists = $exists" if [ "$exists" -ne 0 ]; then - old_drate=`nft list chain bridge nft-qos-ssid-lan-bridge download -a | grep -i $3 | awk -F'kbytes' '{print $1}' | awk '{print $NF}'` + old_drate=`nft list chain bridge nft-qos-ssid-lan-bridge $dlchain -a | grep -i $3 | awk -F'kbytes' '{print $1}' | awk '{print $NF}'` logger -t "mac-rate" "old_drate=$old_drate" if [ "$old_drate" -ne "$rate" ]; then changed=1 - id=`nft list chain bridge nft-qos-ssid-lan-bridge download -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` + id=`nft list chain bridge nft-qos-ssid-lan-bridge $dlchain -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` if [ -n "$id" ]; then - nft delete rule bridge nft-qos-ssid-lan-bridge download handle $id + nft delete rule bridge nft-qos-ssid-lan-bridge $dlchain handle $id fi logger -t "mac-rate" "changed DL $old_drate to $rate, del $3" else @@ -54,19 +62,19 @@ if [ "$1" == "add" ]; then if [ "$exists" == 0 -o "$changed" == 1 ]; then if [ "$rate" -ne 0 ]; then - dok=`nft add rule bridge nft-qos-ssid-lan-bridge download ether daddr $3 limit rate over $rate kbytes/second drop` + dok=`nft add rule bridge nft-qos-ssid-lan-bridge $dlchain ether daddr $3 limit rate over $rate kbytes/second drop` fi fi config_foreach handle_interface wifi-iface upload - exists=`nft list chain bridge nft-qos-ssid-lan-bridge upload -a | grep -ic $3` + exists=`nft list chain bridge nft-qos-ssid-lan-bridge $ulchain -a | grep -ic $3` if [ "$exists" -ne 0 ]; then - old_urate=`nft list chain bridge nft-qos-ssid-lan-bridge upload -a | grep -i $3 | awk -F'kbytes' '{print $1}' | awk '{print $NF}'` + old_urate=`nft list chain bridge nft-qos-ssid-lan-bridge $ulchain -a | grep -i $3 | awk -F'kbytes' '{print $1}' | awk '{print $NF}'` if [ "$old_urate" -ne "$rate" ]; then changed=1 - id=`nft list chain bridge nft-qos-ssid-lan-bridge upload -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` + id=`nft list chain bridge nft-qos-ssid-lan-bridge $ulchain -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` if [ -n "$id" ]; then - nft delete rule bridge nft-qos-ssid-lan-bridge upload handle $id + nft delete rule bridge nft-qos-ssid-lan-bridge $ulchain handle $id fi logger -t "mac-rate" "changed UL $old_urate to $rate del $3" @@ -78,20 +86,20 @@ if [ "$1" == "add" ]; then if [ "$exists" == 0 -o "$changed" == 1 ]; then if [ "$rate" -ne 0 ]; then - uok=`nft add rule bridge nft-qos-ssid-lan-bridge upload ether saddr $3 limit rate over $rate kbytes/second drop` + uok=`nft add rule bridge nft-qos-ssid-lan-bridge $ulchain ether saddr $3 limit rate over $rate kbytes/second drop` fi fi elif [ "$1" == "del" ]; then - id=`nft list chain bridge nft-qos-ssid-lan-bridge download -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` + id=`nft list chain bridge nft-qos-ssid-lan-bridge $dlchain -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` logger -t "mac-rate" "$id $3" if [ -n "$id" ]; then - nft delete rule bridge nft-qos-ssid-lan-bridge download handle $id + nft delete rule bridge nft-qos-ssid-lan-bridge $dlchain handle $id fi - id=`nft list chain bridge nft-qos-ssid-lan-bridge upload -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` + id=`nft list chain bridge nft-qos-ssid-lan-bridge $ulchain -a | grep -i $3 | awk -F "handle " '{print $2;exit}'` if [ -n "$id" ]; then - nft delete rule bridge nft-qos-ssid-lan-bridge upload handle $id + nft delete rule bridge nft-qos-ssid-lan-bridge $ulchain handle $id fi fi diff --git a/feeds/wlan-ap/nft-qos/files/lib/ssid_ratelimit.sh b/feeds/wlan-ap/nft-qos/files/lib/ssid_ratelimit.sh index 8cc33c2c5..20b024f2d 100644 --- a/feeds/wlan-ap/nft-qos/files/lib/ssid_ratelimit.sh +++ b/feeds/wlan-ap/nft-qos/files/lib/ssid_ratelimit.sh @@ -42,8 +42,20 @@ qosdef_append_rule_ssid() { #
rate=$((rate/8)) fi - if [ -z "$iface" -o -z "$rate" -o $rate == 0 ]; then - logger -t "nft-qos" "Error: No interface $iface or rate $rate present" + if [ -z "$iface" ]; then + logger -t "nft-qos" "Error: No interface $iface present" + return + fi + + if [ -z "$rate" -o $rate == 0 ]; then + logger -t "nft-qos" "ssid-rate disabled $iface, configure client-rate" + maclist=`iwinfo $iface assoclist | grep dBm | cut -f 1 -s -d" "` + + for mac in $maclist + do + logger -t "nft-qos" "Add $mac" + /lib/nft-qos/mac-rate.sh add $iface $mac + done return fi diff --git a/feeds/wlan-ap/nft-qos/files/nft-qos.init b/feeds/wlan-ap/nft-qos/files/nft-qos.init index fb367f7ff..b49cd94ee 100755 --- a/feeds/wlan-ap/nft-qos/files/nft-qos.init +++ b/feeds/wlan-ap/nft-qos/files/nft-qos.init @@ -4,49 +4,26 @@ # . /lib/nft-qos/core.sh -. /lib/nft-qos/monitor.sh -. /lib/nft-qos/dynamic.sh -. /lib/nft-qos/static.sh -. /lib/nft-qos/priority.sh . /lib/nft-qos/ssid_ratelimit.sh START=99 USE_PROCD=1 service_triggers() { -# procd_add_reload_trigger nft-qos wireless -# procd_add_reload_trigger wireless procd_open_validate -# qosdef_validate_dynamic -# qosdef_validate_static -# qosdef_validate_priority procd_close_validate } start_service() { config_load nft-qos - -# qosdef_init_env -# qosdef_flush_static -# qosdef_flush_dynamic qosdef_flush_ssid_ratelimit -# qosdef_remove_priority - -# qosdef_init_header -# qosdef_init_monitor -# qosdef_validate_dynamic default qosdef_init_dynamic -# qosdef_validate_static default qosdef_init_static -# qosdef_validate_priority default qosdef_init_priority qosdef_init_ssid_ratelimit qosdef_init_done qosdef_start } stop_service() { -# qosdef_flush_dynamic -# qosdef_flush_static -# qosdef_remove_priority qosdef_flush_ssid_ratelimit qosdef_clean_cache } diff --git a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/radio_nl80211.c b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/radio_nl80211.c index e2e4af5be..76e6e1445 100644 --- a/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/radio_nl80211.c +++ b/feeds/wlan-ap/opensync/src/platform/openwrt/src/lib/target/src/radio_nl80211.c @@ -103,7 +103,7 @@ static void vif_add_sta_rate_rule(uint8_t *addr, char *ifname) char *rule; ssize_t rule_sz; - LOGI("Add mac rate rule: %s %02X:%02X:%02X:%02X:%02X:%02X", + LOGI("Add mac rate rule:%s: %02X:%02X:%02X:%02X:%02X:%02X", ifname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); rule_sz = snprintf(NULL, 0, "/lib/nft-qos/mac-rate.sh add %s %02X:%02X:%02X:%02X:%02X:%02X", @@ -123,7 +123,7 @@ static void vif_del_sta_rate_rule(uint8_t *addr, char *ifname) char *rule; ssize_t rule_sz; - LOGI("Del mac rate rule: %s %02X:%02X:%02X:%02X:%02X:%02X", + LOGI("Del mac rate rule:%s: %02X:%02X:%02X:%02X:%02X:%02X", ifname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); rule_sz = snprintf(NULL, 0, "/lib/nft-qos/mac-rate.sh del %s %02X:%02X:%02X:%02X:%02X:%02X", @@ -147,11 +147,10 @@ static void nl80211_add_station(struct nlattr **tb, char *ifname) return; addr = nla_data(tb[NL80211_ATTR_MAC]); + vif_add_sta_rate_rule(addr, ifname); sta = avl_find_element(&sta_tree, addr, sta, avl); - if (sta) { - vif_add_sta_rate_rule(addr, ifname); + if (sta) return; - } wif = avl_find_element(&wif_tree, ifname, wif, avl); if (!wif) @@ -168,7 +167,6 @@ static void nl80211_add_station(struct nlattr **tb, char *ifname) list_add(&sta->iface, &wif->stas); vif_add_station(sta, ifname, 1); - vif_add_sta_rate_rule(addr, ifname); } static void _nl80211_del_station(char *ifname, struct wifi_station *sta) diff --git a/patches/0048-Fix-ssid-ratelimiting-in-wifi6-AP.patch b/patches/0048-Fix-ssid-ratelimiting-in-wifi6-AP.patch new file mode 100644 index 000000000..ae222c5fb --- /dev/null +++ b/patches/0048-Fix-ssid-ratelimiting-in-wifi6-AP.patch @@ -0,0 +1,258 @@ +From 22c8d560c380cb3b188d2177c96121b9cd1835bd Mon Sep 17 00:00:00 2001 +From: Chaitanya Godavarthi +Date: Sun, 4 Apr 2021 15:11:22 -0400 +Subject: [PATCH] Fix ssid ratelimiting in wifi6 AP + +This patch backports some fixes in +netfilter ratelimiting module for linux v4.4.60. +These fixes are ported from until following commit id +6e323887565fe8a23c6c85faf9e395a24affd05c in +the mainline kernel. + +Signed-off-by: Chaitanya Godavarthi +--- + .../patches/110-nf-ratelimit-fix.patch | 232 ++++++++++++++++++ + 1 file changed, 232 insertions(+) + create mode 100644 target/linux/ipq807x/patches/110-nf-ratelimit-fix.patch + +diff --git a/target/linux/ipq807x/patches/110-nf-ratelimit-fix.patch b/target/linux/ipq807x/patches/110-nf-ratelimit-fix.patch +new file mode 100644 +index 0000000000..d4506944b8 +--- /dev/null ++++ b/target/linux/ipq807x/patches/110-nf-ratelimit-fix.patch +@@ -0,0 +1,232 @@ ++Index: linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/include/uapi/linux/netfilter/nf_tables.h ++=================================================================== ++--- linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce.orig/include/uapi/linux/netfilter/nf_tables.h +++++ linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/include/uapi/linux/netfilter/nf_tables.h ++@@ -761,6 +761,10 @@ enum nft_limit_type { ++ NFT_LIMIT_PKT_BYTES ++ }; ++ +++enum nft_limit_flags { +++ NFT_LIMIT_F_INV = (1 << 0), +++}; +++ ++ /** ++ * enum nft_limit_attributes - nf_tables limit expression netlink attributes ++ * ++@@ -768,6 +772,7 @@ enum nft_limit_type { ++ * @NFTA_LIMIT_UNIT: refill unit (NLA_U64) ++ * @NFTA_LIMIT_BURST: burst (NLA_U32) ++ * @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type) +++ * @NFTA_LIMIT_FLAGS: flags (NLA_U32: enum nft_limit_flags) ++ */ ++ enum nft_limit_attributes { ++ NFTA_LIMIT_UNSPEC, ++@@ -775,6 +780,8 @@ enum nft_limit_attributes { ++ NFTA_LIMIT_UNIT, ++ NFTA_LIMIT_BURST, ++ NFTA_LIMIT_TYPE, +++ NFTA_LIMIT_FLAGS, +++ NFTA_LIMIT_PAD, ++ __NFTA_LIMIT_MAX ++ }; ++ #define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1) ++Index: linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/net/netfilter/nft_limit.c ++=================================================================== ++--- linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce.orig/net/netfilter/nft_limit.c +++++ linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/net/netfilter/nft_limit.c ++@@ -17,15 +17,15 @@ ++ #include ++ #include ++ ++-static DEFINE_SPINLOCK(limit_lock); ++- ++ struct nft_limit { +++ spinlock_t lock; ++ u64 last; ++ u64 tokens; ++ u64 tokens_max; ++ u64 rate; ++ u64 nsecs; ++ u32 burst; +++ bool invert; ++ }; ++ ++ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) ++@@ -33,7 +33,7 @@ static inline bool nft_limit_eval(struct ++ u64 now, tokens; ++ s64 delta; ++ ++- spin_lock_bh(&limit_lock); +++ spin_lock_bh(&limit->lock); ++ now = ktime_get_ns(); ++ tokens = limit->tokens + now - limit->last; ++ if (tokens > limit->tokens_max) ++@@ -43,12 +43,12 @@ static inline bool nft_limit_eval(struct ++ delta = tokens - cost; ++ if (delta >= 0) { ++ limit->tokens = delta; ++- spin_unlock_bh(&limit_lock); ++- return false; +++ spin_unlock_bh(&limit->lock); +++ return limit->invert; ++ } ++ limit->tokens = tokens; ++- spin_unlock_bh(&limit_lock); ++- return true; +++ spin_unlock_bh(&limit->lock); +++ return !limit->invert; ++ } ++ ++ static int nft_limit_init(struct nft_limit *limit, ++@@ -65,20 +65,31 @@ static int nft_limit_init(struct nft_lim ++ limit->nsecs = unit * NSEC_PER_SEC; ++ if (limit->rate == 0 || limit->nsecs < unit) ++ return -EOVERFLOW; ++- limit->tokens = limit->tokens_max = limit->nsecs; ++- ++- if (tb[NFTA_LIMIT_BURST]) { ++- u64 rate; ++ +++ if (tb[NFTA_LIMIT_BURST]) ++ limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); +++ else +++ limit->burst = 0; +++ +++ if (limit->rate + limit->burst < limit->rate) +++ return -EOVERFLOW; +++ +++ /* The token bucket size limits the number of tokens can be +++ * accumulated. tokens_max specifies the bucket size. +++ * tokens_max = unit * (rate + burst) / rate. +++ */ +++ limit->tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), +++ limit->rate); +++ limit->tokens_max = limit->tokens; ++ ++- rate = limit->rate + limit->burst; ++- if (rate < limit->rate) ++- return -EOVERFLOW; +++ if (tb[NFTA_LIMIT_FLAGS]) { +++ u32 flags = ntohl(nla_get_be32(tb[NFTA_LIMIT_FLAGS])); ++ ++- limit->rate = rate; +++ if (flags & NFT_LIMIT_F_INV) +++ limit->invert = true; ++ } ++ limit->last = ktime_get_ns(); +++ spin_lock_init(&limit->lock); ++ ++ return 0; ++ } ++@@ -86,13 +97,14 @@ static int nft_limit_init(struct nft_lim ++ static int nft_limit_dump(struct sk_buff *skb, const struct nft_limit *limit, ++ enum nft_limit_type type) ++ { +++ u32 flags = limit->invert ? NFT_LIMIT_F_INV : 0; ++ u64 secs = div_u64(limit->nsecs, NSEC_PER_SEC); ++- u64 rate = limit->rate - limit->burst; ++ ++- if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(rate)) || +++ if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(limit->rate)) || ++ nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(secs)) || ++ nla_put_be32(skb, NFTA_LIMIT_BURST, htonl(limit->burst)) || ++- nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type))) +++ nla_put_be32(skb, NFTA_LIMIT_TYPE, htonl(type)) || +++ nla_put_be32(skb, NFTA_LIMIT_FLAGS, htonl(flags))) ++ goto nla_put_failure; ++ return 0; ++ ++@@ -120,6 +132,7 @@ static const struct nla_policy nft_limit ++ [NFTA_LIMIT_UNIT] = { .type = NLA_U64 }, ++ [NFTA_LIMIT_BURST] = { .type = NLA_U32 }, ++ [NFTA_LIMIT_TYPE] = { .type = NLA_U32 }, +++ [NFTA_LIMIT_FLAGS] = { .type = NLA_U32 }, ++ }; ++ ++ static int nft_limit_pkts_init(const struct nft_ctx *ctx, ++@@ -133,7 +146,7 @@ static int nft_limit_pkts_init(const str ++ if (err < 0) ++ return err; ++ ++- priv->cost = div_u64(priv->limit.nsecs, priv->limit.rate); +++ priv->cost = div64_u64(priv->limit.nsecs, priv->limit.rate); ++ return 0; ++ } ++ ++@@ -153,40 +166,40 @@ static const struct nft_expr_ops nft_lim ++ .dump = nft_limit_pkts_dump, ++ }; ++ ++-static void nft_limit_pkt_bytes_eval(const struct nft_expr *expr, ++- struct nft_regs *regs, ++- const struct nft_pktinfo *pkt) +++static void nft_limit_bytes_eval(const struct nft_expr *expr, +++ struct nft_regs *regs, +++ const struct nft_pktinfo *pkt) ++ { ++ struct nft_limit *priv = nft_expr_priv(expr); ++- u64 cost = div_u64(priv->nsecs * pkt->skb->len, priv->rate); +++ u64 cost = div64_u64(priv->nsecs * pkt->skb->len, priv->rate); ++ ++ if (nft_limit_eval(priv, cost)) ++ regs->verdict.code = NFT_BREAK; ++ } ++ ++-static int nft_limit_pkt_bytes_init(const struct nft_ctx *ctx, ++- const struct nft_expr *expr, ++- const struct nlattr * const tb[]) +++static int nft_limit_bytes_init(const struct nft_ctx *ctx, +++ const struct nft_expr *expr, +++ const struct nlattr * const tb[]) ++ { ++ struct nft_limit *priv = nft_expr_priv(expr); ++ ++ return nft_limit_init(priv, tb); ++ } ++ ++-static int nft_limit_pkt_bytes_dump(struct sk_buff *skb, ++- const struct nft_expr *expr) +++static int nft_limit_bytes_dump(struct sk_buff *skb, +++ const struct nft_expr *expr) ++ { ++ const struct nft_limit *priv = nft_expr_priv(expr); ++ ++ return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES); ++ } ++ ++-static const struct nft_expr_ops nft_limit_pkt_bytes_ops = { +++static const struct nft_expr_ops nft_limit_bytes_ops = { ++ .type = &nft_limit_type, ++ .size = NFT_EXPR_SIZE(sizeof(struct nft_limit)), ++- .eval = nft_limit_pkt_bytes_eval, ++- .init = nft_limit_pkt_bytes_init, ++- .dump = nft_limit_pkt_bytes_dump, +++ .eval = nft_limit_bytes_eval, +++ .init = nft_limit_bytes_init, +++ .dump = nft_limit_bytes_dump, ++ }; ++ ++ static const struct nft_expr_ops * ++@@ -200,7 +213,7 @@ nft_limit_select_ops(const struct nft_ct ++ case NFT_LIMIT_PKTS: ++ return &nft_limit_pkts_ops; ++ case NFT_LIMIT_PKT_BYTES: ++- return &nft_limit_pkt_bytes_ops; +++ return &nft_limit_bytes_ops; ++ } ++ return ERR_PTR(-EOPNOTSUPP); ++ } ++Index: linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/net/bridge/br_private.h ++=================================================================== ++--- linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce.orig/net/bridge/br_private.h +++++ linux-4.4.60-qsdk-10fd7d14853b7020b804acae690c8acec5d954ce/net/bridge/br_private.h ++@@ -926,9 +926,6 @@ BR_HOOK(uint8_t pf, unsigned int hook, s ++ struct sk_buff *skb, struct net_device *in, struct net_device *out, ++ int (*okfn)(struct net *, struct sock *, struct sk_buff *)) ++ { ++- if (!br_netfilter_run_hooks()) ++- return okfn(net, sk, skb); ++- ++ return NF_HOOK(pf, hook, net, sk, skb, in, out, okfn); ++ } ++ +-- +2.25.1 +