From ff8372a467fa28752610f57a6512c5365413faa2 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:34 +0800 Subject: net: skb: move enum skb_drop_reason to standalone header file As the skb drop reasons are getting more and more, move the enum 'skb_drop_reason' and related function to the standalone header 'dropreason.h', as Jakub Kicinski suggested. Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/net/dropreason.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 include/net/dropreason.h (limited to 'include/net') diff --git a/include/net/dropreason.h b/include/net/dropreason.h new file mode 100644 index 000000000000..ecd18b7b1364 --- /dev/null +++ b/include/net/dropreason.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _LINUX_DROPREASON_H +#define _LINUX_DROPREASON_H + +/* The reason of skb drop, which is used in kfree_skb_reason(). + * en...maybe they should be splited by group? + * + * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is + * used to translate the reason to string. + */ +enum skb_drop_reason { + SKB_NOT_DROPPED_YET = 0, + SKB_DROP_REASON_NOT_SPECIFIED, /* drop reason is not specified */ + SKB_DROP_REASON_NO_SOCKET, /* socket not found */ + SKB_DROP_REASON_PKT_TOO_SMALL, /* packet size is too small */ + SKB_DROP_REASON_TCP_CSUM, /* TCP checksum error */ + SKB_DROP_REASON_SOCKET_FILTER, /* dropped by socket filter */ + SKB_DROP_REASON_UDP_CSUM, /* UDP checksum error */ + SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */ + SKB_DROP_REASON_OTHERHOST, /* packet don't belong to current + * host (interface is in promisc + * mode) + */ + SKB_DROP_REASON_IP_CSUM, /* IP checksum error */ + SKB_DROP_REASON_IP_INHDR, /* there is something wrong with + * IP header (see + * IPSTATS_MIB_INHDRERRORS) + */ + SKB_DROP_REASON_IP_RPFILTER, /* IP rpfilter validate failed. + * see the document for rp_filter + * in ip-sysctl.rst for more + * information + */ + SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2 + * is multicast, but L3 is + * unicast. + */ + SKB_DROP_REASON_XFRM_POLICY, /* xfrm policy check failed */ + SKB_DROP_REASON_IP_NOPROTO, /* no support for IP protocol */ + SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */ + SKB_DROP_REASON_PROTO_MEM, /* proto memory limition, such as + * udp packet drop out of + * udp_memory_allocated. + */ + SKB_DROP_REASON_TCP_MD5NOTFOUND, /* no MD5 hash and one + * expected, corresponding + * to LINUX_MIB_TCPMD5NOTFOUND + */ + SKB_DROP_REASON_TCP_MD5UNEXPECTED, /* MD5 hash and we're not + * expecting one, corresponding + * to LINUX_MIB_TCPMD5UNEXPECTED + */ + SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong, + * corresponding to + * LINUX_MIB_TCPMD5FAILURE + */ + SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket + * backlog (see + * LINUX_MIB_TCPBACKLOGDROP) + */ + SKB_DROP_REASON_TCP_FLAGS, /* TCP flags invalid */ + SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero, + * see LINUX_MIB_TCPZEROWINDOWDROP + */ + SKB_DROP_REASON_TCP_OLD_DATA, /* the TCP data reveived is already + * received before (spurious retrans + * may happened), see + * LINUX_MIB_DELAYEDACKLOST + */ + SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window, + * the seq of the first byte exceed + * the right edges of receive + * window + */ + SKB_DROP_REASON_TCP_OFOMERGE, /* the data of skb is already in + * the ofo queue, corresponding to + * LINUX_MIB_TCPOFOMERGE + */ + SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to + * LINUX_MIB_PAWSESTABREJECTED + */ + SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */ + SKB_DROP_REASON_TCP_RESET, /* Invalid RST packet */ + SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */ + SKB_DROP_REASON_TCP_CLOSE, /* TCP socket in CLOSE state */ + SKB_DROP_REASON_TCP_FASTOPEN, /* dropped by FASTOPEN request socket */ + SKB_DROP_REASON_TCP_OLD_ACK, /* TCP ACK is old, but in window */ + SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */ + SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */ + SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */ + SKB_DROP_REASON_TCP_OFO_DROP, /* data already in receive queue */ + SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */ + SKB_DROP_REASON_BPF_CGROUP_EGRESS, /* dropped by + * BPF_PROG_TYPE_CGROUP_SKB + * eBPF program + */ + SKB_DROP_REASON_IPV6DISABLED, /* IPv6 is disabled on the device */ + SKB_DROP_REASON_NEIGH_CREATEFAIL, /* failed to create neigh + * entry + */ + SKB_DROP_REASON_NEIGH_FAILED, /* neigh entry in failed state */ + SKB_DROP_REASON_NEIGH_QUEUEFULL, /* arp_queue for neigh + * entry is full + */ + SKB_DROP_REASON_NEIGH_DEAD, /* neigh entry is dead */ + SKB_DROP_REASON_TC_EGRESS, /* dropped in TC egress HOOK */ + SKB_DROP_REASON_QDISC_DROP, /* dropped by qdisc when packet + * outputting (failed to enqueue to + * current qdisc) + */ + SKB_DROP_REASON_CPU_BACKLOG, /* failed to enqueue the skb to + * the per CPU backlog queue. This + * can be caused by backlog queue + * full (see netdev_max_backlog in + * net.rst) or RPS flow limit + */ + SKB_DROP_REASON_XDP, /* dropped by XDP in input path */ + SKB_DROP_REASON_TC_INGRESS, /* dropped in TC ingress HOOK */ + SKB_DROP_REASON_UNHANDLED_PROTO, /* protocol not implemented + * or not supported + */ + SKB_DROP_REASON_SKB_CSUM, /* sk_buff checksum computation + * error + */ + SKB_DROP_REASON_SKB_GSO_SEG, /* gso segmentation error */ + SKB_DROP_REASON_SKB_UCOPY_FAULT, /* failed to copy data from + * user space, e.g., via + * zerocopy_sg_from_iter() + * or skb_orphan_frags_rx() + */ + SKB_DROP_REASON_DEV_HDR, /* device driver specific + * header/metadata is invalid + */ + /* the device is not ready to xmit/recv due to any of its data + * structure that is not up/ready/initialized, e.g., the IFF_UP is + * not set, or driver specific tun->tfiles[txq] is not initialized + */ + SKB_DROP_REASON_DEV_READY, + SKB_DROP_REASON_FULL_RING, /* ring buffer is full */ + SKB_DROP_REASON_NOMEM, /* error due to OOM */ + SKB_DROP_REASON_HDR_TRUNC, /* failed to trunc/extract the header + * from networking data, e.g., failed + * to pull the protocol header from + * frags via pskb_may_pull() + */ + SKB_DROP_REASON_TAP_FILTER, /* dropped by (ebpf) filter directly + * attached to tun/tap, e.g., via + * TUNSETFILTEREBPF + */ + SKB_DROP_REASON_TAP_TXFILTER, /* dropped by tx filter implemented + * at tun/tap, e.g., check_filter() + */ + SKB_DROP_REASON_ICMP_CSUM, /* ICMP checksum error */ + SKB_DROP_REASON_INVALID_PROTO, /* the packet doesn't follow RFC + * 2211, such as a broadcasts + * ICMP_TIMESTAMP + */ + SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding + * to IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding + * to IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed + * the MTU) + */ + SKB_DROP_REASON_MAX, +}; + +#define SKB_DR_INIT(name, reason) \ + enum skb_drop_reason name = SKB_DROP_REASON_##reason +#define SKB_DR(name) \ + SKB_DR_INIT(name, NOT_SPECIFIED) +#define SKB_DR_SET(name, reason) \ + (name = SKB_DROP_REASON_##reason) +#define SKB_DR_OR(name, reason) \ + do { \ + if (name == SKB_DROP_REASON_NOT_SPECIFIED || \ + name == SKB_NOT_DROPPED_YET) \ + SKB_DR_SET(name, reason); \ + } while (0) + +#endif -- cgit v1.2.3 From ec43908dd556b2292f028c6e412261689405ba6e Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:35 +0800 Subject: net: skb: use auto-generation to convert skb drop reason to string It is annoying to add new skb drop reasons to 'enum skb_drop_reason' and TRACE_SKB_DROP_REASON in trace/event/skb.h, and it's easy to forget to add the new reasons we added to TRACE_SKB_DROP_REASON. TRACE_SKB_DROP_REASON is used to convert drop reason of type number to string. For now, the string we passed to user space is exactly the same as the name in 'enum skb_drop_reason' with a 'SKB_DROP_REASON_' prefix. Therefore, we can use 'auto-generation' to generate these drop reasons to string at build time. The new source 'dropreason_str.c' will be auto generated during build time, which contains the string array 'const char * const drop_reasons[]'. Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/net/dropreason.h | 2 ++ include/trace/events/skb.h | 89 +--------------------------------------------- net/core/.gitignore | 1 + net/core/Makefile | 23 +++++++++++- net/core/drop_monitor.c | 13 ------- net/core/skbuff.c | 3 ++ 6 files changed, 29 insertions(+), 102 deletions(-) create mode 100644 net/core/.gitignore (limited to 'include/net') diff --git a/include/net/dropreason.h b/include/net/dropreason.h index ecd18b7b1364..013ff0f2543e 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -181,4 +181,6 @@ enum skb_drop_reason { SKB_DR_SET(name, reason); \ } while (0) +extern const char * const drop_reasons[]; + #endif diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index a477bf907498..45264e4bb254 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -9,92 +9,6 @@ #include #include -#define TRACE_SKB_DROP_REASON \ - EM(SKB_DROP_REASON_NOT_SPECIFIED, NOT_SPECIFIED) \ - EM(SKB_DROP_REASON_NO_SOCKET, NO_SOCKET) \ - EM(SKB_DROP_REASON_PKT_TOO_SMALL, PKT_TOO_SMALL) \ - EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM) \ - EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER) \ - EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM) \ - EM(SKB_DROP_REASON_NETFILTER_DROP, NETFILTER_DROP) \ - EM(SKB_DROP_REASON_OTHERHOST, OTHERHOST) \ - EM(SKB_DROP_REASON_IP_CSUM, IP_CSUM) \ - EM(SKB_DROP_REASON_IP_INHDR, IP_INHDR) \ - EM(SKB_DROP_REASON_IP_RPFILTER, IP_RPFILTER) \ - EM(SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, \ - UNICAST_IN_L2_MULTICAST) \ - EM(SKB_DROP_REASON_XFRM_POLICY, XFRM_POLICY) \ - EM(SKB_DROP_REASON_IP_NOPROTO, IP_NOPROTO) \ - EM(SKB_DROP_REASON_SOCKET_RCVBUFF, SOCKET_RCVBUFF) \ - EM(SKB_DROP_REASON_PROTO_MEM, PROTO_MEM) \ - EM(SKB_DROP_REASON_TCP_MD5NOTFOUND, TCP_MD5NOTFOUND) \ - EM(SKB_DROP_REASON_TCP_MD5UNEXPECTED, \ - TCP_MD5UNEXPECTED) \ - EM(SKB_DROP_REASON_TCP_MD5FAILURE, TCP_MD5FAILURE) \ - EM(SKB_DROP_REASON_SOCKET_BACKLOG, SOCKET_BACKLOG) \ - EM(SKB_DROP_REASON_TCP_FLAGS, TCP_FLAGS) \ - EM(SKB_DROP_REASON_TCP_ZEROWINDOW, TCP_ZEROWINDOW) \ - EM(SKB_DROP_REASON_TCP_OLD_DATA, TCP_OLD_DATA) \ - EM(SKB_DROP_REASON_TCP_OVERWINDOW, TCP_OVERWINDOW) \ - EM(SKB_DROP_REASON_TCP_OFOMERGE, TCP_OFOMERGE) \ - EM(SKB_DROP_REASON_TCP_OFO_DROP, TCP_OFO_DROP) \ - EM(SKB_DROP_REASON_TCP_RFC7323_PAWS, TCP_RFC7323_PAWS) \ - EM(SKB_DROP_REASON_TCP_INVALID_SEQUENCE, \ - TCP_INVALID_SEQUENCE) \ - EM(SKB_DROP_REASON_TCP_RESET, TCP_RESET) \ - EM(SKB_DROP_REASON_TCP_INVALID_SYN, TCP_INVALID_SYN) \ - EM(SKB_DROP_REASON_TCP_CLOSE, TCP_CLOSE) \ - EM(SKB_DROP_REASON_TCP_FASTOPEN, TCP_FASTOPEN) \ - EM(SKB_DROP_REASON_TCP_OLD_ACK, TCP_OLD_ACK) \ - EM(SKB_DROP_REASON_TCP_TOO_OLD_ACK, TCP_TOO_OLD_ACK) \ - EM(SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, \ - TCP_ACK_UNSENT_DATA) \ - EM(SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, \ - TCP_OFO_QUEUE_PRUNE) \ - EM(SKB_DROP_REASON_IP_OUTNOROUTES, IP_OUTNOROUTES) \ - EM(SKB_DROP_REASON_BPF_CGROUP_EGRESS, \ - BPF_CGROUP_EGRESS) \ - EM(SKB_DROP_REASON_IPV6DISABLED, IPV6DISABLED) \ - EM(SKB_DROP_REASON_NEIGH_CREATEFAIL, NEIGH_CREATEFAIL) \ - EM(SKB_DROP_REASON_NEIGH_FAILED, NEIGH_FAILED) \ - EM(SKB_DROP_REASON_NEIGH_QUEUEFULL, NEIGH_QUEUEFULL) \ - EM(SKB_DROP_REASON_NEIGH_DEAD, NEIGH_DEAD) \ - EM(SKB_DROP_REASON_TC_EGRESS, TC_EGRESS) \ - EM(SKB_DROP_REASON_QDISC_DROP, QDISC_DROP) \ - EM(SKB_DROP_REASON_CPU_BACKLOG, CPU_BACKLOG) \ - EM(SKB_DROP_REASON_XDP, XDP) \ - EM(SKB_DROP_REASON_TC_INGRESS, TC_INGRESS) \ - EM(SKB_DROP_REASON_UNHANDLED_PROTO, UNHANDLED_PROTO) \ - EM(SKB_DROP_REASON_SKB_CSUM, SKB_CSUM) \ - EM(SKB_DROP_REASON_SKB_GSO_SEG, SKB_GSO_SEG) \ - EM(SKB_DROP_REASON_SKB_UCOPY_FAULT, SKB_UCOPY_FAULT) \ - EM(SKB_DROP_REASON_DEV_HDR, DEV_HDR) \ - EM(SKB_DROP_REASON_DEV_READY, DEV_READY) \ - EM(SKB_DROP_REASON_FULL_RING, FULL_RING) \ - EM(SKB_DROP_REASON_NOMEM, NOMEM) \ - EM(SKB_DROP_REASON_HDR_TRUNC, HDR_TRUNC) \ - EM(SKB_DROP_REASON_TAP_FILTER, TAP_FILTER) \ - EM(SKB_DROP_REASON_TAP_TXFILTER, TAP_TXFILTER) \ - EM(SKB_DROP_REASON_ICMP_CSUM, ICMP_CSUM) \ - EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO) \ - EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS) \ - EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES) \ - EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG) \ - EMe(SKB_DROP_REASON_MAX, MAX) - -#undef EM -#undef EMe - -#define EM(a, b) TRACE_DEFINE_ENUM(a); -#define EMe(a, b) TRACE_DEFINE_ENUM(a); - -TRACE_SKB_DROP_REASON - -#undef EM -#undef EMe -#define EM(a, b) { a, #b }, -#define EMe(a, b) { a, #b } - /* * Tracepoint for free an sk_buff: */ @@ -121,8 +35,7 @@ TRACE_EVENT(kfree_skb, TP_printk("skbaddr=%p protocol=%u location=%p reason: %s", __entry->skbaddr, __entry->protocol, __entry->location, - __print_symbolic(__entry->reason, - TRACE_SKB_DROP_REASON)) + drop_reasons[__entry->reason]) ); TRACE_EVENT(consume_skb, diff --git a/net/core/.gitignore b/net/core/.gitignore new file mode 100644 index 000000000000..df1e74372cce --- /dev/null +++ b/net/core/.gitignore @@ -0,0 +1 @@ +dropreason_str.c diff --git a/net/core/Makefile b/net/core/Makefile index a8e4f737692b..e8ce3bd283a6 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -4,7 +4,8 @@ # obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ - gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o + gen_stats.o gen_estimator.o net_namespace.o secure_seq.o \ + flow_dissector.o dropreason_str.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o @@ -39,3 +40,23 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o obj-$(CONFIG_BPF_SYSCALL) += sock_map.o obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o obj-$(CONFIG_OF) += of_net.o + +clean-files := dropreason_str.c + +quiet_cmd_dropreason_str = GEN $@ +cmd_dropreason_str = awk -F ',' 'BEGIN{ print "\#include \n"; \ + print "const char * const drop_reasons[] = {" }\ + /^enum skb_drop/ { dr=1; }\ + /^\};/ { dr=0; }\ + /^\tSKB_DROP_REASON_/ {\ + if (dr) {\ + sub(/\tSKB_DROP_REASON_/, "", $$1);\ + printf "\t[SKB_DROP_REASON_%s] = \"%s\",\n", $$1, $$1;\ + }\ + }\ + END{ print "};" }' $< > $@ + +$(obj)/dropreason_str.c: $(srctree)/include/net/dropreason.h + $(call cmd,dropreason_str) + +$(obj)/dropreason_str.o: $(obj)/dropreason_str.c diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 41cac0e4834e..4ad1decce724 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -48,19 +48,6 @@ static int trace_state = TRACE_OFF; static bool monitor_hw; -#undef EM -#undef EMe - -#define EM(a, b) [a] = #b, -#define EMe(a, b) [a] = #b - -/* drop_reasons is used to translate 'enum skb_drop_reason' to string, - * which is reported to user space. - */ -static const char * const drop_reasons[] = { - TRACE_SKB_DROP_REASON -}; - /* net_dm_mutex * * An overall lock guarding every operation coming from userspace. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 5b3559cb1d82..b661040c100e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -91,6 +91,9 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); +/* The array 'drop_reasons' is auto-generated in dropreason_str.c */ +EXPORT_SYMBOL(drop_reasons); + /** * skb_panic - private function for out-of-line support * @skb: buffer -- cgit v1.2.3 From b160f7270e6df0f4ccadcf6750696b380eb3b811 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:36 +0800 Subject: net: dropreason: reformat the comment fo skb drop reasons To make the code clear, reformat the comment in dropreason.h to k-doc style. Now, the comment can pass the check of kernel-doc without warnning: $ ./scripts/kernel-doc -v -none include/linux/dropreason.h include/linux/dropreason.h:7: info: Scanning doc for enum skb_drop_reason Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/net/dropreason.h | 382 ++++++++++++++++++++++++++++------------------- 1 file changed, 226 insertions(+), 156 deletions(-) (limited to 'include/net') diff --git a/include/net/dropreason.h b/include/net/dropreason.h index 013ff0f2543e..fae9b40e54fa 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -3,168 +3,238 @@ #ifndef _LINUX_DROPREASON_H #define _LINUX_DROPREASON_H -/* The reason of skb drop, which is used in kfree_skb_reason(). - * en...maybe they should be splited by group? +/** + * enum skb_drop_reason - the reasons of skb drops * - * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is - * used to translate the reason to string. + * The reason of skb drop, which is used in kfree_skb_reason(). */ enum skb_drop_reason { + /** + * @SKB_NOT_DROPPED_YET: skb is not dropped yet (used for no-drop case) + */ SKB_NOT_DROPPED_YET = 0, - SKB_DROP_REASON_NOT_SPECIFIED, /* drop reason is not specified */ - SKB_DROP_REASON_NO_SOCKET, /* socket not found */ - SKB_DROP_REASON_PKT_TOO_SMALL, /* packet size is too small */ - SKB_DROP_REASON_TCP_CSUM, /* TCP checksum error */ - SKB_DROP_REASON_SOCKET_FILTER, /* dropped by socket filter */ - SKB_DROP_REASON_UDP_CSUM, /* UDP checksum error */ - SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */ - SKB_DROP_REASON_OTHERHOST, /* packet don't belong to current - * host (interface is in promisc - * mode) - */ - SKB_DROP_REASON_IP_CSUM, /* IP checksum error */ - SKB_DROP_REASON_IP_INHDR, /* there is something wrong with - * IP header (see - * IPSTATS_MIB_INHDRERRORS) - */ - SKB_DROP_REASON_IP_RPFILTER, /* IP rpfilter validate failed. - * see the document for rp_filter - * in ip-sysctl.rst for more - * information - */ - SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2 - * is multicast, but L3 is - * unicast. - */ - SKB_DROP_REASON_XFRM_POLICY, /* xfrm policy check failed */ - SKB_DROP_REASON_IP_NOPROTO, /* no support for IP protocol */ - SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */ - SKB_DROP_REASON_PROTO_MEM, /* proto memory limition, such as - * udp packet drop out of - * udp_memory_allocated. - */ - SKB_DROP_REASON_TCP_MD5NOTFOUND, /* no MD5 hash and one - * expected, corresponding - * to LINUX_MIB_TCPMD5NOTFOUND - */ - SKB_DROP_REASON_TCP_MD5UNEXPECTED, /* MD5 hash and we're not - * expecting one, corresponding - * to LINUX_MIB_TCPMD5UNEXPECTED - */ - SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong, - * corresponding to - * LINUX_MIB_TCPMD5FAILURE - */ - SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket - * backlog (see - * LINUX_MIB_TCPBACKLOGDROP) - */ - SKB_DROP_REASON_TCP_FLAGS, /* TCP flags invalid */ - SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero, - * see LINUX_MIB_TCPZEROWINDOWDROP - */ - SKB_DROP_REASON_TCP_OLD_DATA, /* the TCP data reveived is already - * received before (spurious retrans - * may happened), see - * LINUX_MIB_DELAYEDACKLOST - */ - SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window, - * the seq of the first byte exceed - * the right edges of receive - * window - */ - SKB_DROP_REASON_TCP_OFOMERGE, /* the data of skb is already in - * the ofo queue, corresponding to - * LINUX_MIB_TCPOFOMERGE - */ - SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to - * LINUX_MIB_PAWSESTABREJECTED - */ - SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */ - SKB_DROP_REASON_TCP_RESET, /* Invalid RST packet */ - SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */ - SKB_DROP_REASON_TCP_CLOSE, /* TCP socket in CLOSE state */ - SKB_DROP_REASON_TCP_FASTOPEN, /* dropped by FASTOPEN request socket */ - SKB_DROP_REASON_TCP_OLD_ACK, /* TCP ACK is old, but in window */ - SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */ - SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */ - SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */ - SKB_DROP_REASON_TCP_OFO_DROP, /* data already in receive queue */ - SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */ - SKB_DROP_REASON_BPF_CGROUP_EGRESS, /* dropped by - * BPF_PROG_TYPE_CGROUP_SKB - * eBPF program - */ - SKB_DROP_REASON_IPV6DISABLED, /* IPv6 is disabled on the device */ - SKB_DROP_REASON_NEIGH_CREATEFAIL, /* failed to create neigh - * entry - */ - SKB_DROP_REASON_NEIGH_FAILED, /* neigh entry in failed state */ - SKB_DROP_REASON_NEIGH_QUEUEFULL, /* arp_queue for neigh - * entry is full - */ - SKB_DROP_REASON_NEIGH_DEAD, /* neigh entry is dead */ - SKB_DROP_REASON_TC_EGRESS, /* dropped in TC egress HOOK */ - SKB_DROP_REASON_QDISC_DROP, /* dropped by qdisc when packet - * outputting (failed to enqueue to - * current qdisc) - */ - SKB_DROP_REASON_CPU_BACKLOG, /* failed to enqueue the skb to - * the per CPU backlog queue. This - * can be caused by backlog queue - * full (see netdev_max_backlog in - * net.rst) or RPS flow limit - */ - SKB_DROP_REASON_XDP, /* dropped by XDP in input path */ - SKB_DROP_REASON_TC_INGRESS, /* dropped in TC ingress HOOK */ - SKB_DROP_REASON_UNHANDLED_PROTO, /* protocol not implemented - * or not supported - */ - SKB_DROP_REASON_SKB_CSUM, /* sk_buff checksum computation - * error - */ - SKB_DROP_REASON_SKB_GSO_SEG, /* gso segmentation error */ - SKB_DROP_REASON_SKB_UCOPY_FAULT, /* failed to copy data from - * user space, e.g., via - * zerocopy_sg_from_iter() - * or skb_orphan_frags_rx() - */ - SKB_DROP_REASON_DEV_HDR, /* device driver specific - * header/metadata is invalid - */ - /* the device is not ready to xmit/recv due to any of its data - * structure that is not up/ready/initialized, e.g., the IFF_UP is - * not set, or driver specific tun->tfiles[txq] is not initialized + /** @SKB_DROP_REASON_NOT_SPECIFIED: drop reason is not specified */ + SKB_DROP_REASON_NOT_SPECIFIED, + /** @SKB_DROP_REASON_NO_SOCKET: socket not found */ + SKB_DROP_REASON_NO_SOCKET, + /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */ + SKB_DROP_REASON_PKT_TOO_SMALL, + /** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */ + SKB_DROP_REASON_TCP_CSUM, + /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */ + SKB_DROP_REASON_SOCKET_FILTER, + /** @SKB_DROP_REASON_UDP_CSUM: UDP checksum error */ + SKB_DROP_REASON_UDP_CSUM, + /** @SKB_DROP_REASON_NETFILTER_DROP: dropped by netfilter */ + SKB_DROP_REASON_NETFILTER_DROP, + /** + * @SKB_DROP_REASON_OTHERHOST: packet don't belong to current host + * (interface is in promisc mode) + */ + SKB_DROP_REASON_OTHERHOST, + /** @SKB_DROP_REASON_IP_CSUM: IP checksum error */ + SKB_DROP_REASON_IP_CSUM, + /** + * @SKB_DROP_REASON_IP_INHDR: there is something wrong with IP header (see + * IPSTATS_MIB_INHDRERRORS) + */ + SKB_DROP_REASON_IP_INHDR, + /** + * @SKB_DROP_REASON_IP_RPFILTER: IP rpfilter validate failed. see the + * document for rp_filter in ip-sysctl.rst for more information + */ + SKB_DROP_REASON_IP_RPFILTER, + /** + * @SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST: destination address of L2 is + * multicast, but L3 is unicast. + */ + SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, + /** @SKB_DROP_REASON_XFRM_POLICY: xfrm policy check failed */ + SKB_DROP_REASON_XFRM_POLICY, + /** @SKB_DROP_REASON_IP_NOPROTO: no support for IP protocol */ + SKB_DROP_REASON_IP_NOPROTO, + /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */ + SKB_DROP_REASON_SOCKET_RCVBUFF, + /** + * @SKB_DROP_REASON_PROTO_MEM: proto memory limition, such as udp packet + * drop out of udp_memory_allocated. + */ + SKB_DROP_REASON_PROTO_MEM, + /** + * @SKB_DROP_REASON_TCP_MD5NOTFOUND: no MD5 hash and one expected, + * corresponding to LINUX_MIB_TCPMD5NOTFOUND + */ + SKB_DROP_REASON_TCP_MD5NOTFOUND, + /** + * @SKB_DROP_REASON_TCP_MD5UNEXPECTED: MD5 hash and we're not expecting + * one, corresponding to LINUX_MIB_TCPMD5UNEXPECTED + */ + SKB_DROP_REASON_TCP_MD5UNEXPECTED, + /** + * @SKB_DROP_REASON_TCP_MD5FAILURE: MD5 hash and its wrong, corresponding + * to LINUX_MIB_TCPMD5FAILURE + */ + SKB_DROP_REASON_TCP_MD5FAILURE, + /** + * @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog ( + * see LINUX_MIB_TCPBACKLOGDROP) + */ + SKB_DROP_REASON_SOCKET_BACKLOG, + /** @SKB_DROP_REASON_TCP_FLAGS: TCP flags invalid */ + SKB_DROP_REASON_TCP_FLAGS, + /** + * @SKB_DROP_REASON_TCP_ZEROWINDOW: TCP receive window size is zero, + * see LINUX_MIB_TCPZEROWINDOWDROP + */ + SKB_DROP_REASON_TCP_ZEROWINDOW, + /** + * @SKB_DROP_REASON_TCP_OLD_DATA: the TCP data reveived is already + * received before (spurious retrans may happened), see + * LINUX_MIB_DELAYEDACKLOST + */ + SKB_DROP_REASON_TCP_OLD_DATA, + /** + * @SKB_DROP_REASON_TCP_OVERWINDOW: the TCP data is out of window, + * the seq of the first byte exceed the right edges of receive + * window + */ + SKB_DROP_REASON_TCP_OVERWINDOW, + /** + * @SKB_DROP_REASON_TCP_OFOMERGE: the data of skb is already in the ofo + * queue, corresponding to LINUX_MIB_TCPOFOMERGE + */ + SKB_DROP_REASON_TCP_OFOMERGE, + /** + * @SKB_DROP_REASON_TCP_RFC7323_PAWS: PAWS check, corresponding to + * LINUX_MIB_PAWSESTABREJECTED + */ + SKB_DROP_REASON_TCP_RFC7323_PAWS, + /** @SKB_DROP_REASON_TCP_INVALID_SEQUENCE: Not acceptable SEQ field */ + SKB_DROP_REASON_TCP_INVALID_SEQUENCE, + /** @SKB_DROP_REASON_TCP_RESET: Invalid RST packet */ + SKB_DROP_REASON_TCP_RESET, + /** + * @SKB_DROP_REASON_TCP_INVALID_SYN: Incoming packet has unexpected + * SYN flag + */ + SKB_DROP_REASON_TCP_INVALID_SYN, + /** @SKB_DROP_REASON_TCP_CLOSE: TCP socket in CLOSE state */ + SKB_DROP_REASON_TCP_CLOSE, + /** @SKB_DROP_REASON_TCP_FASTOPEN: dropped by FASTOPEN request socket */ + SKB_DROP_REASON_TCP_FASTOPEN, + /** @SKB_DROP_REASON_TCP_OLD_ACK: TCP ACK is old, but in window */ + SKB_DROP_REASON_TCP_OLD_ACK, + /** @SKB_DROP_REASON_TCP_TOO_OLD_ACK: TCP ACK is too old */ + SKB_DROP_REASON_TCP_TOO_OLD_ACK, + /** + * @SKB_DROP_REASON_TCP_ACK_UNSENT_DATA: TCP ACK for data we haven't + * sent yet + */ + SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, + /** @SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE: pruned from TCP OFO queue */ + SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, + /** @SKB_DROP_REASON_TCP_OFO_DROP: data already in receive queue */ + SKB_DROP_REASON_TCP_OFO_DROP, + /** @SKB_DROP_REASON_IP_OUTNOROUTES: route lookup failed */ + SKB_DROP_REASON_IP_OUTNOROUTES, + /** + * @SKB_DROP_REASON_BPF_CGROUP_EGRESS: dropped by BPF_PROG_TYPE_CGROUP_SKB + * eBPF program + */ + SKB_DROP_REASON_BPF_CGROUP_EGRESS, + /** @SKB_DROP_REASON_IPV6DISABLED: IPv6 is disabled on the device */ + SKB_DROP_REASON_IPV6DISABLED, + /** @SKB_DROP_REASON_NEIGH_CREATEFAIL: failed to create neigh entry */ + SKB_DROP_REASON_NEIGH_CREATEFAIL, + /** @SKB_DROP_REASON_NEIGH_FAILED: neigh entry in failed state */ + SKB_DROP_REASON_NEIGH_FAILED, + /** @SKB_DROP_REASON_NEIGH_QUEUEFULL: arp_queue for neigh entry is full */ + SKB_DROP_REASON_NEIGH_QUEUEFULL, + /** @SKB_DROP_REASON_NEIGH_DEAD: neigh entry is dead */ + SKB_DROP_REASON_NEIGH_DEAD, + /** @SKB_DROP_REASON_TC_EGRESS: dropped in TC egress HOOK */ + SKB_DROP_REASON_TC_EGRESS, + /** + * @SKB_DROP_REASON_QDISC_DROP: dropped by qdisc when packet outputting ( + * failed to enqueue to current qdisc) + */ + SKB_DROP_REASON_QDISC_DROP, + /** + * @SKB_DROP_REASON_CPU_BACKLOG: failed to enqueue the skb to the per CPU + * backlog queue. This can be caused by backlog queue full (see + * netdev_max_backlog in net.rst) or RPS flow limit + */ + SKB_DROP_REASON_CPU_BACKLOG, + /** @SKB_DROP_REASON_XDP: dropped by XDP in input path */ + SKB_DROP_REASON_XDP, + /** @SKB_DROP_REASON_TC_INGRESS: dropped in TC ingress HOOK */ + SKB_DROP_REASON_TC_INGRESS, + /** @SKB_DROP_REASON_UNHANDLED_PROTO: protocol not implemented or not supported */ + SKB_DROP_REASON_UNHANDLED_PROTO, + /** @SKB_DROP_REASON_SKB_CSUM: sk_buff checksum computation error */ + SKB_DROP_REASON_SKB_CSUM, + /** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */ + SKB_DROP_REASON_SKB_GSO_SEG, + /** + * @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space, + * e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx() + */ + SKB_DROP_REASON_SKB_UCOPY_FAULT, + /** @SKB_DROP_REASON_DEV_HDR: device driver specific header/metadata is invalid */ + SKB_DROP_REASON_DEV_HDR, + /** + * @SKB_DROP_REASON_DEV_READY: the device is not ready to xmit/recv due to + * any of its data structure that is not up/ready/initialized, + * e.g., the IFF_UP is not set, or driver specific tun->tfiles[txq] + * is not initialized */ SKB_DROP_REASON_DEV_READY, - SKB_DROP_REASON_FULL_RING, /* ring buffer is full */ - SKB_DROP_REASON_NOMEM, /* error due to OOM */ - SKB_DROP_REASON_HDR_TRUNC, /* failed to trunc/extract the header - * from networking data, e.g., failed - * to pull the protocol header from - * frags via pskb_may_pull() - */ - SKB_DROP_REASON_TAP_FILTER, /* dropped by (ebpf) filter directly - * attached to tun/tap, e.g., via - * TUNSETFILTEREBPF - */ - SKB_DROP_REASON_TAP_TXFILTER, /* dropped by tx filter implemented - * at tun/tap, e.g., check_filter() - */ - SKB_DROP_REASON_ICMP_CSUM, /* ICMP checksum error */ - SKB_DROP_REASON_INVALID_PROTO, /* the packet doesn't follow RFC - * 2211, such as a broadcasts - * ICMP_TIMESTAMP - */ - SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed - * the MTU) - */ + /** @SKB_DROP_REASON_FULL_RING: ring buffer is full */ + SKB_DROP_REASON_FULL_RING, + /** @SKB_DROP_REASON_NOMEM: error due to OOM */ + SKB_DROP_REASON_NOMEM, + /** + * @SKB_DROP_REASON_HDR_TRUNC: failed to trunc/extract the header from + * networking data, e.g., failed to pull the protocol header from + * frags via pskb_may_pull() + */ + SKB_DROP_REASON_HDR_TRUNC, + /** + * @SKB_DROP_REASON_TAP_FILTER: dropped by (ebpf) filter directly attached + * to tun/tap, e.g., via TUNSETFILTEREBPF + */ + SKB_DROP_REASON_TAP_FILTER, + /** + * @SKB_DROP_REASON_TAP_TXFILTER: dropped by tx filter implemented at + * tun/tap, e.g., check_filter() + */ + SKB_DROP_REASON_TAP_TXFILTER, + /** @SKB_DROP_REASON_ICMP_CSUM: ICMP checksum error */ + SKB_DROP_REASON_ICMP_CSUM, + /** + * @SKB_DROP_REASON_INVALID_PROTO: the packet doesn't follow RFC 2211, + * such as a broadcasts ICMP_TIMESTAMP + */ + SKB_DROP_REASON_INVALID_PROTO, + /** + * @SKB_DROP_REASON_IP_INADDRERRORS: host unreachable, corresponding to + * IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INADDRERRORS, + /** + * @SKB_DROP_REASON_IP_INNOROUTES: network unreachable, corresponding to + * IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INNOROUTES, + /** + * @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the + * MTU) + */ + SKB_DROP_REASON_PKT_TOO_BIG, + /** + * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be + * used as a real 'reason' + */ SKB_DROP_REASON_MAX, }; -- cgit v1.2.3 From a84a434baf9427a1c49782fb1f0973d1308016df Mon Sep 17 00:00:00 2001 From: Peter Lafreniere Date: Mon, 6 Jun 2022 07:34:58 -0400 Subject: net: constify some inline functions in sock.h Despite these inline functions having full visibility to the compiler at compile time, they still strip const from passed pointers. This change allows for functions in various network drivers to be marked as const that could not be marked const before. Signed-off-by: Peter Lafreniere Link: https://lore.kernel.org/r/20220606113458.35953-1-pjlafren@mtu.edu Signed-off-by: Jakub Kicinski --- include/net/sock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index c585ef6565d9..657873e2d90f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -611,7 +611,7 @@ void sock_net_set(struct sock *sk, struct net *net) int sk_set_peek_off(struct sock *sk, int val); -static inline int sk_peek_offset(struct sock *sk, int flags) +static inline int sk_peek_offset(const struct sock *sk, int flags) { if (unlikely(flags & MSG_PEEK)) { return READ_ONCE(sk->sk_peek_off); @@ -863,7 +863,7 @@ static inline void sk_add_bind2_node(struct sock *sk, struct hlist_head *list) ({ tpos = (typeof(*tpos) *)((void *)pos - offset); 1;}); \ pos = rcu_dereference(hlist_next_rcu(pos))) -static inline struct user_namespace *sk_user_ns(struct sock *sk) +static inline struct user_namespace *sk_user_ns(const struct sock *sk) { /* Careful only use this in a context where these parameters * can not change and must all be valid, such as recvmsg from @@ -909,7 +909,7 @@ enum sock_flags { #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) -static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) +static inline void sock_copy_flags(struct sock *nsk, const struct sock *osk) { nsk->sk_flags = osk->sk_flags; } -- cgit v1.2.3 From d62607c3fe45911b2331fac073355a8c914bbde2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 7 Jun 2022 21:39:55 -0700 Subject: net: rename reference+tracking helpers Netdev reference helpers have a dev_ prefix for historic reasons. Renaming the old helpers would be too much churn but we can rename the tracking ones which are relatively recent and should be the default for new code. Rename: dev_hold_track() -> netdev_hold() dev_put_track() -> netdev_put() dev_replace_track() -> netdev_ref_replace() Link: https://lore.kernel.org/r/20220608043955.919359-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/eql.c | 4 ++-- drivers/net/macsec.c | 4 ++-- drivers/net/macvlan.c | 4 ++-- drivers/net/netconsole.c | 2 +- drivers/net/vrf.c | 8 ++++---- include/linux/netdevice.h | 24 ++++++++++++------------ include/net/xfrm.h | 2 +- net/8021q/vlan_dev.c | 4 ++-- net/ax25/af_ax25.c | 7 ++++--- net/ax25/ax25_dev.c | 6 +++--- net/bridge/br_if.c | 10 +++++----- net/core/dev.c | 10 +++++----- net/core/dev_ioctl.c | 4 ++-- net/core/drop_monitor.c | 5 +++-- net/core/dst.c | 8 ++++---- net/core/failover.c | 4 ++-- net/core/link_watch.c | 2 +- net/core/neighbour.c | 18 +++++++++--------- net/core/net-sysfs.c | 8 ++++---- net/core/netpoll.c | 2 +- net/core/pktgen.c | 6 +++--- net/ethtool/ioctl.c | 4 ++-- net/ethtool/netlink.c | 6 +++--- net/ethtool/netlink.h | 2 +- net/ipv4/devinet.c | 4 ++-- net/ipv4/fib_semantics.c | 11 ++++++----- net/ipv4/ipmr.c | 2 +- net/ipv4/route.c | 7 +++---- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 4 ++-- net/ipv6/addrconf_core.c | 2 +- net/ipv6/ip6_gre.c | 8 ++++---- net/ipv6/ip6_tunnel.c | 4 ++-- net/ipv6/ip6_vti.c | 4 ++-- net/ipv6/ip6mr.c | 2 +- net/ipv6/route.c | 10 +++++----- net/ipv6/sit.c | 4 ++-- net/ipv6/xfrm6_policy.c | 4 ++-- net/llc/af_llc.c | 2 +- net/openvswitch/vport-netdev.c | 6 +++--- net/packet/af_packet.c | 12 ++++++------ net/sched/act_mirred.c | 6 +++--- net/sched/sch_api.c | 2 +- net/sched/sch_generic.c | 11 ++++++----- net/smc/smc_pnet.c | 7 ++++--- net/switchdev/switchdev.c | 4 ++-- net/tipc/bearer.c | 4 ++-- net/xfrm/xfrm_device.c | 2 +- 48 files changed, 141 insertions(+), 137 deletions(-) (limited to 'include/net') diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 557ca8ff9dec..ca3e4700a813 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave) list_del(&slave->list); queue->num_slaves--; slave->dev->flags &= ~IFF_SLAVE; - dev_put_track(slave->dev, &slave->dev_tracker); + netdev_put(slave->dev, &slave->dev_tracker); kfree(slave); } @@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) if (duplicate_slave) eql_kill_one_slave(queue, duplicate_slave); - dev_hold_track(slave->dev, &slave->dev_tracker, GFP_ATOMIC); + netdev_hold(slave->dev, &slave->dev_tracker, GFP_ATOMIC); list_add(&slave->list, &queue->all_slaves); queue->num_slaves++; slave->dev->flags |= IFF_SLAVE; diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 817577e713d7..815738c0e067 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3462,7 +3462,7 @@ static int macsec_dev_init(struct net_device *dev) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); /* Get macsec's reference to real_dev */ - dev_hold_track(real_dev, &macsec->dev_tracker, GFP_KERNEL); + netdev_hold(real_dev, &macsec->dev_tracker, GFP_KERNEL); return 0; } @@ -3710,7 +3710,7 @@ static void macsec_free_netdev(struct net_device *dev) free_percpu(macsec->secy.tx_sc.stats); /* Get rid of the macsec's reference to real_dev */ - dev_put_track(macsec->real_dev, &macsec->dev_tracker); + netdev_put(macsec->real_dev, &macsec->dev_tracker); } static void macsec_setup(struct net_device *dev) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index eff75beb1395..5b46a6526fc6 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -915,7 +915,7 @@ static int macvlan_init(struct net_device *dev) port->count += 1; /* Get macvlan's reference to lowerdev */ - dev_hold_track(lowerdev, &vlan->dev_tracker, GFP_KERNEL); + netdev_hold(lowerdev, &vlan->dev_tracker, GFP_KERNEL); return 0; } @@ -1185,7 +1185,7 @@ static void macvlan_dev_free(struct net_device *dev) struct macvlan_dev *vlan = netdev_priv(dev); /* Get rid of the macvlan's reference to lowerdev */ - dev_put_track(vlan->lowerdev, &vlan->dev_tracker); + netdev_put(vlan->lowerdev, &vlan->dev_tracker); } void macvlan_common_setup(struct net_device *dev) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index ab8cd5551020..ddac61d79145 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -721,7 +721,7 @@ restart: __netpoll_cleanup(&nt->np); spin_lock_irqsave(&target_list_lock, flags); - dev_put_track(nt->np.dev, &nt->np.dev_tracker); + netdev_put(nt->np.dev, &nt->np.dev_tracker); nt->np.dev = NULL; nt->enabled = false; stopped = true; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index cfc30ce4c6e1..40445a12c682 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -814,8 +814,8 @@ static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf) */ if (rt6) { dst = &rt6->dst; - dev_replace_track(dst->dev, net->loopback_dev, - &dst->dev_tracker, GFP_KERNEL); + netdev_ref_replace(dst->dev, net->loopback_dev, + &dst->dev_tracker, GFP_KERNEL); dst->dev = net->loopback_dev; dst_release(dst); } @@ -1061,8 +1061,8 @@ static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf) */ if (rth) { dst = &rth->dst; - dev_replace_track(dst->dev, net->loopback_dev, - &dst->dev_tracker, GFP_KERNEL); + netdev_ref_replace(dst->dev, net->loopback_dev, + &dst->dev_tracker, GFP_KERNEL); dst->dev = net->loopback_dev; dst_release(dst); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f615a66c89e9..e2e5088888b1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3981,8 +3981,8 @@ static inline void netdev_tracker_free(struct net_device *dev, #endif } -static inline void dev_hold_track(struct net_device *dev, - netdevice_tracker *tracker, gfp_t gfp) +static inline void netdev_hold(struct net_device *dev, + netdevice_tracker *tracker, gfp_t gfp) { if (dev) { __dev_hold(dev); @@ -3990,8 +3990,8 @@ static inline void dev_hold_track(struct net_device *dev, } } -static inline void dev_put_track(struct net_device *dev, - netdevice_tracker *tracker) +static inline void netdev_put(struct net_device *dev, + netdevice_tracker *tracker) { if (dev) { netdev_tracker_free(dev, tracker); @@ -4004,11 +4004,11 @@ static inline void dev_put_track(struct net_device *dev, * @dev: network device * * Hold reference to device to keep it from being freed. - * Try using dev_hold_track() instead. + * Try using netdev_hold() instead. */ static inline void dev_hold(struct net_device *dev) { - dev_hold_track(dev, NULL, GFP_ATOMIC); + netdev_hold(dev, NULL, GFP_ATOMIC); } /** @@ -4016,17 +4016,17 @@ static inline void dev_hold(struct net_device *dev) * @dev: network device * * Release reference to device to allow it to be freed. - * Try using dev_put_track() instead. + * Try using netdev_put() instead. */ static inline void dev_put(struct net_device *dev) { - dev_put_track(dev, NULL); + netdev_put(dev, NULL); } -static inline void dev_replace_track(struct net_device *odev, - struct net_device *ndev, - netdevice_tracker *tracker, - gfp_t gfp) +static inline void netdev_ref_replace(struct net_device *odev, + struct net_device *ndev, + netdevice_tracker *tracker, + gfp_t gfp) { if (odev) netdev_tracker_free(odev, tracker); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c39d910d4b45..9287712ad977 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1923,7 +1923,7 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x) if (dev->xfrmdev_ops->xdo_dev_state_free) dev->xfrmdev_ops->xdo_dev_state_free(x); xso->dev = NULL; - dev_put_track(dev, &xso->dev_tracker); + netdev_put(dev, &xso->dev_tracker); } } #else diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 839f2020b015..e3dff2df6f54 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -615,7 +615,7 @@ static int vlan_dev_init(struct net_device *dev) return -ENOMEM; /* Get vlan's reference to real_dev */ - dev_hold_track(real_dev, &vlan->dev_tracker, GFP_KERNEL); + netdev_hold(real_dev, &vlan->dev_tracker, GFP_KERNEL); return 0; } @@ -852,7 +852,7 @@ static void vlan_dev_free(struct net_device *dev) vlan->vlan_pcpu_stats = NULL; /* Get rid of the vlan's reference to real_dev */ - dev_put_track(vlan->real_dev, &vlan->dev_tracker); + netdev_put(vlan->real_dev, &vlan->dev_tracker); } void vlan_setup(struct net_device *dev) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 95393bb2760b..1a5c0b071aa3 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -102,7 +102,8 @@ again: ax25_disconnect(s, ENETUNREACH); s->ax25_dev = NULL; if (sk->sk_socket) { - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, + &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } ax25_cb_del(s); @@ -1065,7 +1066,7 @@ static int ax25_release(struct socket *sock) del_timer_sync(&ax25->t3timer); del_timer_sync(&ax25->idletimer); } - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } @@ -1146,7 +1147,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (ax25_dev) { ax25_fillin_cb(ax25, ax25_dev); - dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC); + netdev_hold(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC); } done: diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 95a76d571c44..ab88b6ac5401 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -60,7 +60,7 @@ void ax25_dev_device_up(struct net_device *dev) refcount_set(&ax25_dev->refcount, 1); dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; - dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &ax25_dev->dev_tracker, GFP_ATOMIC); ax25_dev->forward = NULL; ax25_dev->device_up = true; @@ -136,7 +136,7 @@ unlock_put: spin_unlock_bh(&ax25_dev_lock); ax25_dev_put(ax25_dev); dev->ax25_ptr = NULL; - dev_put_track(dev, &ax25_dev->dev_tracker); + netdev_put(dev, &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } @@ -205,7 +205,7 @@ void __exit ax25_dev_free(void) ax25_dev = ax25_dev_list; while (ax25_dev != NULL) { s = ax25_dev; - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); ax25_dev = ax25_dev->next; kfree(s); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 47fcbade7389..a84a7cfb9d6d 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p) p->br = NULL; p->dev = NULL; - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kobject_put(&p->kobj); } @@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, return ERR_PTR(-ENOMEM); p->br = br; - dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; p->path_cost = port_cost(dev); p->priority = 0x8000 >> BR_PORT_BITS; @@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, br_stp_port_timer_init(p); err = br_multicast_add_port(p); if (err) { - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); p = ERR_PTR(err); } @@ -615,7 +615,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, err = dev_set_allmulti(dev, 1); if (err) { br_multicast_del_port(p); - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); /* kobject not yet init'd, manually free */ goto err1; } @@ -725,7 +725,7 @@ err3: sysfs_remove_link(br->ifobj, p->dev->name); err2: br_multicast_del_port(p); - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kobject_put(&p->kobj); dev_set_allmulti(dev, -1); err1: diff --git a/net/core/dev.c b/net/core/dev.c index 08ce317fcec8..c9d96b85a825 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7463,7 +7463,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, adj->ref_nr = 1; adj->private = private; adj->ignore = false; - dev_hold_track(adj_dev, &adj->dev_tracker, GFP_KERNEL); + netdev_hold(adj_dev, &adj->dev_tracker, GFP_KERNEL); pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", dev->name, adj_dev->name, adj->ref_nr, adj_dev->name); @@ -7492,7 +7492,7 @@ remove_symlinks: if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); free_adj: - dev_put_track(adj_dev, &adj->dev_tracker); + netdev_put(adj_dev, &adj->dev_tracker); kfree(adj); return ret; @@ -7534,7 +7534,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, list_del_rcu(&adj->list); pr_debug("adjacency: dev_put for %s, because link removed from %s to %s\n", adj_dev->name, dev->name, adj_dev->name); - dev_put_track(adj_dev, &adj->dev_tracker); + netdev_put(adj_dev, &adj->dev_tracker); kfree_rcu(adj, rcu); } @@ -10062,7 +10062,7 @@ int register_netdevice(struct net_device *dev) dev_init_scheduler(dev); - dev_hold_track(dev, &dev->dev_registered_tracker, GFP_KERNEL); + netdev_hold(dev, &dev->dev_registered_tracker, GFP_KERNEL); list_netdevice(dev); add_device_randomness(dev->dev_addr, dev->addr_len); @@ -10868,7 +10868,7 @@ void unregister_netdevice_many(struct list_head *head) synchronize_net(); list_for_each_entry(dev, head, unreg_list) { - dev_put_track(dev, &dev->dev_registered_tracker); + netdev_put(dev, &dev->dev_registered_tracker); net_set_todo(dev); } diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 4f6be442ae7e..7674bb9f3076 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -384,10 +384,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, return -ENODEV; if (!netif_is_bridge_master(dev)) return -EOPNOTSUPP; - dev_hold_track(dev, &dev_tracker, GFP_KERNEL); + netdev_hold(dev, &dev_tracker, GFP_KERNEL); rtnl_unlock(); err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL); - dev_put_track(dev, &dev_tracker); + netdev_put(dev, &dev_tracker); rtnl_lock(); return err; diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 4ad1decce724..804d02fc245f 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -864,7 +864,8 @@ net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata) } hw_metadata->input_dev = metadata->input_dev; - dev_hold_track(hw_metadata->input_dev, &hw_metadata->dev_tracker, GFP_ATOMIC); + netdev_hold(hw_metadata->input_dev, &hw_metadata->dev_tracker, + GFP_ATOMIC); return hw_metadata; @@ -880,7 +881,7 @@ free_hw_metadata: static void net_dm_hw_metadata_free(struct devlink_trap_metadata *hw_metadata) { - dev_put_track(hw_metadata->input_dev, &hw_metadata->dev_tracker); + netdev_put(hw_metadata->input_dev, &hw_metadata->dev_tracker); kfree(hw_metadata->fa_cookie); kfree(hw_metadata->trap_name); kfree(hw_metadata->trap_group_name); diff --git a/net/core/dst.c b/net/core/dst.c index d16c2c9bfebd..bc9c9be4e080 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, unsigned short flags) { dst->dev = dev; - dev_hold_track(dev, &dst->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dst->dev_tracker, GFP_ATOMIC); dst->ops = ops; dst_init_metrics(dst, dst_default_metrics.metrics, true); dst->expires = 0UL; @@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) if (dst->ops->destroy) dst->ops->destroy(dst); - dev_put_track(dst->dev, &dst->dev_tracker); + netdev_put(dst->dev, &dst->dev_tracker); lwtstate_put(dst->lwtstate); @@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst) dst->input = dst_discard; dst->output = dst_discard_out; dst->dev = blackhole_netdev; - dev_replace_track(dev, blackhole_netdev, &dst->dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker, + GFP_ATOMIC); } EXPORT_SYMBOL(dst_dev_put); diff --git a/net/core/failover.c b/net/core/failover.c index dcaa92a85ea2..864d2d83eff4 100644 --- a/net/core/failover.c +++ b/net/core/failover.c @@ -252,7 +252,7 @@ struct failover *failover_register(struct net_device *dev, return ERR_PTR(-ENOMEM); rcu_assign_pointer(failover->ops, ops); - dev_hold_track(dev, &failover->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &failover->dev_tracker, GFP_KERNEL); dev->priv_flags |= IFF_FAILOVER; rcu_assign_pointer(failover->failover_dev, dev); @@ -285,7 +285,7 @@ void failover_unregister(struct failover *failover) failover_dev->name); failover_dev->priv_flags &= ~IFF_FAILOVER; - dev_put_track(failover_dev, &failover->dev_tracker); + netdev_put(failover_dev, &failover->dev_tracker); spin_lock(&failover_lock); list_del(&failover->list); diff --git a/net/core/link_watch.c b/net/core/link_watch.c index a244d3bade7d..aa6cb1f90966 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -110,7 +110,7 @@ static void linkwatch_add_event(struct net_device *dev) spin_lock_irqsave(&lweventlist_lock, flags); if (list_empty(&dev->link_watch_list)) { list_add_tail(&dev->link_watch_list, &lweventlist); - dev_hold_track(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC); } spin_unlock_irqrestore(&lweventlist_lock, flags); } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 54625287ee5b..d8ec70622ecb 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -624,7 +624,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey, memcpy(n->primary_key, pkey, key_len); n->dev = dev; - dev_hold_track(dev, &n->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC); /* Protocol specific setup. */ if (tbl->constructor && (error = tbl->constructor(n)) < 0) { @@ -770,10 +770,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, write_pnet(&n->net, net); memcpy(n->key, pkey, key_len); n->dev = dev; - dev_hold_track(dev, &n->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &n->dev_tracker, GFP_KERNEL); if (tbl->pconstructor && tbl->pconstructor(n)) { - dev_put_track(dev, &n->dev_tracker); + netdev_put(dev, &n->dev_tracker); kfree(n); n = NULL; goto out; @@ -805,7 +805,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, write_unlock_bh(&tbl->lock); if (tbl->pdestructor) tbl->pdestructor(n); - dev_put_track(n->dev, &n->dev_tracker); + netdev_put(n->dev, &n->dev_tracker); kfree(n); return 0; } @@ -838,7 +838,7 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, n->next = NULL; if (tbl->pdestructor) tbl->pdestructor(n); - dev_put_track(n->dev, &n->dev_tracker); + netdev_put(n->dev, &n->dev_tracker); kfree(n); } return -ENOENT; @@ -879,7 +879,7 @@ void neigh_destroy(struct neighbour *neigh) if (dev->netdev_ops->ndo_neigh_destroy) dev->netdev_ops->ndo_neigh_destroy(dev, neigh); - dev_put_track(dev, &neigh->dev_tracker); + netdev_put(dev, &neigh->dev_tracker); neigh_parms_put(neigh->parms); neigh_dbg(2, "neigh %p is destroyed\n", neigh); @@ -1671,13 +1671,13 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, refcount_set(&p->refcnt, 1); p->reachable_time = neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; write_pnet(&p->net, net); p->sysctl_table = NULL; if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); return NULL; } @@ -1708,7 +1708,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) list_del(&parms->list); parms->dead = 1; write_unlock_bh(&tbl->lock); - dev_put_track(parms->dev, &parms->dev_tracker); + netdev_put(parms->dev, &parms->dev_tracker); call_rcu(&parms->rcu_head, neigh_rcu_free_parms); } EXPORT_SYMBOL(neigh_parms_release); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index e319e242dddf..d49fc974e630 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1016,7 +1016,7 @@ static void rx_queue_release(struct kobject *kobj) #endif memset(kobj, 0, sizeof(*kobj)); - dev_put_track(queue->dev, &queue->dev_tracker); + netdev_put(queue->dev, &queue->dev_tracker); } static const void *rx_queue_namespace(struct kobject *kobj) @@ -1056,7 +1056,7 @@ static int rx_queue_add_kobject(struct net_device *dev, int index) /* Kobject_put later will trigger rx_queue_release call which * decreases dev refcount: Take that reference here */ - dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); + netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL); kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, @@ -1619,7 +1619,7 @@ static void netdev_queue_release(struct kobject *kobj) struct netdev_queue *queue = to_netdev_queue(kobj); memset(kobj, 0, sizeof(*kobj)); - dev_put_track(queue->dev, &queue->dev_tracker); + netdev_put(queue->dev, &queue->dev_tracker); } static const void *netdev_queue_namespace(struct kobject *kobj) @@ -1659,7 +1659,7 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) /* Kobject_put later will trigger netdev_queue_release call * which decreases dev refcount: Take that reference here */ - dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); + netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL); kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, diff --git a/net/core/netpoll.c b/net/core/netpoll.c index db724463e7cd..5d27067b72d5 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -853,7 +853,7 @@ void netpoll_cleanup(struct netpoll *np) if (!np->dev) goto out; __netpoll_cleanup(np); - dev_put_track(np->dev, &np->dev_tracker); + netdev_put(np->dev, &np->dev_tracker); np->dev = NULL; out: rtnl_unlock(); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 84b62cd7bc57..88906ba6d9a7 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2100,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn, /* Clean old setups */ if (pkt_dev->odev) { - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); pkt_dev->odev = NULL; } @@ -3807,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) return add_dev_to_thread(t, pkt_dev); out2: - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); out1: #ifdef CONFIG_XFRM free_SAs(pkt_dev); @@ -3901,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, /* Dis-associate from the interface */ if (pkt_dev->odev) { - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); pkt_dev->odev = NULL; } diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 326e14ee05db..d05ff6a17a1f 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -2010,7 +2010,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) * removal of the device. */ busy = true; - dev_hold_track(dev, &dev_tracker, GFP_KERNEL); + netdev_hold(dev, &dev_tracker, GFP_KERNEL); rtnl_unlock(); if (rc == 0) { @@ -2034,7 +2034,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) } rtnl_lock(); - dev_put_track(dev, &dev_tracker); + netdev_put(dev, &dev_tracker); busy = false; (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE); diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 5fe8f4ae2ceb..e26079e11835 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -402,7 +402,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) ops->cleanup_data(reply_data); genlmsg_end(rskb, reply_payload); - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); kfree(reply_data); kfree(req_info); return genlmsg_reply(rskb, info); @@ -414,7 +414,7 @@ err_cleanup: if (ops->cleanup_data) ops->cleanup_data(reply_data); err_dev: - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); kfree(reply_data); kfree(req_info); return ret; @@ -550,7 +550,7 @@ static int ethnl_default_start(struct netlink_callback *cb) * same parser as for non-dump (doit) requests is used, it * would take reference to the device if it finds one */ - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); req_info->dev = NULL; } if (ret < 0) diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 7919ddb2371c..c0d587611854 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -237,7 +237,7 @@ struct ethnl_req_info { static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info) { - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); } /** diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index b2366ad540e6..92b778e423df 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -244,7 +244,7 @@ void in_dev_finish_destroy(struct in_device *idev) #ifdef NET_REFCNT_DEBUG pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL"); #endif - dev_put_track(dev, &idev->dev_tracker); + netdev_put(dev, &idev->dev_tracker); if (!idev->dead) pr_err("Freeing alive in_device %p\n", idev); else @@ -272,7 +272,7 @@ static struct in_device *inetdev_init(struct net_device *dev) if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) dev_disable_lro(dev); /* Reference in_dev->dev */ - dev_hold_track(dev, &in_dev->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &in_dev->dev_tracker, GFP_KERNEL); /* Account for reference dev->ip_ptr (below) */ refcount_set(&in_dev->refcnt, 1); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index a57ba23571c9..a5439a8414d4 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -211,7 +211,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) void fib_nh_common_release(struct fib_nh_common *nhc) { - dev_put_track(nhc->nhc_dev, &nhc->nhc_dev_tracker); + netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker); lwtstate_put(nhc->nhc_lwtstate); rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); rt_fibinfo_free(&nhc->nhc_rth_input); @@ -1057,7 +1057,8 @@ static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh, err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); if (!err) { nh->fib_nh_dev = fib6_nh.fib_nh_dev; - dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_KERNEL); + netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, + GFP_KERNEL); nh->fib_nh_oif = nh->fib_nh_dev->ifindex; nh->fib_nh_scope = RT_SCOPE_LINK; @@ -1141,7 +1142,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, if (!netif_carrier_ok(dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_dev = dev; - dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); nh->fib_nh_scope = RT_SCOPE_LINK; return 0; } @@ -1195,7 +1196,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, "No egress device for nexthop gateway"); goto out; } - dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); if (!netif_carrier_ok(dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; @@ -1229,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh, } nh->fib_nh_dev = in_dev->dev; - dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); nh->fib_nh_scope = RT_SCOPE_HOST; if (!netif_carrier_ok(nh->fib_nh_dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 13e6329784fb..8324e541d193 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -691,7 +691,7 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify, if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); - dev_put_track(dev, &v->dev_tracker); + netdev_put(dev, &v->dev_tracker); return 0; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 356f535f3443..2d16bcc7d346 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1550,9 +1550,8 @@ void rt_flush_dev(struct net_device *dev) if (rt->dst.dev != dev) continue; rt->dst.dev = blackhole_netdev; - dev_replace_track(dev, blackhole_netdev, - &rt->dst.dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(dev, blackhole_netdev, + &rt->dst.dev_tracker, GFP_ATOMIC); list_move(&rt->rt_uncached, &ul->quarantine); } spin_unlock_bh(&ul->lock); @@ -2851,7 +2850,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or new->output = dst_discard_out; new->dev = net->loopback_dev; - dev_hold_track(new->dev, &new->dev_tracker, GFP_ATOMIC); + netdev_hold(new->dev, &new->dev_tracker, GFP_ATOMIC); rt->rt_is_input = ort->rt_is_input; rt->rt_iif = ort->rt_iif; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 6fde0b184791..3d0dfa6cf9f9 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -75,7 +75,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, xdst->u.rt.rt_iif = fl4->flowi4_iif; xdst->u.dst.dev = dev; - dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); /* Sheit... I remember I did this right. Apparently, * it was magically lost, so this code needs audit */ diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1b1932502e9e..3497ad1362c0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -398,13 +398,13 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) if (ndev->cnf.forwarding) dev_disable_lro(dev); /* We refer to the device */ - dev_hold_track(dev, &ndev->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &ndev->dev_tracker, GFP_KERNEL); if (snmp6_alloc_dev(ndev) < 0) { netdev_dbg(dev, "%s: cannot allocate memory for statistics\n", __func__); neigh_parms_release(&nd_tbl, ndev->nd_parms); - dev_put_track(dev, &ndev->dev_tracker); + netdev_put(dev, &ndev->dev_tracker); kfree(ndev); return ERR_PTR(err); } diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 881d1477d24a..507a8353a6bd 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -263,7 +263,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) #ifdef NET_REFCNT_DEBUG pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL"); #endif - dev_put_track(dev, &idev->dev_tracker); + netdev_put(dev, &idev->dev_tracker); if (!idev->dead) { pr_warn("Freeing alive inet6 device %p\n", idev); return; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4e37f7c29900..3e22cbe5966a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -398,7 +398,7 @@ static void ip6erspan_tunnel_uninit(struct net_device *dev) ip6erspan_tunnel_unlink_md(ign, t); ip6gre_tunnel_unlink(ign, t); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } static void ip6gre_tunnel_uninit(struct net_device *dev) @@ -411,7 +411,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) if (ign->fb_tunnel_dev == dev) WRITE_ONCE(ign->fb_tunnel_dev, NULL); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } @@ -1495,7 +1495,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev) } ip6gre_tnl_init_features(dev); - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; cleanup_dst_cache_init: @@ -1887,7 +1887,7 @@ static int ip6erspan_tap_init(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ip6erspan_tnl_link_config(tunnel, 1); - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; cleanup_dst_cache_init: diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 19325b7600bb..689de5eb604e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -381,7 +381,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) else ip6_tnl_unlink(ip6n, t); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } /** @@ -1889,7 +1889,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev) dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len; - dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); return 0; destroy_dst: diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 3a434d75925c..8fe59a79e800 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -293,7 +293,7 @@ static void vti6_dev_uninit(struct net_device *dev) RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); else vti6_tnl_unlink(ip6n, t); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi, @@ -936,7 +936,7 @@ static inline int vti6_dev_init_gen(struct net_device *dev) dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; - dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); return 0; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 4e74bc61a3db..d4aad41c9849 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -741,7 +741,7 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify, if ((v->flags & MIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); - dev_put_track(dev, &v->dev_tracker); + netdev_put(dev, &v->dev_tracker); return 0; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d25dc83bac62..0be01a4d48c1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -182,9 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net_device *dev) if (rt_dev == dev) { rt->dst.dev = blackhole_netdev; - dev_replace_track(rt_dev, blackhole_netdev, - &rt->dst.dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(rt_dev, blackhole_netdev, + &rt->dst.dev_tracker, + GFP_ATOMIC); handled = true; } if (handled) @@ -607,7 +607,7 @@ static void rt6_probe_deferred(struct work_struct *w) addrconf_addr_solict_mult(&work->target, &mcaddr); ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0); - dev_put_track(work->dev, &work->dev_tracker); + netdev_put(work->dev, &work->dev_tracker); kfree(work); } @@ -661,7 +661,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh) } else { INIT_WORK(&work->work, rt6_probe_deferred); work->target = *nh_gw; - dev_hold_track(dev, &work->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &work->dev_tracker, GFP_ATOMIC); work->dev = dev; schedule_work(&work->work); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c0b138c20992..4f1721865fda 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -521,7 +521,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) ipip6_tunnel_del_prl(tunnel, NULL); } dst_cache_reset(&tunnel->dst_cache); - dev_put_track(dev, &tunnel->dev_tracker); + netdev_put(dev, &tunnel->dev_tracker); } static int ipip6_err(struct sk_buff *skb, u32 info) @@ -1463,7 +1463,7 @@ static int ipip6_tunnel_init(struct net_device *dev) dev->tstats = NULL; return err; } - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index e64e427a51cf..4a4b0e49ec92 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -73,11 +73,11 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)xdst->route; xdst->u.dst.dev = dev; - dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); xdst->u.rt6.rt6i_idev = in6_dev_get(dev); if (!xdst->u.rt6.rt6i_idev) { - dev_put_track(dev, &xdst->u.dst.dev_tracker); + netdev_put(dev, &xdst->u.dst.dev_tracker); return -ENODEV; } diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 7f555d2e5357..da7fe94bea2e 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock) } else { release_sock(sk); } - dev_put_track(llc->dev, &llc->dev_tracker); + netdev_put(llc->dev, &llc->dev_tracker); sock_put(sk); llc_sk_free(sk); out: diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index b498dac4e1e0..2f61d5bdce1a 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -115,7 +115,7 @@ error_master_upper_dev_unlink: error_unlock: rtnl_unlock(); error_put: - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); error_free_vport: ovs_vport_free(vport); return ERR_PTR(err); @@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); ovs_vport_free(vport); } @@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport) */ if (vport->dev->reg_state == NETREG_REGISTERED) rtnl_delete_link(vport->dev); - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); vport->dev = NULL; rtnl_unlock(); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ca6e92a22923..d08c4728523b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3134,7 +3134,7 @@ static int packet_release(struct socket *sock) packet_cached_dev_reset(po); if (po->prot_hook.dev) { - dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker); po->prot_hook.dev = NULL; } spin_unlock(&po->bind_lock); @@ -3235,15 +3235,15 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, WRITE_ONCE(po->num, proto); po->prot_hook.type = proto; - dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker); if (unlikely(unlisted)) { po->prot_hook.dev = NULL; WRITE_ONCE(po->ifindex, -1); packet_cached_dev_reset(po); } else { - dev_hold_track(dev, &po->prot_hook.dev_tracker, - GFP_ATOMIC); + netdev_hold(dev, &po->prot_hook.dev_tracker, + GFP_ATOMIC); po->prot_hook.dev = dev; WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0); packet_cached_dev_assign(po, dev); @@ -4167,8 +4167,8 @@ static int packet_notifier(struct notifier_block *this, if (msg == NETDEV_UNREGISTER) { packet_cached_dev_reset(po); WRITE_ONCE(po->ifindex, -1); - dev_put_track(po->prot_hook.dev, - &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, + &po->prot_hook.dev_tracker); po->prot_hook.dev = NULL; } spin_unlock(&po->bind_lock); diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index ebb92fb072ab..a1d70cf86843 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a) /* last reference to action, no need to lock */ dev = rcu_dereference_protected(m->tcfm_dev, 1); - dev_put_track(dev, &m->tcfm_dev_tracker); + netdev_put(dev, &m->tcfm_dev_tracker); } static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { @@ -181,7 +181,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, mac_header_xmit = dev_is_mac_header_xmit(ndev); odev = rcu_replace_pointer(m->tcfm_dev, ndev, lockdep_is_held(&m->tcf_lock)); - dev_put_track(odev, &m->tcfm_dev_tracker); + netdev_put(odev, &m->tcfm_dev_tracker); netdev_tracker_alloc(ndev, &m->tcfm_dev_tracker, GFP_ATOMIC); m->tcfm_mac_header_xmit = mac_header_xmit; } @@ -402,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused, list_for_each_entry(m, &mirred_list, tcfm_list) { spin_lock_bh(&m->tcf_lock); if (tcf_mirred_dev_dereference(m) == dev) { - dev_put_track(dev, &m->tcfm_dev_tracker); + netdev_put(dev, &m->tcfm_dev_tracker); /* Note : no rcu grace period necessary, as * net_device are already rcu protected. */ diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index e3c0e8ea2dbb..bf87b50837a8 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1292,7 +1292,7 @@ err_out5: if (ops->destroy) ops->destroy(sch); err_out3: - dev_put_track(dev, &sch->dev_tracker); + netdev_put(dev, &sch->dev_tracker); qdisc_free(sch); err_out2: module_put(ops->owner); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index dba0b3e24af5..cc6eabee2830 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -541,7 +541,7 @@ static void dev_watchdog(struct timer_list *t) spin_unlock(&dev->tx_global_lock); if (release) - dev_put_track(dev, &dev->watchdog_dev_tracker); + netdev_put(dev, &dev->watchdog_dev_tracker); } void __netdev_watchdog_up(struct net_device *dev) @@ -551,7 +551,8 @@ void __netdev_watchdog_up(struct net_device *dev) dev->watchdog_timeo = 5*HZ; if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo))) - dev_hold_track(dev, &dev->watchdog_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dev->watchdog_dev_tracker, + GFP_ATOMIC); } } EXPORT_SYMBOL_GPL(__netdev_watchdog_up); @@ -565,7 +566,7 @@ static void dev_watchdog_down(struct net_device *dev) { netif_tx_lock_bh(dev); if (del_timer(&dev->watchdog_timer)) - dev_put_track(dev, &dev->watchdog_dev_tracker); + netdev_put(dev, &dev->watchdog_dev_tracker); netif_tx_unlock_bh(dev); } @@ -975,7 +976,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; sch->dev_queue = dev_queue; - dev_hold_track(dev, &sch->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &sch->dev_tracker, GFP_KERNEL); refcount_set(&sch->refcnt, 1); return sch; @@ -1067,7 +1068,7 @@ static void qdisc_destroy(struct Qdisc *qdisc) ops->destroy(qdisc); module_put(ops->owner); - dev_put_track(qdisc_dev(qdisc), &qdisc->dev_tracker); + netdev_put(qdisc_dev(qdisc), &qdisc->dev_tracker); trace_qdisc_destroy(qdisc); diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 7055ed10e316..4c3bf6db7038 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -120,7 +120,8 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name) smc_pnet_match(pnetelem->pnet_name, pnet_name)) { list_del(&pnetelem->list); if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) { - dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker); + netdev_put(pnetelem->ndev, + &pnetelem->dev_tracker); pr_warn_ratelimited("smc: net device %s " "erased user defined " "pnetid %.16s\n", @@ -196,7 +197,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev) list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev && !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) { - dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC); + netdev_hold(ndev, &pnetelem->dev_tracker, GFP_ATOMIC); pnetelem->ndev = ndev; rc = 0; pr_warn_ratelimited("smc: adding net device %s with " @@ -227,7 +228,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev) mutex_lock(&pnettable->lock); list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) { - dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker); + netdev_put(pnetelem->ndev, &pnetelem->dev_tracker); pnetelem->ndev = NULL; rc = 0; pr_warn_ratelimited("smc: removing net device %s with " diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 474f76383033..8cc42aea19c7 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -64,7 +64,7 @@ void switchdev_deferred_process(void) while ((dfitem = switchdev_deferred_dequeue())) { dfitem->func(dfitem->dev, dfitem->data); - dev_put_track(dfitem->dev, &dfitem->dev_tracker); + netdev_put(dfitem->dev, &dfitem->dev_tracker); kfree(dfitem); } } @@ -91,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev, dfitem->dev = dev; dfitem->func = func; memcpy(dfitem->data, data, data_len); - dev_hold_track(dev, &dfitem->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dfitem->dev_tracker, GFP_ATOMIC); spin_lock_bh(&deferred_lock); list_add_tail(&dfitem->list, &deferred); spin_unlock_bh(&deferred_lock); diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 932c87b98eca..35cac7733fd3 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -788,7 +788,7 @@ int tipc_attach_loopback(struct net *net) if (!dev) return -ENODEV; - dev_hold_track(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL); tn->loopback_pt.dev = dev; tn->loopback_pt.type = htons(ETH_P_TIPC); tn->loopback_pt.func = tipc_loopback_rcv_pkt; @@ -801,7 +801,7 @@ void tipc_detach_loopback(struct net *net) struct tipc_net *tn = tipc_net(net); dev_remove_pack(&tn->loopback_pt); - dev_put_track(net->loopback_dev, &tn->loopback_pt.dev_tracker); + netdev_put(net->loopback_dev, &tn->loopback_pt.dev_tracker); } /* Caller should hold rtnl_lock to protect the bearer */ diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 35c7e89b2e7d..637ca8838436 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -275,7 +275,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, xso->dev = NULL; xso->dir = 0; xso->real_dev = NULL; - dev_put_track(dev, &xso->dev_tracker); + netdev_put(dev, &xso->dev_tracker); if (err != -EOPNOTSUPP) return err; -- cgit v1.2.3 From 9962acefbcb92736c268aafe5f52200948f60f3e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 08:46:37 -0700 Subject: net: adopt u64_stats_t in struct pcpu_sw_netstats As explained in commit 316580b69d0a ("u64_stats: provide u64_stats_t type") we should use u64_stats_t and related accessors to avoid load/store tearing. Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/macsec.c | 8 ++++---- drivers/net/usb/usbnet.c | 8 ++++---- drivers/net/vxlan/vxlan_core.c | 8 ++++---- include/linux/netdevice.h | 16 ++++++++-------- include/net/ip_tunnels.h | 4 ++-- net/bridge/br_netlink.c | 8 ++++---- net/bridge/br_vlan.c | 36 ++++++++++++++++++++---------------- net/core/dev.c | 18 +++++++++--------- net/dsa/slave.c | 8 ++++---- 9 files changed, 59 insertions(+), 55 deletions(-) (limited to 'include/net') diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 815738c0e067..c881e1bf6f6e 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -523,8 +523,8 @@ static void count_tx(struct net_device *dev, int ret, int len) struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += len; + u64_stats_inc(&stats->tx_packets); + u64_stats_add(&stats->tx_bytes, len); u64_stats_update_end(&stats->syncp); } } @@ -825,8 +825,8 @@ static void count_rx(struct net_device *dev, int len) struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += len; + u64_stats_inc(&stats->rx_packets); + u64_stats_add(&stats->rx_bytes, len); u64_stats_update_end(&stats->syncp); } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1cb6dab3e2d0..dc79811535c2 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -337,8 +337,8 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) skb->protocol = eth_type_trans (skb, dev->net); flags = u64_stats_update_begin_irqsave(&stats64->syncp); - stats64->rx_packets++; - stats64->rx_bytes += skb->len; + u64_stats_inc(&stats64->rx_packets); + u64_stats_add(&stats64->rx_bytes, skb->len); u64_stats_update_end_irqrestore(&stats64->syncp, flags); netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", @@ -1258,8 +1258,8 @@ static void tx_complete (struct urb *urb) unsigned long flags; flags = u64_stats_update_begin_irqsave(&stats64->syncp); - stats64->tx_packets += entry->packets; - stats64->tx_bytes += entry->length; + u64_stats_add(&stats64->tx_packets, entry->packets); + u64_stats_add(&stats64->tx_bytes, entry->length); u64_stats_update_end_irqrestore(&stats64->syncp, flags); } else { dev->net->stats.tx_errors++; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 265d4a0245e7..8b0710b576c2 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2385,15 +2385,15 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni); u64_stats_update_begin(&tx_stats->syncp); - tx_stats->tx_packets++; - tx_stats->tx_bytes += len; + u64_stats_inc(&tx_stats->tx_packets); + u64_stats_add(&tx_stats->tx_bytes, len); u64_stats_update_end(&tx_stats->syncp); vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len); if (__netif_rx(skb) == NET_RX_SUCCESS) { u64_stats_update_begin(&rx_stats->syncp); - rx_stats->rx_packets++; - rx_stats->rx_bytes += len; + u64_stats_inc(&rx_stats->rx_packets); + u64_stats_add(&rx_stats->rx_bytes, len); u64_stats_update_end(&rx_stats->syncp); vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX, len); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e2e5088888b1..89afa4f7747d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2636,10 +2636,10 @@ struct packet_offload { /* often modified stats are per-CPU, other are shared (netdev->stats) */ struct pcpu_sw_netstats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; struct u64_stats_sync syncp; } __aligned(4 * sizeof(u64)); @@ -2656,8 +2656,8 @@ static inline void dev_sw_netstats_rx_add(struct net_device *dev, unsigned int l struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->rx_bytes += len; - tstats->rx_packets++; + u64_stats_add(&tstats->rx_bytes, len); + u64_stats_inc(&tstats->rx_packets); u64_stats_update_end(&tstats->syncp); } @@ -2668,8 +2668,8 @@ static inline void dev_sw_netstats_tx_add(struct net_device *dev, struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->tx_bytes += len; - tstats->tx_packets += packets; + u64_stats_add(&tstats->tx_bytes, len); + u64_stats_add(&tstats->tx_packets, packets); u64_stats_update_end(&tstats->syncp); } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index c24fa934221d..70cbc4a72669 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -456,8 +456,8 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len) struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->tx_bytes += pkt_len; - tstats->tx_packets++; + u64_stats_add(&tstats->tx_bytes, pkt_len); + u64_stats_inc(&tstats->tx_packets); u64_stats_update_end(&tstats->syncp); put_cpu_ptr(tstats); } else { diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index bb01776d2d88..1ef14a099c6b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1770,10 +1770,10 @@ static int br_fill_linkxstats(struct sk_buff *skb, if (v->vid == pvid) vxi.flags |= BRIDGE_VLAN_INFO_PVID; br_vlan_get_stats(v, &stats); - vxi.rx_bytes = stats.rx_bytes; - vxi.rx_packets = stats.rx_packets; - vxi.tx_bytes = stats.tx_bytes; - vxi.tx_packets = stats.tx_packets; + vxi.rx_bytes = u64_stats_read(&stats.rx_bytes); + vxi.rx_packets = u64_stats_read(&stats.rx_packets); + vxi.tx_bytes = u64_stats_read(&stats.tx_bytes); + vxi.tx_packets = u64_stats_read(&stats.tx_packets); if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi)) goto nla_put_failure; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 0f5e75ccac79..6e53dc991409 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -505,8 +505,8 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br, if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); - stats->tx_bytes += skb->len; - stats->tx_packets++; + u64_stats_add(&stats->tx_bytes, skb->len); + u64_stats_inc(&stats->tx_packets); u64_stats_update_end(&stats->syncp); } @@ -624,8 +624,8 @@ static bool __allowed_ingress(const struct net_bridge *br, if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += skb->len; - stats->rx_packets++; + u64_stats_add(&stats->rx_bytes, skb->len); + u64_stats_inc(&stats->rx_packets); u64_stats_update_end(&stats->syncp); } @@ -1379,16 +1379,16 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v, cpu_stats = per_cpu_ptr(v->stats, i); do { start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); - rxpackets = cpu_stats->rx_packets; - rxbytes = cpu_stats->rx_bytes; - txbytes = cpu_stats->tx_bytes; - txpackets = cpu_stats->tx_packets; + rxpackets = u64_stats_read(&cpu_stats->rx_packets); + rxbytes = u64_stats_read(&cpu_stats->rx_bytes); + txbytes = u64_stats_read(&cpu_stats->tx_bytes); + txpackets = u64_stats_read(&cpu_stats->tx_packets); } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); - stats->rx_packets += rxpackets; - stats->rx_bytes += rxbytes; - stats->tx_bytes += txbytes; - stats->tx_packets += txpackets; + u64_stats_add(&stats->rx_packets, rxpackets); + u64_stats_add(&stats->rx_bytes, rxbytes); + u64_stats_add(&stats->tx_bytes, txbytes); + u64_stats_add(&stats->tx_packets, txpackets); } } @@ -1779,14 +1779,18 @@ static bool br_vlan_stats_fill(struct sk_buff *skb, return false; br_vlan_get_stats(v, &stats); - if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, stats.rx_bytes, + if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, + u64_stats_read(&stats.rx_bytes), BRIDGE_VLANDB_STATS_PAD) || nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS, - stats.rx_packets, BRIDGE_VLANDB_STATS_PAD) || - nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, stats.tx_bytes, + u64_stats_read(&stats.rx_packets), + BRIDGE_VLANDB_STATS_PAD) || + nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, + u64_stats_read(&stats.tx_bytes), BRIDGE_VLANDB_STATS_PAD) || nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS, - stats.tx_packets, BRIDGE_VLANDB_STATS_PAD)) + u64_stats_read(&stats.tx_packets), + BRIDGE_VLANDB_STATS_PAD)) goto out_err; nla_nest_end(skb, nest); diff --git a/net/core/dev.c b/net/core/dev.c index c9d96b85a825..511cf5d3aade 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10459,23 +10459,23 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s, int cpu; for_each_possible_cpu(cpu) { + u64 rx_packets, rx_bytes, tx_packets, tx_bytes; const struct pcpu_sw_netstats *stats; - struct pcpu_sw_netstats tmp; unsigned int start; stats = per_cpu_ptr(netstats, cpu); do { start = u64_stats_fetch_begin_irq(&stats->syncp); - tmp.rx_packets = stats->rx_packets; - tmp.rx_bytes = stats->rx_bytes; - tmp.tx_packets = stats->tx_packets; - tmp.tx_bytes = stats->tx_bytes; + rx_packets = u64_stats_read(&stats->rx_packets); + rx_bytes = u64_stats_read(&stats->rx_bytes); + tx_packets = u64_stats_read(&stats->tx_packets); + tx_bytes = u64_stats_read(&stats->tx_bytes); } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); - s->rx_packets += tmp.rx_packets; - s->rx_bytes += tmp.rx_bytes; - s->tx_packets += tmp.tx_packets; - s->tx_bytes += tmp.tx_bytes; + s->rx_packets += rx_packets; + s->rx_bytes += rx_bytes; + s->tx_packets += tx_packets; + s->tx_bytes += tx_bytes; } } EXPORT_SYMBOL_GPL(dev_fetch_sw_netstats); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 801a5d445833..2e1ac638d135 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -935,10 +935,10 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev, s = per_cpu_ptr(dev->tstats, i); do { start = u64_stats_fetch_begin_irq(&s->syncp); - tx_packets = s->tx_packets; - tx_bytes = s->tx_bytes; - rx_packets = s->rx_packets; - rx_bytes = s->rx_bytes; + tx_packets = u64_stats_read(&s->tx_packets); + tx_bytes = u64_stats_read(&s->tx_bytes); + rx_packets = u64_stats_read(&s->rx_packets); + rx_bytes = u64_stats_read(&s->rx_bytes); } while (u64_stats_fetch_retry_irq(&s->syncp, start)); data[0] += tx_packets; data[1] += tx_bytes; -- cgit v1.2.3 From 2bff369b23542ea22d0111aaa8e0b8208bf0dc96 Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Wed, 8 Jun 2022 14:14:56 -0400 Subject: bonding: netlink error message support for options Add support for reporting errors via extack in both bond_newlink and bond_changelink. Instead of having to look in the kernel log for why an option was not correct just report the error to the user via the extack variable. What is currently reported today: ip link add bond0 type bond ip link set bond0 up ip link set bond0 type bond mode 4 RTNETLINK answers: Device or resource busy After this change: ip link add bond0 type bond ip link set bond0 up ip link set bond0 type bond mode 4 Error: unable to set option because the bond is up. Signed-off-by: Jonathan Toppins Acked-by: Jay Vosburgh Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_netlink.c | 101 +++++++++++++++++++++++++------------ drivers/net/bonding/bond_options.c | 32 +++++++++--- include/net/bond_options.h | 3 +- 3 files changed, 95 insertions(+), 41 deletions(-) (limited to 'include/net') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 6f404f9c34e3..5a6f44455b95 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -151,7 +151,8 @@ static int bond_slave_changelink(struct net_device *bond_dev, snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n", slave_dev->name, queue_id); bond_opt_initstr(&newval, queue_id_str); - err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval); + err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval, + data[IFLA_BOND_SLAVE_QUEUE_ID], extack); if (err) return err; } @@ -175,7 +176,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int mode = nla_get_u8(data[IFLA_BOND_MODE]); bond_opt_initval(&newval, mode); - err = __bond_opt_set(bond, BOND_OPT_MODE, &newval); + err = __bond_opt_set(bond, BOND_OPT_MODE, &newval, + data[IFLA_BOND_MODE], extack); if (err) return err; } @@ -192,7 +194,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], active_slave = slave_dev->name; } bond_opt_initstr(&newval, active_slave); - err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval, + data[IFLA_BOND_ACTIVE_SLAVE], extack); if (err) return err; } @@ -200,7 +203,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); bond_opt_initval(&newval, miimon); - err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval); + err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval, + data[IFLA_BOND_MIIMON], extack); if (err) return err; } @@ -208,7 +212,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]); bond_opt_initval(&newval, updelay); - err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval, + data[IFLA_BOND_UPDELAY], extack); if (err) return err; } @@ -216,7 +221,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]); bond_opt_initval(&newval, downdelay); - err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval, + data[IFLA_BOND_DOWNDELAY], extack); if (err) return err; } @@ -224,7 +230,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]); bond_opt_initval(&newval, delay); - err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval, + data[IFLA_BOND_PEER_NOTIF_DELAY], extack); if (err) return err; } @@ -232,7 +239,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]); bond_opt_initval(&newval, use_carrier); - err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval); + err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval, + data[IFLA_BOND_USE_CARRIER], extack); if (err) return err; } @@ -240,12 +248,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); if (arp_interval && miimon) { - netdev_err(bond->dev, "ARP monitoring cannot be used with MII monitoring\n"); + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], + "ARP monitoring cannot be used with MII monitoring"); return -EINVAL; } bond_opt_initval(&newval, arp_interval); - err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval, + data[IFLA_BOND_ARP_INTERVAL], extack); if (err) return err; } @@ -264,7 +274,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initval(&newval, (__force u64)target); err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, - &newval); + &newval, + data[IFLA_BOND_ARP_IP_TARGET], + extack); if (err) break; i++; @@ -292,7 +304,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initextra(&newval, &addr6, sizeof(addr6)); err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS, - &newval); + &newval, + data[IFLA_BOND_NS_IP6_TARGET], + extack); if (err) break; i++; @@ -307,12 +321,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); if (arp_validate && miimon) { - netdev_err(bond->dev, "ARP validating cannot be used with MII monitoring\n"); + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], + "ARP validating cannot be used with MII monitoring"); return -EINVAL; } bond_opt_initval(&newval, arp_validate); - err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval, + data[IFLA_BOND_ARP_VALIDATE], extack); if (err) return err; } @@ -321,7 +337,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]); bond_opt_initval(&newval, arp_all_targets); - err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval, + data[IFLA_BOND_ARP_ALL_TARGETS], extack); if (err) return err; } @@ -335,7 +352,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], primary = dev->name; bond_opt_initstr(&newval, primary); - err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval); + err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval, + data[IFLA_BOND_PRIMARY], extack); if (err) return err; } @@ -344,7 +362,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]); bond_opt_initval(&newval, primary_reselect); - err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval); + err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval, + data[IFLA_BOND_PRIMARY_RESELECT], extack); if (err) return err; } @@ -353,7 +372,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]); bond_opt_initval(&newval, fail_over_mac); - err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval); + err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval, + data[IFLA_BOND_FAIL_OVER_MAC], extack); if (err) return err; } @@ -362,7 +382,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]); bond_opt_initval(&newval, xmit_hash_policy); - err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval); + err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval, + data[IFLA_BOND_XMIT_HASH_POLICY], extack); if (err) return err; } @@ -371,7 +392,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_RESEND_IGMP]); bond_opt_initval(&newval, resend_igmp); - err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval); + err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval, + data[IFLA_BOND_RESEND_IGMP], extack); if (err) return err; } @@ -380,7 +402,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]); bond_opt_initval(&newval, num_peer_notif); - err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval); + err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval, + data[IFLA_BOND_NUM_PEER_NOTIF], extack); if (err) return err; } @@ -389,7 +412,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]); bond_opt_initval(&newval, all_slaves_active); - err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval, + data[IFLA_BOND_ALL_SLAVES_ACTIVE], extack); if (err) return err; } @@ -398,7 +422,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_MIN_LINKS]); bond_opt_initval(&newval, min_links); - err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval); + err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval, + data[IFLA_BOND_MIN_LINKS], extack); if (err) return err; } @@ -407,7 +432,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_LP_INTERVAL]); bond_opt_initval(&newval, lp_interval); - err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval); + err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval, + data[IFLA_BOND_LP_INTERVAL], extack); if (err) return err; } @@ -416,7 +442,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]); bond_opt_initval(&newval, packets_per_slave); - err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval, + data[IFLA_BOND_PACKETS_PER_SLAVE], extack); if (err) return err; } @@ -425,7 +452,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int lacp_active = nla_get_u8(data[IFLA_BOND_AD_LACP_ACTIVE]); bond_opt_initval(&newval, lacp_active); - err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval, + data[IFLA_BOND_AD_LACP_ACTIVE], extack); if (err) return err; } @@ -435,7 +463,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]); bond_opt_initval(&newval, lacp_rate); - err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval); + err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval, + data[IFLA_BOND_AD_LACP_RATE], extack); if (err) return err; } @@ -444,7 +473,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_AD_SELECT]); bond_opt_initval(&newval, ad_select); - err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval, + data[IFLA_BOND_AD_SELECT], extack); if (err) return err; } @@ -453,7 +483,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]); bond_opt_initval(&newval, actor_sys_prio); - err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval, + data[IFLA_BOND_AD_ACTOR_SYS_PRIO], extack); if (err) return err; } @@ -462,7 +493,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); bond_opt_initval(&newval, port_key); - err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval, + data[IFLA_BOND_AD_USER_PORT_KEY], extack); if (err) return err; } @@ -472,7 +504,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initval(&newval, nla_get_u64(data[IFLA_BOND_AD_ACTOR_SYSTEM])); - err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval, + data[IFLA_BOND_AD_ACTOR_SYSTEM], extack); if (err) return err; } @@ -480,7 +513,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]); bond_opt_initval(&newval, dynamic_lb); - err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval); + err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval, + data[IFLA_BOND_TLB_DYNAMIC_LB], extack); if (err) return err; } @@ -489,7 +523,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int missed_max = nla_get_u8(data[IFLA_BOND_MISSED_MAX]); bond_opt_initval(&newval, missed_max); - err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval); + err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval, + data[IFLA_BOND_MISSED_MAX], extack); if (err) return err; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1f8323ad5282..96eef19cffc4 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -632,27 +632,35 @@ static int bond_opt_check_deps(struct bonding *bond, } static void bond_opt_dep_print(struct bonding *bond, - const struct bond_option *opt) + const struct bond_option *opt, + struct nlattr *bad_attr, + struct netlink_ext_ack *extack) { const struct bond_opt_value *modeval; struct bond_params *params; params = &bond->params; modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode); - if (test_bit(params->mode, &opt->unsuppmodes)) + if (test_bit(params->mode, &opt->unsuppmodes)) { netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n", opt->name, modeval->string, modeval->value); + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "option not supported in mode"); + } } static void bond_opt_error_interpret(struct bonding *bond, const struct bond_option *opt, - int error, const struct bond_opt_value *val) + int error, const struct bond_opt_value *val, + struct nlattr *bad_attr, + struct netlink_ext_ack *extack) { const struct bond_opt_value *minval, *maxval; char *p; switch (error) { case -EINVAL: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value"); if (val) { if (val->string) { /* sometimes RAWVAL opts may have new lines */ @@ -674,13 +682,17 @@ static void bond_opt_error_interpret(struct bonding *bond, opt->name, minval ? minval->value : 0, maxval->value); break; case -EACCES: - bond_opt_dep_print(bond, opt); + bond_opt_dep_print(bond, opt, bad_attr, extack); break; case -ENOTEMPTY: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "unable to set option because the bond device has slaves"); netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n", opt->name); break; case -EBUSY: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "unable to set option because the bond is up"); netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n", opt->name); break; @@ -691,6 +703,8 @@ static void bond_opt_error_interpret(struct bonding *bond, *p = '\0'; netdev_err(bond->dev, "option %s: interface %s does not exist!\n", opt->name, val->string); + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "interface does not exist"); } break; default: @@ -703,13 +717,17 @@ static void bond_opt_error_interpret(struct bonding *bond, * @bond: target bond device * @option: option to set * @val: value to set it to + * @bad_attr: netlink attribue that caused the error + * @extack: extended netlink error structure, used when an error message + * needs to be returned to the caller via netlink * * This function is used to change the bond's option value, it can be * used for both enabling/changing an option and for disabling it. RTNL lock * must be obtained before calling this function. */ int __bond_opt_set(struct bonding *bond, - unsigned int option, struct bond_opt_value *val) + unsigned int option, struct bond_opt_value *val, + struct nlattr *bad_attr, struct netlink_ext_ack *extack) { const struct bond_opt_value *retval = NULL; const struct bond_option *opt; @@ -731,7 +749,7 @@ int __bond_opt_set(struct bonding *bond, ret = opt->set(bond, retval); out: if (ret) - bond_opt_error_interpret(bond, opt, ret, val); + bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack); return ret; } @@ -753,7 +771,7 @@ int __bond_opt_set_notify(struct bonding *bond, ASSERT_RTNL(); - ret = __bond_opt_set(bond, option, val); + ret = __bond_opt_set(bond, option, val, NULL, NULL); if (!ret && (bond->dev->reg_state == NETREG_REGISTERED)) call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev); diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 61b49063791c..1618b76f4903 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -107,7 +107,8 @@ struct bond_option { }; int __bond_opt_set(struct bonding *bond, unsigned int option, - struct bond_opt_value *val); + struct bond_opt_value *val, + struct nlattr *bad_attr, struct netlink_ext_ack *extack); int __bond_opt_set_notify(struct bonding *bond, unsigned int option, struct bond_opt_value *val); int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf); -- cgit v1.2.3 From b5c8b3fe8946c1927155599dfb79045477901009 Mon Sep 17 00:00:00 2001 From: Eyal Birger Date: Fri, 20 May 2022 13:48:45 +0300 Subject: xfrm: no need to set DST_NOPOLICY in IPv4 This is a cleanup patch following commit e6175a2ed1f1 ("xfrm: fix "disable_policy" flag use when arriving from different devices") which made DST_NOPOLICY no longer be used for inbound policy checks. On outbound the flag was set, but never used. As such, avoid setting it altogether and remove the nopolicy argument from rt_dst_alloc(). Signed-off-by: Eyal Birger Reviewed-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- drivers/net/vrf.c | 2 +- include/net/route.h | 3 +-- net/ipv4/route.c | 24 ++++++++---------------- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'include/net') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 40445a12c682..5df7a0abc39d 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1077,7 +1077,7 @@ static int vrf_rtable_create(struct net_device *dev) return -ENOMEM; /* create a dst for routing packets out through a VRF device */ - rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1); + rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1); if (!rth) return -ENOMEM; diff --git a/include/net/route.h b/include/net/route.h index 991a3985712d..b6743ff88e30 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -244,8 +244,7 @@ void ip_rt_multicast_event(struct in_device *); int ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt); void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); struct rtable *rt_dst_alloc(struct net_device *dev, - unsigned int flags, u16 type, - bool nopolicy, bool noxfrm); + unsigned int flags, u16 type, bool noxfrm); struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); struct in_ifaddr; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2d16bcc7d346..bd351fab46e6 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1626,12 +1626,11 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, struct rtable *rt_dst_alloc(struct net_device *dev, unsigned int flags, u16 type, - bool nopolicy, bool noxfrm) + bool noxfrm) { struct rtable *rt; rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK, - (nopolicy ? DST_NOPOLICY : 0) | (noxfrm ? DST_NOXFRM : 0)); if (rt) { @@ -1726,7 +1725,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct in_device *in_dev = __in_dev_get_rcu(dev); unsigned int flags = RTCF_MULTICAST; struct rtable *rth; - bool no_policy; u32 itag = 0; int err; @@ -1737,12 +1735,11 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (our) flags |= RTCF_LOCAL; - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST, - no_policy, false); + false); if (!rth) return -ENOBUFS; @@ -1801,7 +1798,7 @@ static int __mkroute_input(struct sk_buff *skb, struct rtable *rth; int err; struct in_device *out_dev; - bool do_cache, no_policy; + bool do_cache; u32 itag = 0; /* get a working reference to the output device */ @@ -1846,8 +1843,7 @@ static int __mkroute_input(struct sk_buff *skb, } } - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; fnhe = find_exception(nhc, daddr); @@ -1862,7 +1858,7 @@ static int __mkroute_input(struct sk_buff *skb, } } - rth = rt_dst_alloc(out_dev->dev, 0, res->type, no_policy, + rth = rt_dst_alloc(out_dev->dev, 0, res->type, IN_DEV_ORCONF(out_dev, NOXFRM)); if (!rth) { err = -ENOBUFS; @@ -2237,7 +2233,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct rtable *rth; struct flowi4 fl4; bool do_cache = true; - bool no_policy; /* IP on this device is disabled. */ @@ -2356,8 +2351,7 @@ brd_input: RT_CACHE_STAT_INC(in_brd); local_input: - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; do_cache &= res->fi && !itag; @@ -2373,8 +2367,7 @@ local_input: } rth = rt_dst_alloc(ip_rt_get_dev(net, res), - flags | RTCF_LOCAL, res->type, - no_policy, false); + flags | RTCF_LOCAL, res->type, false); if (!rth) goto e_nobufs; @@ -2597,7 +2590,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res, add: rth = rt_dst_alloc(dev_out, flags, type, - IN_DEV_ORCONF(in_dev, NOPOLICY), IN_DEV_ORCONF(in_dev, NOXFRM)); if (!rth) return ERR_PTR(-ENOBUFS); -- cgit v1.2.3 From 23a5f0af6ff43195c6fd15d8ae59d019836a6046 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Feb 2022 13:14:26 +0100 Subject: wifi: mac80211: remove cipher scheme support The only driver using this was iwlwifi, where we just removed the support because it was never really used. Remove the code from mac80211 as well. Change-Id: I1667417a5932315ee9d81f5c233c56a354923f09 Signed-off-by: Johannes Berg --- include/net/mac80211.h | 35 ------------ net/mac80211/cfg.c | 26 +-------- net/mac80211/ieee80211_i.h | 11 +--- net/mac80211/iface.c | 7 +-- net/mac80211/key.c | 22 +------- net/mac80211/key.h | 7 +-- net/mac80211/main.c | 69 ++--------------------- net/mac80211/mesh_hwmp.c | 6 +- net/mac80211/mlme.c | 6 +- net/mac80211/rx.c | 49 ++++------------- net/mac80211/sta_info.h | 4 +- net/mac80211/tx.c | 21 ++----- net/mac80211/util.c | 70 +----------------------- net/mac80211/wpa.c | 133 +-------------------------------------------- net/mac80211/wpa.h | 5 +- 15 files changed, 39 insertions(+), 432 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ebadb2103968..5c9e97eca739 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1958,36 +1958,6 @@ struct ieee80211_key_seq { }; }; -/** - * struct ieee80211_cipher_scheme - cipher scheme - * - * This structure contains a cipher scheme information defining - * the secure packet crypto handling. - * - * @cipher: a cipher suite selector - * @iftype: a cipher iftype bit mask indicating an allowed cipher usage - * @hdr_len: a length of a security header used the cipher - * @pn_len: a length of a packet number in the security header - * @pn_off: an offset of pn from the beginning of the security header - * @key_idx_off: an offset of key index byte in the security header - * @key_idx_mask: a bit mask of key_idx bits - * @key_idx_shift: a bit shift needed to get key_idx - * key_idx value calculation: - * (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift - * @mic_len: a mic length in bytes - */ -struct ieee80211_cipher_scheme { - u32 cipher; - u16 iftype; - u8 hdr_len; - u8 pn_len; - u8 pn_off; - u8 key_idx_off; - u8 key_idx_mask; - u8 key_idx_shift; - u8 mic_len; -}; - /** * enum set_key_cmd - key command * @@ -2664,9 +2634,6 @@ enum ieee80211_hw_flags { * deliver to a WMM STA during any Service Period triggered by the WMM STA. * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values. * - * @n_cipher_schemes: a size of an array of cipher schemes definitions. - * @cipher_schemes: a pointer to an array of cipher scheme definitions - * supported by HW. * @max_nan_de_entries: maximum number of NAN DE functions supported by the * device. * @@ -2716,8 +2683,6 @@ struct ieee80211_hw { netdev_features_t netdev_features; u8 uapsd_queues; u8 uapsd_max_sp_len; - u8 n_cipher_schemes; - const struct ieee80211_cipher_scheme *cipher_schemes; u8 max_nan_de_entries; u8 tx_sk_pacing_shift; u8 weight_multiplier; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f7896f257e1b..f3b10cee9299 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -438,7 +438,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; struct sta_info *sta = NULL; - const struct ieee80211_cipher_scheme *cs = NULL; struct ieee80211_key *key; int err; @@ -456,23 +455,12 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (WARN_ON_ONCE(fips_enabled)) return -EINVAL; break; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_CCMP_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - break; default: - cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); break; } key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, - params->key, params->seq_len, params->seq, - cs); + params->key, params->seq_len, params->seq); if (IS_ERR(key)) return PTR_ERR(key); @@ -537,9 +525,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, break; } - if (sta) - sta->cipher_scheme = cs; - err = ieee80211_key_link(key, sdata, sta); out_unlock: @@ -1207,9 +1192,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_over_nl80211; sdata->control_port_no_preauth = params->crypto.control_port_no_preauth; - sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, - ¶ms->crypto, - sdata->vif.type); list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { vlan->control_port_protocol = @@ -1220,10 +1202,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_over_nl80211; vlan->control_port_no_preauth = params->crypto.control_port_no_preauth; - vlan->encrypt_headroom = - ieee80211_cs_headroom(sdata->local, - ¶ms->crypto, - vlan->vif.type); } sdata->vif.bss_conf.dtim_period = params->dtim_period; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 86ef0a46a68c..1cf331572de1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #ifndef IEEE80211_I_H @@ -944,7 +944,6 @@ struct ieee80211_sub_if_data { bool control_port_no_encrypt; bool control_port_no_preauth; bool control_port_over_nl80211; - int encrypt_headroom; atomic_t num_tx_queued; struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; @@ -2483,14 +2482,6 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *csa_settings); -bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); -bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); -const struct ieee80211_cipher_scheme * -ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, - enum nl80211_iftype iftype); -int ieee80211_cs_headroom(struct ieee80211_local *local, - struct cfg80211_crypto_settings *crypto, - enum nl80211_iftype iftype); void ieee80211_recalc_dtim(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 41531478437c..fb8d102fca48 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -1036,8 +1036,6 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - ieee80211_set_default_queues(sdata); ret = drv_add_interface(local, sdata); @@ -1644,7 +1642,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_encrypt = false; sdata->control_port_over_nl80211 = false; sdata->control_port_no_preauth = false; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; sdata->vif.bss_conf.idle = true; sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ @@ -2116,8 +2113,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; sdata->user_power_level = local->user_power_level; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 0fcf8aebedc4..c3476de4b14d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -6,7 +6,7 @@ * Copyright 2007-2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright 2018-2020 Intel Corporation + * Copyright 2018-2020, 2022 Intel Corporation */ #include @@ -531,8 +531,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct ieee80211_key * ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, const u8 *key_data, - size_t seq_len, const u8 *seq, - const struct ieee80211_cipher_scheme *cs) + size_t seq_len, const u8 *seq) { struct ieee80211_key *key; int i, j, err; @@ -675,21 +674,6 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, return ERR_PTR(err); } break; - default: - if (cs) { - if (seq_len && seq_len != cs->pn_len) { - kfree(key); - return ERR_PTR(-EINVAL); - } - - key->conf.iv_len = cs->hdr_len; - key->conf.icv_len = cs->mic_len; - for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) - for (j = 0; j < seq_len; j++) - key->u.gen.rx_pn[i][j] = - seq[seq_len - j - 1]; - key->flags |= KEY_FLAG_CIPHER_SCHEME; - } } memcpy(key->conf.key, key_data, key_len); INIT_LIST_HEAD(&key->list); @@ -1294,7 +1278,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, keyconf->keylen, keyconf->key, - 0, NULL, NULL); + 0, NULL); if (IS_ERR(key)) return ERR_CAST(key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 1e326c89d721..b3fb41c0c77f 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -2,7 +2,7 @@ /* * Copyright 2002-2004, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019, 2022 Intel Corporation */ #ifndef IEEE80211_KEY_H @@ -30,12 +30,10 @@ struct sta_info; * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present * in the hardware for TX crypto hardware acceleration. * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped. - * @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme */ enum ieee80211_internal_key_flags { KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), KEY_FLAG_TAINTED = BIT(1), - KEY_FLAG_CIPHER_SCHEME = BIT(2), }; enum ieee80211_internal_tkip_state { @@ -140,8 +138,7 @@ struct ieee80211_key { struct ieee80211_key * ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, const u8 *key_data, - size_t seq_len, const u8 *seq, - const struct ieee80211_cipher_scheme *cs); + size_t seq_len, const u8 *seq); /* * Insert a key into data structures (sdata, sta if necessary) * to make it used, free old key. On failure, also free the new key. diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5a385d4146b9..4f3e93c0819b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -778,7 +778,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) { bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */ bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE); - int n_suites = 0, r = 0, w = 0; + int r = 0, w = 0; u32 *suites; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ @@ -824,10 +824,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) continue; suites[w++] = suite; } - } else if (!local->hw.cipher_schemes) { - /* If the driver doesn't have cipher schemes, there's nothing - * else to do other than assign the (software supported and - * perhaps offloaded) cipher suites. + } else { + /* assign the (software supported and perhaps offloaded) + * cipher suites */ local->hw.wiphy->cipher_suites = cipher_suites; local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -842,58 +841,6 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) /* not dynamically allocated, so just return */ return 0; - } else { - const struct ieee80211_cipher_scheme *cs; - - cs = local->hw.cipher_schemes; - - /* Driver specifies cipher schemes only (but not cipher suites - * including the schemes) - * - * We start counting ciphers defined by schemes, TKIP, CCMP, - * CCMP-256, GCMP, and GCMP-256 - */ - n_suites = local->hw.n_cipher_schemes + 5; - - /* check if we have WEP40 and WEP104 */ - if (have_wep) - n_suites += 2; - - /* check if we have AES_CMAC, BIP-CMAC-256, BIP-GMAC-128, - * BIP-GMAC-256 - */ - if (have_mfp) - n_suites += 4; - - suites = kmalloc_array(n_suites, sizeof(u32), GFP_KERNEL); - if (!suites) - return -ENOMEM; - - suites[w++] = WLAN_CIPHER_SUITE_CCMP; - suites[w++] = WLAN_CIPHER_SUITE_CCMP_256; - suites[w++] = WLAN_CIPHER_SUITE_TKIP; - suites[w++] = WLAN_CIPHER_SUITE_GCMP; - suites[w++] = WLAN_CIPHER_SUITE_GCMP_256; - - if (have_wep) { - suites[w++] = WLAN_CIPHER_SUITE_WEP40; - suites[w++] = WLAN_CIPHER_SUITE_WEP104; - } - - if (have_mfp) { - suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; - suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; - suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_128; - suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256; - } - - for (r = 0; r < local->hw.n_cipher_schemes; r++) { - suites[w++] = cs[r].cipher; - if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN)) { - kfree(suites); - return -EINVAL; - } - } } local->hw.wiphy->cipher_suites = suites; @@ -1168,12 +1115,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; - if (WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, - local->hw.n_cipher_schemes))) { - result = -EINVAL; - goto fail_workqueue; - } - result = ieee80211_init_cipher_suites(local); if (result < 0) goto fail_workqueue; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 58ebdcd69d05..45e7c1b307bc 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation * Author: Luis Carlos Cobo */ @@ -247,13 +247,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, return -EAGAIN; skb = dev_alloc_skb(local->tx_headroom + - sdata->encrypt_headroom + + IEEE80211_ENCRYPT_HEADROOM + IEEE80211_ENCRYPT_TAILROOM + hdr_len + 2 + 15 /* PERR IE */); if (!skb) return -1; - skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); + skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); mgmt = skb_put_zero(skb, hdr_len); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 58d48dcae030..6d5ad71ef02c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8,7 +8,7 @@ * Copyright 2007, Michael Wu * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation */ #include @@ -2496,8 +2496,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - bss_conf->pwr_reduction = 0; bss_conf->tx_pwr_env_num = 0; memset(bss_conf->tx_pwr_env, 0, sizeof(bss_conf->tx_pwr_env)); @@ -6071,8 +6069,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_over_nl80211 = req->crypto.control_port_over_nl80211; sdata->control_port_no_preauth = req->crypto.control_port_no_preauth; - sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, - sdata->vif.type); /* kick off associate process */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3c08ae04ddbc..a9f4e90ad893 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -1009,43 +1009,20 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return -1; } -static int ieee80211_get_keyid(struct sk_buff *skb, - const struct ieee80211_cipher_scheme *cs) +static int ieee80211_get_keyid(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; - int hdrlen; - int minlen; - u8 key_idx_off; - u8 key_idx_shift; + __le16 fc = hdr->frame_control; + int hdrlen = ieee80211_hdrlen(fc); u8 keyid; - fc = hdr->frame_control; - hdrlen = ieee80211_hdrlen(fc); - - if (cs) { - minlen = hdrlen + cs->hdr_len; - key_idx_off = hdrlen + cs->key_idx_off; - key_idx_shift = cs->key_idx_shift; - } else { - /* WEP, TKIP, CCMP and GCMP */ - minlen = hdrlen + IEEE80211_WEP_IV_LEN; - key_idx_off = hdrlen + 3; - key_idx_shift = 6; - } - - if (unlikely(skb->len < minlen)) + /* WEP, TKIP, CCMP and GCMP */ + if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN)) return -EINVAL; - skb_copy_bits(skb, key_idx_off, &keyid, 1); + skb_copy_bits(skb, hdrlen + 3, &keyid, 1); - if (cs) - keyid &= cs->key_idx_mask; - keyid >>= key_idx_shift; - - /* cs could use more than the usual two bits for the keyid */ - if (unlikely(keyid >= NUM_DEFAULT_KEYS)) - return -EINVAL; + keyid >>= 6; return keyid; } @@ -1916,7 +1893,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *ptk_idx = NULL; int mmie_keyidx = -1; __le16 fc; - const struct ieee80211_cipher_scheme *cs = NULL; if (ieee80211_is_ext(hdr->frame_control)) return RX_CONTINUE; @@ -1959,8 +1935,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (ieee80211_has_protected(fc) && !(status->flag & RX_FLAG_IV_STRIPPED)) { - cs = rx->sta->cipher_scheme; - keyid = ieee80211_get_keyid(rx->skb, cs); + keyid = ieee80211_get_keyid(rx->skb); if (unlikely(keyid < 0)) return RX_DROP_UNUSABLE; @@ -2065,7 +2040,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; - keyidx = ieee80211_get_keyid(rx->skb, cs); + keyidx = ieee80211_get_keyid(rx->skb); if (unlikely(keyidx < 0)) return RX_DROP_UNUSABLE; @@ -2131,7 +2106,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) result = ieee80211_crypto_gcmp_decrypt(rx); break; default: - result = ieee80211_crypto_hw_decrypt(rx); + result = RX_DROP_UNUSABLE; } /* the hdr variable is invalid after the decrypt handlers */ @@ -2945,7 +2920,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) tailroom = IEEE80211_ENCRYPT_TAILROOM; fwd_skb = skb_copy_expand(skb, local->tx_headroom + - sdata->encrypt_headroom, + IEEE80211_ENCRYPT_HEADROOM, tailroom, GFP_ATOMIC); if (!fwd_skb) goto out; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 35c390bedfba..aa6950aa49a9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -3,7 +3,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright(c) 2020-2021 Intel Corporation + * Copyright(c) 2020-2022 Intel Corporation */ #ifndef STA_INFO_H @@ -616,7 +616,6 @@ struct link_sta_info { * taken from HT/VHT capabilities or VHT operating mode notification * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * AP only. - * @cipher_scheme: optional cipher scheme for this station * @cparams: CoDel parameters for this station. * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) * @fast_tx: TX fastpath information @@ -700,7 +699,6 @@ struct sta_info { #endif enum ieee80211_smps_mode known_smps_mode; - const struct ieee80211_cipher_scheme *cipher_scheme; struct codel_params cparams; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0e4efc08c762..37fe72bb5ab0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * Transmit and frame generation functions. */ @@ -882,7 +882,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, rem -= fraglen; tmp = dev_alloc_skb(local->tx_headroom + frag_threshold + - tx->sdata->encrypt_headroom + + IEEE80211_ENCRYPT_HEADROOM + IEEE80211_ENCRYPT_TAILROOM); if (!tmp) return -ENOMEM; @@ -890,7 +890,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, __skb_queue_tail(&tx->skbs, tmp); skb_reserve(tmp, - local->tx_headroom + tx->sdata->encrypt_headroom); + local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); /* copy control information */ memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); @@ -1040,8 +1040,6 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: return ieee80211_crypto_gcmp_encrypt(tx); - default: - return ieee80211_crypto_hw_encrypt(tx); } return TX_DROP; @@ -2013,7 +2011,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, headroom = local->tx_headroom; if (encrypt != ENCRYPT_NO) - headroom += sdata->encrypt_headroom; + headroom += IEEE80211_ENCRYPT_HEADROOM; headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); @@ -2867,7 +2865,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, */ if (head_need > 0 || skb_cloned(skb)) { - head_need += sdata->encrypt_headroom; + head_need += IEEE80211_ENCRYPT_HEADROOM; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) { @@ -3128,15 +3126,6 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) /* we don't know how to generate IVs for this at all */ if (WARN_ON(gen_iv)) goto out; - /* pure hardware keys are OK, of course */ - if (!(build.key->flags & KEY_FLAG_CIPHER_SCHEME)) - break; - /* cipher scheme might require space allocation */ - if (iv_spc && - build.key->conf.iv_len > IEEE80211_FAST_XMIT_MAX_IV) - goto out; - if (iv_spc) - build.hdr_len += build.key->conf.iv_len; } fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1e26b5235add..9e6c4dcef280 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -6,7 +6,7 @@ * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * utilities for mac80211 */ @@ -4212,74 +4212,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, return 0; } -bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) -{ - return !(cs == NULL || cs->cipher == 0 || - cs->hdr_len < cs->pn_len + cs->pn_off || - cs->hdr_len <= cs->key_idx_off || - cs->key_idx_shift > 7 || - cs->key_idx_mask == 0); -} - -bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) -{ - int i; - - /* Ensure we have enough iftype bitmap space for all iftype values */ - WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); - - for (i = 0; i < n; i++) - if (!ieee80211_cs_valid(&cs[i])) - return false; - - return true; -} - -const struct ieee80211_cipher_scheme * -ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, - enum nl80211_iftype iftype) -{ - const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; - int n = local->hw.n_cipher_schemes; - int i; - const struct ieee80211_cipher_scheme *cs = NULL; - - for (i = 0; i < n; i++) { - if (l[i].cipher == cipher) { - cs = &l[i]; - break; - } - } - - if (!cs || !(cs->iftype & BIT(iftype))) - return NULL; - - return cs; -} - -int ieee80211_cs_headroom(struct ieee80211_local *local, - struct cfg80211_crypto_settings *crypto, - enum nl80211_iftype iftype) -{ - const struct ieee80211_cipher_scheme *cs; - int headroom = IEEE80211_ENCRYPT_HEADROOM; - int i; - - for (i = 0; i < crypto->n_ciphers_pairwise; i++) { - cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], - iftype); - - if (cs && headroom < cs->hdr_len) - headroom = cs->hdr_len; - } - - cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); - if (cs && headroom < cs->hdr_len) - headroom = cs->hdr_len; - - return headroom; -} - static bool ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i) { diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 5fd8a3e8b5b4..93ec2f349748 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -3,7 +3,7 @@ * Copyright 2002-2004, Instant802 Networks, Inc. * Copyright 2008, Jouni Malinen * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation */ #include @@ -778,102 +778,6 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static ieee80211_tx_result -ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_key *key = tx->key; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int hdrlen; - u8 *pos, iv_len = key->conf.iv_len; - - if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { - /* hwaccel has no need for preallocated head room */ - return TX_CONTINUE; - } - - if (unlikely(skb_headroom(skb) < iv_len && - pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC))) - return TX_DROP; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - pos = skb_push(skb, iv_len); - memmove(pos, pos + iv_len, hdrlen); - - return TX_CONTINUE; -} - -static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) -{ - int i; - - /* pn is little endian */ - for (i = len - 1; i >= 0; i--) { - if (pn1[i] < pn2[i]) - return -1; - else if (pn1[i] > pn2[i]) - return 1; - } - - return 0; -} - -static ieee80211_rx_result -ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) -{ - struct ieee80211_key *key = rx->key; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - const struct ieee80211_cipher_scheme *cs = NULL; - int hdrlen = ieee80211_hdrlen(hdr->frame_control); - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int data_len; - u8 *rx_pn; - u8 *skb_pn; - u8 qos_tid; - - if (!rx->sta || !rx->sta->cipher_scheme || - !(status->flag & RX_FLAG_DECRYPTED)) - return RX_DROP_UNUSABLE; - - if (!ieee80211_is_data(hdr->frame_control)) - return RX_CONTINUE; - - cs = rx->sta->cipher_scheme; - - data_len = rx->skb->len - hdrlen - cs->hdr_len; - - if (data_len < 0) - return RX_DROP_UNUSABLE; - - if (ieee80211_is_data_qos(hdr->frame_control)) - qos_tid = ieee80211_get_tid(hdr); - else - qos_tid = 0; - - if (skb_linearize(rx->skb)) - return RX_DROP_UNUSABLE; - - rx_pn = key->u.gen.rx_pn[qos_tid]; - skb_pn = rx->skb->data + hdrlen + cs->pn_off; - - if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) - return RX_DROP_UNUSABLE; - - memcpy(rx_pn, skb_pn, cs->pn_len); - - /* remove security header and MIC */ - if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) - return RX_DROP_UNUSABLE; - - memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); - skb_pull(rx->skb, cs->hdr_len); - - return RX_CONTINUE; -} - static void bip_aad(struct sk_buff *skb, u8 *aad) { __le16 mask_fc; @@ -1212,38 +1116,3 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } - -ieee80211_tx_result -ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) -{ - struct sk_buff *skb; - struct ieee80211_tx_info *info = NULL; - ieee80211_tx_result res; - - skb_queue_walk(&tx->skbs, skb) { - info = IEEE80211_SKB_CB(skb); - - /* handle hw-only algorithm */ - if (!info->control.hw_key) - return TX_DROP; - - if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) { - res = ieee80211_crypto_cs_encrypt(tx, skb); - if (res != TX_CONTINUE) - return res; - } - } - - ieee80211_tx_set_protected(tx); - - return TX_CONTINUE; -} - -ieee80211_rx_result -ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) -{ - if (rx->sta && rx->sta->cipher_scheme) - return ieee80211_crypto_cs_decrypt(rx); - - return RX_DROP_UNUSABLE; -} diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index af3272284e85..a9a81abb5479 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2002-2004, Instant802 Networks, Inc. + * Copyright (C) 2022 Intel Corporation */ #ifndef WPA_H @@ -39,10 +40,6 @@ ieee80211_tx_result ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx); ieee80211_rx_result ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx); -ieee80211_tx_result -ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); -ieee80211_rx_result -ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); ieee80211_tx_result ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx); -- cgit v1.2.3 From e70f3c701276a8825414dc650c4f76141a8704b4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:06 -0700 Subject: Revert "net: set SK_MEM_QUANTUM to 4096" This reverts commit bd68a2a854ad5a85f0c8d0a9c8048ca3f6391efb. This change broke memcg on arches with PAGE_SIZE != 4096 Later, commit 2bb2f5fb21b04 ("net: add new socket option SO_RESERVE_MEM") also assumed PAGE_SIZE==SK_MEM_QUANTUM Following patches in the series will greatly reduce the over allocations problem. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 657873e2d90f..5c5265269899 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1532,25 +1532,15 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind); void __sk_mem_reduce_allocated(struct sock *sk, int amount); void __sk_mem_reclaim(struct sock *sk, int amount); -/* We used to have PAGE_SIZE here, but systems with 64KB pages - * do not necessarily have 16x time more memory than 4KB ones. - */ -#define SK_MEM_QUANTUM 4096 +#define SK_MEM_QUANTUM ((int)PAGE_SIZE) #define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) #define SK_MEM_SEND 0 #define SK_MEM_RECV 1 -/* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */ +/* sysctl_mem values are in pages */ static inline long sk_prot_mem_limits(const struct sock *sk, int index) { - long val = sk->sk_prot->sysctl_mem[index]; - -#if PAGE_SIZE > SK_MEM_QUANTUM - val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT; -#elif PAGE_SIZE < SK_MEM_QUANTUM - val >>= SK_MEM_QUANTUM_SHIFT - PAGE_SHIFT; -#endif - return val; + return sk->sk_prot->sysctl_mem[index]; } static inline int sk_mem_pages(int amt) -- cgit v1.2.3 From 100fdd1faf50557558e2911af4be32e515cb8036 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:07 -0700 Subject: net: remove SK_MEM_QUANTUM and SK_MEM_QUANTUM_SHIFT Due to memcg interface, SK_MEM_QUANTUM is effectively PAGE_SIZE. This might change in the future, but it seems better to avoid the confusion. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 8 +++----- net/core/sock.c | 16 ++++++++-------- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 2 +- net/ipv4/udp.c | 10 +++++----- net/mptcp/protocol.c | 8 ++++---- net/sctp/protocol.c | 4 ++-- 8 files changed, 26 insertions(+), 28 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 5c5265269899..298897bbfb3a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1532,8 +1532,6 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind); void __sk_mem_reduce_allocated(struct sock *sk, int amount); void __sk_mem_reclaim(struct sock *sk, int amount); -#define SK_MEM_QUANTUM ((int)PAGE_SIZE) -#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) #define SK_MEM_SEND 0 #define SK_MEM_RECV 1 @@ -1545,7 +1543,7 @@ static inline long sk_prot_mem_limits(const struct sock *sk, int index) static inline int sk_mem_pages(int amt) { - return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT; + return (amt + PAGE_SIZE - 1) >> PAGE_SHIFT; } static inline bool sk_has_account(struct sock *sk) @@ -1594,7 +1592,7 @@ static inline void sk_mem_reclaim(struct sock *sk) reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - if (reclaimable >= SK_MEM_QUANTUM) + if (reclaimable >= (int)PAGE_SIZE) __sk_mem_reclaim(sk, reclaimable); } @@ -1613,7 +1611,7 @@ static inline void sk_mem_reclaim_partial(struct sock *sk) reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - if (reclaimable > SK_MEM_QUANTUM) + if (reclaimable > (int)PAGE_SIZE) __sk_mem_reclaim(sk, reclaimable - 1); } diff --git a/net/core/sock.c b/net/core/sock.c index f5062d9e1222..063fd7680a84 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -991,7 +991,7 @@ EXPORT_SYMBOL(sock_set_mark); static void sock_release_reserved_memory(struct sock *sk, int bytes) { /* Round down bytes to multiple of pages */ - bytes &= ~(SK_MEM_QUANTUM - 1); + bytes = round_down(bytes, PAGE_SIZE); WARN_ON(bytes > sk->sk_reserved_mem); sk->sk_reserved_mem -= bytes; @@ -1028,9 +1028,9 @@ static int sock_reserve_memory(struct sock *sk, int bytes) mem_cgroup_uncharge_skmem(sk->sk_memcg, pages); return -ENOMEM; } - sk->sk_forward_alloc += pages << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc += pages << PAGE_SHIFT; - sk->sk_reserved_mem += pages << SK_MEM_QUANTUM_SHIFT; + sk->sk_reserved_mem += pages << PAGE_SHIFT; return 0; } @@ -3003,10 +3003,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) { int ret, amt = sk_mem_pages(size); - sk->sk_forward_alloc += amt << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc += amt << PAGE_SHIFT; ret = __sk_mem_raise_allocated(sk, size, amt, kind); if (!ret) - sk->sk_forward_alloc -= amt << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc -= amt << PAGE_SHIFT; return ret; } EXPORT_SYMBOL(__sk_mem_schedule); @@ -3034,12 +3034,12 @@ EXPORT_SYMBOL(__sk_mem_reduce_allocated); /** * __sk_mem_reclaim - reclaim sk_forward_alloc and memory_allocated * @sk: socket - * @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple) + * @amount: number of bytes (rounded down to a PAGE_SIZE multiple) */ void __sk_mem_reclaim(struct sock *sk, int amount) { - amount >>= SK_MEM_QUANTUM_SHIFT; - sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT; + amount >>= PAGE_SHIFT; + sk->sk_forward_alloc -= amount << PAGE_SHIFT; __sk_mem_reduce_allocated(sk, amount); } EXPORT_SYMBOL(__sk_mem_reclaim); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9984d23a7f3e..9e696758a4c2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4661,11 +4661,11 @@ void __init tcp_init(void) max_wshare = min(4UL*1024*1024, limit); max_rshare = min(6UL*1024*1024, limit); - init_net.ipv4.sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; + init_net.ipv4.sysctl_tcp_wmem[0] = PAGE_SIZE; init_net.ipv4.sysctl_tcp_wmem[1] = 16*1024; init_net.ipv4.sysctl_tcp_wmem[2] = max(64*1024, max_wshare); - init_net.ipv4.sysctl_tcp_rmem[0] = SK_MEM_QUANTUM; + init_net.ipv4.sysctl_tcp_rmem[0] = PAGE_SIZE; init_net.ipv4.sysctl_tcp_rmem[1] = 131072; init_net.ipv4.sysctl_tcp_rmem[2] = max(131072, max_rshare); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2e2a9ece9af2..3fb117022558 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5287,7 +5287,7 @@ new_range: before(TCP_SKB_CB(skb)->end_seq, start)) { /* Do not attempt collapsing tiny skbs */ if (range_truesize != head->truesize || - end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + end - start >= SKB_WITH_OVERHEAD(PAGE_SIZE)) { tcp_collapse(sk, NULL, &tp->out_of_order_queue, head, skb, start, end); } else { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 1c054431e358..8ab98e1aca67 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3367,7 +3367,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size) if (size <= sk->sk_forward_alloc) return; amt = sk_mem_pages(size); - sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; + sk->sk_forward_alloc += amt << PAGE_SHIFT; sk_memory_allocated_add(sk, amt); if (mem_cgroup_sockets_enabled && sk->sk_memcg) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index aa9f2ec3dc46..bbc9970fa2e9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1461,11 +1461,11 @@ static void udp_rmem_release(struct sock *sk, int size, int partial, sk->sk_forward_alloc += size; - amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1); + amt = (sk->sk_forward_alloc - partial) & ~(PAGE_SIZE - 1); sk->sk_forward_alloc -= amt; if (amt) - __sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT); + __sk_mem_reduce_allocated(sk, amt >> PAGE_SHIFT); atomic_sub(size, &sk->sk_rmem_alloc); @@ -1558,7 +1558,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb) spin_lock(&list->lock); if (size >= sk->sk_forward_alloc) { amt = sk_mem_pages(size); - delta = amt << SK_MEM_QUANTUM_SHIFT; + delta = amt << PAGE_SHIFT; if (!__sk_mem_raise_allocated(sk, delta, amt, SK_MEM_RECV)) { err = -ENOBUFS; spin_unlock(&list->lock); @@ -3263,8 +3263,8 @@ EXPORT_SYMBOL(udp_flow_hashrnd); static void __udp_sysctl_init(struct net *net) { - net->ipv4.sysctl_udp_rmem_min = SK_MEM_QUANTUM; - net->ipv4.sysctl_udp_wmem_min = SK_MEM_QUANTUM; + net->ipv4.sysctl_udp_rmem_min = PAGE_SIZE; + net->ipv4.sysctl_udp_wmem_min = PAGE_SIZE; #ifdef CONFIG_NET_L3_MASTER_DEV net->ipv4.sysctl_udp_l3mdev_accept = 0; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 17e13396024a..080a630d6902 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -167,8 +167,8 @@ static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff *to, static void __mptcp_rmem_reclaim(struct sock *sk, int amount) { - amount >>= SK_MEM_QUANTUM_SHIFT; - mptcp_sk(sk)->rmem_fwd_alloc -= amount << SK_MEM_QUANTUM_SHIFT; + amount >>= PAGE_SHIFT; + mptcp_sk(sk)->rmem_fwd_alloc -= amount << PAGE_SHIFT; __sk_mem_reduce_allocated(sk, amount); } @@ -327,7 +327,7 @@ static bool mptcp_rmem_schedule(struct sock *sk, struct sock *ssk, int size) return true; amt = sk_mem_pages(size); - amount = amt << SK_MEM_QUANTUM_SHIFT; + amount = amt << PAGE_SHIFT; msk->rmem_fwd_alloc += amount; if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV)) { if (ssk->sk_forward_alloc < amount) { @@ -972,7 +972,7 @@ static void __mptcp_mem_reclaim_partial(struct sock *sk) lockdep_assert_held_once(&sk->sk_lock.slock); - if (reclaimable > SK_MEM_QUANTUM) + if (reclaimable > (int)PAGE_SIZE) __mptcp_rmem_reclaim(sk, reclaimable - 1); sk_mem_reclaim_partial(sk); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 35928fefae33..fa500ea3a1f1 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1523,11 +1523,11 @@ static __init int sctp_init(void) limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7); max_share = min(4UL*1024*1024, limit); - sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */ + sysctl_sctp_rmem[0] = PAGE_SIZE; /* give each asoc 1 page min */ sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1); sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share); - sysctl_sctp_wmem[0] = SK_MEM_QUANTUM; + sysctl_sctp_wmem[0] = PAGE_SIZE; sysctl_sctp_wmem[1] = 16*1024; sysctl_sctp_wmem[2] = max(64*1024, max_share); -- cgit v1.2.3 From 0defbb0af775ef037913786048d099bbe8b9a2c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:08 -0700 Subject: net: add per_cpu_fw_alloc field to struct proto Each protocol having a ->memory_allocated pointer gets a corresponding per-cpu reserve, that following patches will use. Instead of having reserved bytes per socket, we want to have per-cpu reserves. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 1 + include/net/tcp.h | 2 ++ include/net/udp.h | 1 + net/core/sock.c | 4 ++++ net/decnet/af_decnet.c | 4 ++++ net/ipv4/tcp.c | 2 ++ net/ipv4/tcp_ipv4.c | 3 +++ net/ipv4/udp.c | 4 ++++ net/ipv4/udplite.c | 3 +++ net/ipv6/tcp_ipv6.c | 3 +++ net/ipv6/udp.c | 3 +++ net/ipv6/udplite.c | 3 +++ net/mptcp/protocol.c | 3 +++ net/sctp/socket.c | 7 +++++++ 14 files changed, 43 insertions(+) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 298897bbfb3a..825f8cbf791f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1254,6 +1254,7 @@ struct proto { void (*enter_memory_pressure)(struct sock *sk); void (*leave_memory_pressure)(struct sock *sk); atomic_long_t *memory_allocated; /* Current allocated memory. */ + int __percpu *per_cpu_fw_alloc; struct percpu_counter *sockets_allocated; /* Current number of sockets. */ /* diff --git a/include/net/tcp.h b/include/net/tcp.h index 1e99f5c61f84..4794cae4577e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -253,6 +253,8 @@ extern long sysctl_tcp_mem[3]; #define TCP_RACK_NO_DUPTHRESH 0x4 /* Do not use DUPACK threshold in RACK */ extern atomic_long_t tcp_memory_allocated; +DECLARE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); + extern struct percpu_counter tcp_sockets_allocated; extern unsigned long tcp_memory_pressure; diff --git a/include/net/udp.h b/include/net/udp.h index b83a00330566..b60eea2e3fae 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -95,6 +95,7 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table, extern struct proto udp_prot; extern atomic_long_t udp_memory_allocated; +DECLARE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); /* sysctl variables for udp */ extern long sysctl_udp_mem[3]; diff --git a/net/core/sock.c b/net/core/sock.c index 063fd7680a84..f96efc95e334 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3798,6 +3798,10 @@ int proto_register(struct proto *prot, int alloc_slab) pr_err("%s: missing sysctl_mem\n", prot->name); return -EINVAL; } + if (prot->memory_allocated && !prot->per_cpu_fw_alloc) { + pr_err("%s: missing per_cpu_fw_alloc\n", prot->name); + return -EINVAL; + } if (alloc_slab) { prot->slab = kmem_cache_create_usercopy(prot->name, prot->obj_size, 0, diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index dc92a67baea3..aa4f43f52499 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -149,6 +149,7 @@ static DEFINE_RWLOCK(dn_hash_lock); static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_wild_sk; static atomic_long_t decnet_memory_allocated; +static DEFINE_PER_CPU(int, decnet_memory_per_cpu_fw_alloc); static int __dn_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen, int flags); @@ -454,7 +455,10 @@ static struct proto dn_proto = { .owner = THIS_MODULE, .enter_memory_pressure = dn_enter_memory_pressure, .memory_pressure = &dn_memory_pressure, + .memory_allocated = &decnet_memory_allocated, + .per_cpu_fw_alloc = &decnet_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_decnet_mem, .sysctl_wmem = sysctl_decnet_wmem, .sysctl_rmem = sysctl_decnet_rmem, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9e696758a4c2..e6bdf8e2c09a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -294,6 +294,8 @@ EXPORT_SYMBOL(sysctl_tcp_mem); atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; /* Current allocated memory. */ EXPORT_SYMBOL(tcp_memory_allocated); +DEFINE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); +EXPORT_PER_CPU_SYMBOL_GPL(tcp_memory_per_cpu_fw_alloc); #if IS_ENABLED(CONFIG_SMC) DEFINE_STATIC_KEY_FALSE(tcp_have_smc); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fe8f23b95d32..fda811a5251f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3045,7 +3045,10 @@ struct proto tcp_prot = { .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, .orphan_count = &tcp_orphan_count, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .sysctl_mem = sysctl_tcp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bbc9970fa2e9..6172b4750a88 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -125,6 +125,8 @@ EXPORT_SYMBOL(sysctl_udp_mem); atomic_long_t udp_memory_allocated ____cacheline_aligned_in_smp; EXPORT_SYMBOL(udp_memory_allocated); +DEFINE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); +EXPORT_PER_CPU_SYMBOL_GPL(udp_memory_per_cpu_fw_alloc); #define MAX_UDP_PORTS 65536 #define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN) @@ -2946,6 +2948,8 @@ struct proto udp_prot = { .psock_update_sk_prot = udp_bpf_update_proto, #endif .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_udp_wmem_min), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_udp_rmem_min), diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index cd1cd68adeec..6e08a76ae1e7 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -51,7 +51,10 @@ struct proto udplite_prot = { .unhash = udp_lib_unhash, .rehash = udp_v4_rehash, .get_port = udp_v4_get_port, + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .obj_size = sizeof(struct udp_sock), .h.udp_table = &udplite_table, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f37dd4aa91c6..c72448ba6dc9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2159,7 +2159,10 @@ struct proto tcpv6_prot = { .leave_memory_pressure = tcp_leave_memory_pressure, .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .orphan_count = &tcp_orphan_count, .sysctl_mem = sysctl_tcp_mem, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 55afd7f39c04..be074f07073a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1740,7 +1740,10 @@ struct proto udpv6_prot = { #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = udp_bpf_update_proto, #endif + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_udp_wmem_min), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_udp_rmem_min), diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index fbb700d3f437..b70725856259 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -48,7 +48,10 @@ struct proto udplitev6_prot = { .unhash = udp_lib_unhash, .rehash = udp_v6_rehash, .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .obj_size = sizeof(struct udp6_sock), .h.udp_table = &udplite_table, diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 080a630d6902..9563124ac8af 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3437,7 +3437,10 @@ static struct proto mptcp_prot = { .get_port = mptcp_get_port, .forward_alloc_get = mptcp_forward_alloc_get, .sockets_allocated = &mptcp_sockets_allocated, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6d37d2dfb3da..05174acd981a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -93,6 +93,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, static unsigned long sctp_memory_pressure; static atomic_long_t sctp_memory_allocated; +static DEFINE_PER_CPU(int, sctp_memory_per_cpu_fw_alloc); struct percpu_counter sctp_sockets_allocated; static void sctp_enter_memory_pressure(struct sock *sk) @@ -9657,7 +9658,10 @@ struct proto sctp_prot = { .sysctl_wmem = sysctl_sctp_wmem, .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, + .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc, + .sockets_allocated = &sctp_sockets_allocated, }; @@ -9700,7 +9704,10 @@ struct proto sctpv6_prot = { .sysctl_wmem = sysctl_sctp_wmem, .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, + .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc, + .sockets_allocated = &sctp_sockets_allocated, }; #endif /* IS_ENABLED(CONFIG_IPV6) */ -- cgit v1.2.3 From 3cd3399dd7a84ada85cb839989cdf7310e302c7d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:09 -0700 Subject: net: implement per-cpu reserves for memory_allocated We plan keeping sk->sk_forward_alloc as small as possible in future patches. This means we are going to call sk_memory_allocated_add() and sk_memory_allocated_sub() more often. Implement a per-cpu cache of +1/-1 MB, to reduce number of changes to sk->sk_prot->memory_allocated, which would otherwise be cause of false sharing. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Reviewed-by: Shakeel Butt Signed-off-by: Jakub Kicinski --- include/net/sock.h | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 825f8cbf791f..59040fee74e7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1397,22 +1397,48 @@ static inline bool sk_under_memory_pressure(const struct sock *sk) return !!*sk->sk_prot->memory_pressure; } +static inline long +proto_memory_allocated(const struct proto *prot) +{ + return max(0L, atomic_long_read(prot->memory_allocated)); +} + static inline long sk_memory_allocated(const struct sock *sk) { - return atomic_long_read(sk->sk_prot->memory_allocated); + return proto_memory_allocated(sk->sk_prot); } +/* 1 MB per cpu, in page units */ +#define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT)) + static inline long sk_memory_allocated_add(struct sock *sk, int amt) { - return atomic_long_add_return(amt, sk->sk_prot->memory_allocated); + int local_reserve; + + preempt_disable(); + local_reserve = __this_cpu_add_return(*sk->sk_prot->per_cpu_fw_alloc, amt); + if (local_reserve >= SK_MEMORY_PCPU_RESERVE) { + __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); + atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); + } + preempt_enable(); + return sk_memory_allocated(sk); } static inline void sk_memory_allocated_sub(struct sock *sk, int amt) { - atomic_long_sub(amt, sk->sk_prot->memory_allocated); + int local_reserve; + + preempt_disable(); + local_reserve = __this_cpu_sub_return(*sk->sk_prot->per_cpu_fw_alloc, amt); + if (local_reserve <= -SK_MEMORY_PCPU_RESERVE) { + __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); + atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); + } + preempt_enable(); } #define SK_ALLOC_PERCPU_COUNTER_BATCH 16 @@ -1441,12 +1467,6 @@ proto_sockets_allocated_sum_positive(struct proto *prot) return percpu_counter_sum_positive(prot->sockets_allocated); } -static inline long -proto_memory_allocated(struct proto *prot) -{ - return atomic_long_read(prot->memory_allocated); -} - static inline bool proto_memory_pressure(struct proto *prot) { -- cgit v1.2.3 From 7c80b038d23e1f4c7fcc311f43f83b8c60e7fb80 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:10 -0700 Subject: net: fix sk_wmem_schedule() and sk_rmem_schedule() errors If sk->sk_forward_alloc is 150000, and we need to schedule 150001 bytes, we want to allocate 1 byte more (rounded up to one page), instead of 150001 :/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 59040fee74e7..cf288f7e9019 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1575,19 +1575,23 @@ static inline bool sk_has_account(struct sock *sk) static inline bool sk_wmem_schedule(struct sock *sk, int size) { + int delta; + if (!sk_has_account(sk)) return true; - return size <= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_SEND); + delta = size - sk->sk_forward_alloc; + return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_SEND); } static inline bool sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, int size) { + int delta; + if (!sk_has_account(sk)) return true; - return size <= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_RECV) || + delta = size - sk->sk_forward_alloc; + return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_RECV) || skb_pfmemalloc(skb); } -- cgit v1.2.3 From 4890b686f4088c90432149bd6de567e621266fa2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:11 -0700 Subject: net: keep sk->sk_forward_alloc as small as possible Currently, tcp_memory_allocated can hit tcp_mem[] limits quite fast. Each TCP socket can forward allocate up to 2 MB of memory, even after flow became less active. 10,000 sockets can have reserved 20 GB of memory, and we have no shrinker in place to reclaim that. Instead of trying to reclaim the extra allocations in some places, just keep sk->sk_forward_alloc values as small as possible. This should not impact performance too much now we have per-cpu reserves: Changes to tcp_memory_allocated should not be too frequent. For sockets not using SO_RESERVE_MEM: - idle sockets (no packets in tx/rx queues) have zero forward alloc. - non idle sockets have a forward alloc smaller than one page. Note: - Removal of SK_RECLAIM_CHUNK and SK_RECLAIM_THRESHOLD is left to MPTCP maintainers as a follow up. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 29 ++--------------------------- net/core/datagram.c | 3 --- net/ipv4/tcp.c | 7 ------- net/ipv4/tcp_input.c | 4 ---- net/ipv4/tcp_timer.c | 19 ++++--------------- net/iucv/af_iucv.c | 2 -- net/mptcp/protocol.c | 2 +- net/sctp/sm_statefuns.c | 2 -- net/sctp/socket.c | 5 ----- net/sctp/stream_interleave.c | 2 -- net/sctp/ulpqueue.c | 4 ---- 11 files changed, 7 insertions(+), 72 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index cf288f7e9019..0063e8410a4e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1627,19 +1627,6 @@ static inline void sk_mem_reclaim_final(struct sock *sk) sk_mem_reclaim(sk); } -static inline void sk_mem_reclaim_partial(struct sock *sk) -{ - int reclaimable; - - if (!sk_has_account(sk)) - return; - - reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - - if (reclaimable > (int)PAGE_SIZE) - __sk_mem_reclaim(sk, reclaimable - 1); -} - static inline void sk_mem_charge(struct sock *sk, int size) { if (!sk_has_account(sk)) @@ -1647,29 +1634,17 @@ static inline void sk_mem_charge(struct sock *sk, int size) sk->sk_forward_alloc -= size; } -/* the following macros control memory reclaiming in sk_mem_uncharge() +/* the following macros control memory reclaiming in mptcp_rmem_uncharge() */ #define SK_RECLAIM_THRESHOLD (1 << 21) #define SK_RECLAIM_CHUNK (1 << 20) static inline void sk_mem_uncharge(struct sock *sk, int size) { - int reclaimable; - if (!sk_has_account(sk)) return; sk->sk_forward_alloc += size; - reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - - /* Avoid a possible overflow. - * TCP send queues can make this happen, if sk_mem_reclaim() - * is not called and more than 2 GBytes are released at once. - * - * If we reach 2 MBytes, reclaim 1 MBytes right now, there is - * no need to hold that much forward allocation anyway. - */ - if (unlikely(reclaimable >= SK_RECLAIM_THRESHOLD)) - __sk_mem_reclaim(sk, SK_RECLAIM_CHUNK); + sk_mem_reclaim(sk); } /* diff --git a/net/core/datagram.c b/net/core/datagram.c index 50f4faeea76c..35791f86bd1a 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -320,7 +320,6 @@ EXPORT_SYMBOL(skb_recv_datagram); void skb_free_datagram(struct sock *sk, struct sk_buff *skb) { consume_skb(skb); - sk_mem_reclaim_partial(sk); } EXPORT_SYMBOL(skb_free_datagram); @@ -336,7 +335,6 @@ void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len) slow = lock_sock_fast(sk); sk_peek_offset_bwd(sk, len); skb_orphan(skb); - sk_mem_reclaim_partial(sk); unlock_sock_fast(sk, slow); /* skb is now orphaned, can be freed outside of locked section */ @@ -396,7 +394,6 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) NULL); kfree_skb(skb); - sk_mem_reclaim_partial(sk); return err; } EXPORT_SYMBOL(skb_kill_datagram); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e6bdf8e2c09a..14ebb4ec4a51 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -858,9 +858,6 @@ struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, { struct sk_buff *skb; - if (unlikely(tcp_under_memory_pressure(sk))) - sk_mem_reclaim_partial(sk); - skb = alloc_skb_fclone(size + MAX_TCP_HEADER, gfp); if (likely(skb)) { bool mem_scheduled; @@ -2764,8 +2761,6 @@ void __tcp_close(struct sock *sk, long timeout) __kfree_skb(skb); } - sk_mem_reclaim(sk); - /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ if (sk->sk_state == TCP_CLOSE) goto adjudge_to_death; @@ -2873,7 +2868,6 @@ adjudge_to_death: } } if (sk->sk_state != TCP_CLOSE) { - sk_mem_reclaim(sk); if (tcp_check_oom(sk, 0)) { tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_ATOMIC); @@ -2951,7 +2945,6 @@ void tcp_write_queue_purge(struct sock *sk) } tcp_rtx_queue_purge(sk); INIT_LIST_HEAD(&tcp_sk(sk)->tsorted_sent_queue); - sk_mem_reclaim(sk); tcp_clear_all_retrans_hints(tcp_sk(sk)); tcp_sk(sk)->packets_out = 0; inet_csk(sk)->icsk_backoff = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3fb117022558..fdc7beb81b68 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -805,7 +805,6 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) * restart window, so that we send ACKs quickly. */ tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); - sk_mem_reclaim(sk); } } icsk->icsk_ack.lrcvtime = now; @@ -4390,7 +4389,6 @@ void tcp_fin(struct sock *sk) skb_rbtree_purge(&tp->out_of_order_queue); if (tcp_is_sack(tp)) tcp_sack_reset(&tp->rx_opt); - sk_mem_reclaim(sk); if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); @@ -5336,7 +5334,6 @@ static bool tcp_prune_ofo_queue(struct sock *sk) tcp_drop_reason(sk, rb_to_skb(node), SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE); if (!prev || goal <= 0) { - sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !tcp_under_memory_pressure(sk)) break; @@ -5383,7 +5380,6 @@ static int tcp_prune_queue(struct sock *sk) skb_peek(&sk->sk_receive_queue), NULL, tp->copied_seq, tp->rcv_nxt); - sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) return 0; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 20cf4a98c69d..2208755e8efc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -290,15 +290,13 @@ void tcp_delack_timer_handler(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); - sk_mem_reclaim_partial(sk); - if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) - goto out; + return; if (time_after(icsk->icsk_ack.timeout, jiffies)) { sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); - goto out; + return; } icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER; @@ -317,10 +315,6 @@ void tcp_delack_timer_handler(struct sock *sk) tcp_send_ack(sk); __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); } - -out: - if (tcp_under_memory_pressure(sk)) - sk_mem_reclaim(sk); } @@ -600,11 +594,11 @@ void tcp_write_timer_handler(struct sock *sk) if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || !icsk->icsk_pending) - goto out; + return; if (time_after(icsk->icsk_timeout, jiffies)) { sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); - goto out; + return; } tcp_mstamp_refresh(tcp_sk(sk)); @@ -626,9 +620,6 @@ void tcp_write_timer_handler(struct sock *sk) tcp_probe_timer(sk); break; } - -out: - sk_mem_reclaim(sk); } static void tcp_write_timer(struct timer_list *t) @@ -743,8 +734,6 @@ static void tcp_keepalive_timer (struct timer_list *t) elapsed = keepalive_time_when(tp) - elapsed; } - sk_mem_reclaim(sk); - resched: inet_csk_reset_keepalive_timer (sk, elapsed); goto out; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index a0385ddbffcf..498a0c35b7bb 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -278,8 +278,6 @@ static void iucv_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_error_queue); - sk_mem_reclaim(sk); - if (!sock_flag(sk, SOCK_DEAD)) { pr_err("Attempt to release alive iucv socket %p\n", sk); return; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 9563124ac8af..e0fb9f96c45c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -975,7 +975,7 @@ static void __mptcp_mem_reclaim_partial(struct sock *sk) if (reclaimable > (int)PAGE_SIZE) __mptcp_rmem_reclaim(sk, reclaimable - 1); - sk_mem_reclaim_partial(sk); + sk_mem_reclaim(sk); } static void mptcp_mem_reclaim_partial(struct sock *sk) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 52edee1322fc..f6ee7f4040c1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -6590,8 +6590,6 @@ static int sctp_eat_data(const struct sctp_association *asoc, pr_debug("%s: under pressure, reneging for tsn:%u\n", __func__, tsn); deliver = SCTP_CMD_RENEGE; - } else { - sk_mem_reclaim(sk); } } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 05174acd981a..171f1a35d205 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1824,9 +1824,6 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, if (sctp_wspace(asoc) < (int)msg_len) sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); - if (sk_under_memory_pressure(sk)) - sk_mem_reclaim(sk); - if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) { timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); @@ -9195,8 +9192,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, goto do_error; if (signal_pending(current)) goto do_interrupted; - if (sk_under_memory_pressure(sk)) - sk_mem_reclaim(sk); if ((int)msg_len <= sctp_wspace(asoc) && sk_wmem_schedule(sk, msg_len)) break; diff --git a/net/sctp/stream_interleave.c b/net/sctp/stream_interleave.c index 6b13f737ebf2..bb22b71df7a3 100644 --- a/net/sctp/stream_interleave.c +++ b/net/sctp/stream_interleave.c @@ -979,8 +979,6 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0) sctp_intl_start_pd(ulpq, gfp); - - sk_mem_reclaim(asoc->base.sk); } static void sctp_intl_stream_abort_pd(struct sctp_ulpq *ulpq, __u16 sid, diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 407fed46931b..0a8510a0c5e6 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -1100,12 +1100,8 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, else if (retval == 1) sctp_ulpq_reasm_drain(ulpq); } - - sk_mem_reclaim(asoc->base.sk); } - - /* Notify the application if an association is aborted and in * partial delivery mode. Send up any pending received messages. */ -- cgit v1.2.3 From 219160be496f7f9cd105c5708e37cf22ab4ce0c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Jun 2022 20:30:16 -0700 Subject: tcp: sk_forced_mem_schedule() optimization sk_memory_allocated_add() has three callers, and returns to them @memory_allocated. sk_forced_mem_schedule() is one of them, and ignores the returned value. Change sk_memory_allocated_add() to return void. Change sock_reserve_memory() and __sk_mem_raise_allocated() to call sk_memory_allocated(). This removes one cache line miss [1] for RPC workloads, as first skbs in TCP write queue and receive queue go through sk_forced_mem_schedule(). [1] Cache line holding tcp_memory_allocated. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller --- include/net/sock.h | 3 +-- net/core/sock.c | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 0063e8410a4e..304a5e39d41e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1412,7 +1412,7 @@ sk_memory_allocated(const struct sock *sk) /* 1 MB per cpu, in page units */ #define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT)) -static inline long +static inline void sk_memory_allocated_add(struct sock *sk, int amt) { int local_reserve; @@ -1424,7 +1424,6 @@ sk_memory_allocated_add(struct sock *sk, int amt) atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); } preempt_enable(); - return sk_memory_allocated(sk); } static inline void diff --git a/net/core/sock.c b/net/core/sock.c index 697d5c8e2f0d..92a0296ccb18 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1019,7 +1019,8 @@ static int sock_reserve_memory(struct sock *sk, int bytes) return -ENOMEM; /* pre-charge to forward_alloc */ - allocated = sk_memory_allocated_add(sk, pages); + sk_memory_allocated_add(sk, pages); + allocated = sk_memory_allocated(sk); /* If the system goes into memory pressure with this * precharge, give up and return error. */ @@ -2906,11 +2907,13 @@ EXPORT_SYMBOL(sk_wait_data); */ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) { - struct proto *prot = sk->sk_prot; - long allocated = sk_memory_allocated_add(sk, amt); bool memcg_charge = mem_cgroup_sockets_enabled && sk->sk_memcg; + struct proto *prot = sk->sk_prot; bool charged = true; + long allocated; + sk_memory_allocated_add(sk, amt); + allocated = sk_memory_allocated(sk); if (memcg_charge && !(charged = mem_cgroup_charge_skmem(sk->sk_memcg, amt, gfp_memcg_charge()))) -- cgit v1.2.3 From 33bf9885040c399cf6a95bd33216644126728e14 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Wed, 15 Jun 2022 16:48:44 +0300 Subject: bpf: Add helpers to issue and check SYN cookies in XDP The new helpers bpf_tcp_raw_{gen,check}_syncookie_ipv{4,6} allow an XDP program to generate SYN cookies in response to TCP SYN packets and to check those cookies upon receiving the first ACK packet (the final packet of the TCP handshake). Unlike bpf_tcp_{gen,check}_syncookie these new helpers don't need a listening socket on the local machine, which allows to use them together with synproxy to accelerate SYN cookie generation. Signed-off-by: Maxim Mikityanskiy Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/r/20220615134847.3753567-4-maximmi@nvidia.com Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 1 + include/uapi/linux/bpf.h | 78 +++++++++++++++++++++++++++ net/core/filter.c | 118 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_input.c | 3 +- scripts/bpf_doc.py | 4 ++ tools/include/uapi/linux/bpf.h | 78 +++++++++++++++++++++++++++ 6 files changed, 281 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 1e99f5c61f84..9a1efe23fab7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -432,6 +432,7 @@ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph, struct tcphdr *th, u32 *cookie); u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph, struct tcphdr *th, u32 *cookie); +u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss); u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops, const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct tcphdr *th); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f545e39df72a..e81362891596 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5251,6 +5251,80 @@ union bpf_attr { * Pointer to the underlying dynptr data, NULL if the dynptr is * read-only, if the dynptr is invalid, or if the offset and length * is out of bounds. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv4/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv6/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. + * + * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5457,6 +5531,10 @@ union bpf_attr { FN(dynptr_read), \ FN(dynptr_write), \ FN(dynptr_data), \ + FN(tcp_raw_gen_syncookie_ipv4), \ + FN(tcp_raw_gen_syncookie_ipv6), \ + FN(tcp_raw_check_syncookie_ipv4), \ + FN(tcp_raw_check_syncookie_ipv6), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index 5af58eb48587..b62d4126a561 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7444,6 +7444,114 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = { .arg3_type = ARG_ANYTHING, }; +#ifdef CONFIG_SYN_COOKIES +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv4, struct iphdr *, iph, + struct tcphdr *, th, u32, th_len) +{ + u32 cookie; + u16 mss; + + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4)) + return -EINVAL; + + mss = tcp_parse_mss_option(th, 0) ?: TCP_MSS_DEFAULT; + cookie = __cookie_v4_init_sequence(iph, th, &mss); + + return cookie | ((u64)mss << 32); +} + +static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = { + .func = bpf_tcp_raw_gen_syncookie_ipv4, + .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct iphdr), + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, +}; + +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph, + struct tcphdr *, th, u32, th_len) +{ +#if IS_BUILTIN(CONFIG_IPV6) + const u16 mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr); + u32 cookie; + u16 mss; + + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4)) + return -EINVAL; + + mss = tcp_parse_mss_option(th, 0) ?: mss_clamp; + cookie = __cookie_v6_init_sequence(iph, th, &mss); + + return cookie | ((u64)mss << 32); +#else + return -EPROTONOSUPPORT; +#endif +} + +static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = { + .func = bpf_tcp_raw_gen_syncookie_ipv6, + .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct ipv6hdr), + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, +}; + +BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph, + struct tcphdr *, th) +{ + u32 cookie = ntohl(th->ack_seq) - 1; + + if (__cookie_v4_check(iph, th, cookie) > 0) + return 0; + + return -EACCES; +} + +static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = { + .func = bpf_tcp_raw_check_syncookie_ipv4, + .gpl_only = true, /* __cookie_v4_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct iphdr), + .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg2_size = sizeof(struct tcphdr), +}; + +BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv6, struct ipv6hdr *, iph, + struct tcphdr *, th) +{ +#if IS_BUILTIN(CONFIG_IPV6) + u32 cookie = ntohl(th->ack_seq) - 1; + + if (__cookie_v6_check(iph, th, cookie) > 0) + return 0; + + return -EACCES; +#else + return -EPROTONOSUPPORT; +#endif +} + +static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + .func = bpf_tcp_raw_check_syncookie_ipv6, + .gpl_only = true, /* __cookie_v6_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct ipv6hdr), + .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg2_size = sizeof(struct tcphdr), +}; +#endif /* CONFIG_SYN_COOKIES */ + #endif /* CONFIG_INET */ bool bpf_helper_changes_pkt_data(void *func) @@ -7856,6 +7964,16 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_check_syncookie_proto; case BPF_FUNC_tcp_gen_syncookie: return &bpf_tcp_gen_syncookie_proto; +#ifdef CONFIG_SYN_COOKIES + case BPF_FUNC_tcp_raw_gen_syncookie_ipv4: + return &bpf_tcp_raw_gen_syncookie_ipv4_proto; + case BPF_FUNC_tcp_raw_gen_syncookie_ipv6: + return &bpf_tcp_raw_gen_syncookie_ipv6_proto; + case BPF_FUNC_tcp_raw_check_syncookie_ipv4: + return &bpf_tcp_raw_check_syncookie_ipv4_proto; + case BPF_FUNC_tcp_raw_check_syncookie_ipv6: + return &bpf_tcp_raw_check_syncookie_ipv6_proto; +#endif #endif default: return bpf_sk_base_func_proto(func_id); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2e2a9ece9af2..6426f6a2e744 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3967,7 +3967,7 @@ static bool smc_parse_options(const struct tcphdr *th, /* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped * value on success. */ -static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) +u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) { const unsigned char *ptr = (const unsigned char *)(th + 1); int length = (th->doff * 4) - sizeof(struct tcphdr); @@ -4006,6 +4006,7 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) } return mss; } +EXPORT_SYMBOL_GPL(tcp_parse_mss_option); /* Look for tcp options. Normally only called on SYN and SYNACK packets. * But, this can also be called on packets in the established flow when diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 855b937e7585..a0ec321469bd 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -635,6 +635,8 @@ class PrinterHelpers(Printer): 'struct bpf_timer', 'struct mptcp_sock', 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', ] known_types = { '...', @@ -686,6 +688,8 @@ class PrinterHelpers(Printer): 'struct bpf_timer', 'struct mptcp_sock', 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', } mapped_types = { 'u8': '__u8', diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f545e39df72a..e81362891596 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5251,6 +5251,80 @@ union bpf_attr { * Pointer to the underlying dynptr data, NULL if the dynptr is * read-only, if the dynptr is invalid, or if the offset and length * is out of bounds. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv4/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv6/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. + * + * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5457,6 +5531,10 @@ union bpf_attr { FN(dynptr_read), \ FN(dynptr_write), \ FN(dynptr_data), \ + FN(tcp_raw_gen_syncookie_ipv4), \ + FN(tcp_raw_gen_syncookie_ipv6), \ + FN(tcp_raw_check_syncookie_ipv4), \ + FN(tcp_raw_check_syncookie_ipv6), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit v1.2.3 From ba44f8182ec299c5d1c8a72fc0fde4ec127b5a6d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Jun 2022 20:47:04 -0700 Subject: raw: use more conventional iterators In order to prepare the following patch, I change raw v4 & v6 code to use more conventional iterators. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/raw.h | 5 +-- include/net/rawv6.h | 6 +-- net/ipv4/raw.c | 93 +++++++++++++++++----------------------------- net/ipv4/raw_diag.c | 33 ++++++++--------- net/ipv6/raw.c | 105 +++++++++++++++++++--------------------------------- 5 files changed, 92 insertions(+), 150 deletions(-) (limited to 'include/net') diff --git a/include/net/raw.h b/include/net/raw.h index 8ad8df594853..719d3556fc0a 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -20,9 +20,8 @@ extern struct proto raw_prot; extern struct raw_hashinfo raw_v4_hashinfo; -struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, - unsigned short num, __be32 raddr, - __be32 laddr, int dif, int sdif); +bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num, + __be32 raddr, __be32 laddr, int dif, int sdif); int raw_abort(struct sock *sk, int err); void raw_icmp_error(struct sk_buff *, int, u32); diff --git a/include/net/rawv6.h b/include/net/rawv6.h index 53d86b6055e8..c48c1298699a 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h @@ -5,9 +5,9 @@ #include extern struct raw_hashinfo raw_v6_hashinfo; -struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, const struct in6_addr *loc_addr, - const struct in6_addr *rmt_addr, int dif, int sdif); +bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, + const struct in6_addr *loc_addr, + const struct in6_addr *rmt_addr, int dif, int sdif); int raw_abort(struct sock *sk, int err); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index bbd717805b10..05e0de4a7c7f 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -117,24 +117,19 @@ void raw_unhash_sk(struct sock *sk) } EXPORT_SYMBOL_GPL(raw_unhash_sk); -struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, - unsigned short num, __be32 raddr, __be32 laddr, - int dif, int sdif) +bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num, + __be32 raddr, __be32 laddr, int dif, int sdif) { - sk_for_each_from(sk) { - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && inet->inet_num == num && - !(inet->inet_daddr && inet->inet_daddr != raddr) && - !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && - raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) - goto found; /* gotcha */ - } - sk = NULL; -found: - return sk; + struct inet_sock *inet = inet_sk(sk); + + if (net_eq(sock_net(sk), net) && inet->inet_num == num && + !(inet->inet_daddr && inet->inet_daddr != raddr) && + !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && + raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) + return true; + return false; } -EXPORT_SYMBOL_GPL(__raw_v4_lookup); +EXPORT_SYMBOL_GPL(raw_v4_match); /* * 0 - deliver @@ -168,23 +163,21 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) */ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) { + struct net *net = dev_net(skb->dev); int sdif = inet_sdif(skb); int dif = inet_iif(skb); - struct sock *sk; struct hlist_head *head; int delivered = 0; - struct net *net; + struct sock *sk; - read_lock(&raw_v4_hashinfo.lock); head = &raw_v4_hashinfo.ht[hash]; if (hlist_empty(head)) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, - iph->saddr, iph->daddr, dif, sdif); - - while (sk) { + return 0; + read_lock(&raw_v4_hashinfo.lock); + sk_for_each(sk, head) { + if (!raw_v4_match(net, sk, iph->protocol, + iph->saddr, iph->daddr, dif, sdif)) + continue; delivered = 1; if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && ip_mc_sf_allow(sk, iph->daddr, iph->saddr, @@ -195,31 +188,16 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) if (clone) raw_rcv(sk, clone); } - sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, - iph->saddr, iph->daddr, - dif, sdif); } -out: read_unlock(&raw_v4_hashinfo.lock); return delivered; } int raw_local_deliver(struct sk_buff *skb, int protocol) { - int hash; - struct sock *raw_sk; - - hash = protocol & (RAW_HTABLE_SIZE - 1); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - - /* If there maybe a raw socket we must check - if not we - * don't care less - */ - if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash)) - raw_sk = NULL; - - return raw_sk != NULL; + int hash = protocol & (RAW_HTABLE_SIZE - 1); + return raw_v4_input(skb, ip_hdr(skb), hash); } static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) @@ -286,29 +264,24 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) { - int hash; - struct sock *raw_sk; + struct net *net = dev_net(skb->dev);; + int dif = skb->dev->ifindex; + int sdif = inet_sdif(skb); + struct hlist_head *head; const struct iphdr *iph; - struct net *net; + struct sock *sk; + int hash; hash = protocol & (RAW_HTABLE_SIZE - 1); + head = &raw_v4_hashinfo.ht[hash]; read_lock(&raw_v4_hashinfo.lock); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - if (raw_sk) { - int dif = skb->dev->ifindex; - int sdif = inet_sdif(skb); - + sk_for_each(sk, head) { iph = (const struct iphdr *)skb->data; - net = dev_net(skb->dev); - - while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, - iph->daddr, iph->saddr, - dif, sdif)) != NULL) { - raw_err(raw_sk, skb, info); - raw_sk = sk_next(raw_sk); - iph = (const struct iphdr *)skb->data; - } + if (!raw_v4_match(net, sk, iph->protocol, + iph->saddr, iph->daddr, dif, sdif)) + continue; + raw_err(sk, skb, info); } read_unlock(&raw_v4_hashinfo.lock); } diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index ccacbde30a2c..b6d92dc7b051 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -34,31 +34,30 @@ raw_get_hashinfo(const struct inet_diag_req_v2 *r) * use helper to figure it out. */ -static struct sock *raw_lookup(struct net *net, struct sock *from, - const struct inet_diag_req_v2 *req) +static bool raw_lookup(struct net *net, struct sock *sk, + const struct inet_diag_req_v2 *req) { struct inet_diag_req_raw *r = (void *)req; - struct sock *sk = NULL; if (r->sdiag_family == AF_INET) - sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol, - r->id.idiag_dst[0], - r->id.idiag_src[0], - r->id.idiag_if, 0); + return raw_v4_match(net, sk, r->sdiag_raw_protocol, + r->id.idiag_dst[0], + r->id.idiag_src[0], + r->id.idiag_if, 0); #if IS_ENABLED(CONFIG_IPV6) else - sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol, - (const struct in6_addr *)r->id.idiag_src, - (const struct in6_addr *)r->id.idiag_dst, - r->id.idiag_if, 0); + return raw_v6_match(net, sk, r->sdiag_raw_protocol, + (const struct in6_addr *)r->id.idiag_src, + (const struct in6_addr *)r->id.idiag_dst, + r->id.idiag_if, 0); #endif - return sk; + return false; } static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) { struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); - struct sock *sk = NULL, *s; + struct sock *sk; int slot; if (IS_ERR(hashinfo)) @@ -66,9 +65,8 @@ static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 read_lock(&hashinfo->lock); for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { - sk_for_each(s, &hashinfo->ht[slot]) { - sk = raw_lookup(net, s, r); - if (sk) { + sk_for_each(sk, &hashinfo->ht[slot]) { + if (raw_lookup(net, sk, r)) { /* * Grab it and keep until we fill * diag meaage to be reported, so @@ -81,10 +79,11 @@ static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 } } } + sk = ERR_PTR(-ENOENT); out_unlock: read_unlock(&hashinfo->lock); - return sk ? sk : ERR_PTR(-ENOENT); + return sk; } static int raw_diag_dump_one(struct netlink_callback *cb, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3b7cbd522b54..c0f2e3475984 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -66,41 +66,27 @@ struct raw_hashinfo raw_v6_hashinfo = { }; EXPORT_SYMBOL_GPL(raw_v6_hashinfo); -struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, const struct in6_addr *loc_addr, - const struct in6_addr *rmt_addr, int dif, int sdif) +bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, + const struct in6_addr *loc_addr, + const struct in6_addr *rmt_addr, int dif, int sdif) { - bool is_multicast = ipv6_addr_is_multicast(loc_addr); - - sk_for_each_from(sk) - if (inet_sk(sk)->inet_num == num) { - - if (!net_eq(sock_net(sk), net)) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_daddr) && - !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) - continue; - - if (!raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, - dif, sdif)) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) - goto found; - if (is_multicast && - inet6_mc_check(sk, loc_addr, rmt_addr)) - goto found; - continue; - } - goto found; - } - sk = NULL; -found: - return sk; + if (inet_sk(sk)->inet_num != num || + !net_eq(sock_net(sk), net) || + (!ipv6_addr_any(&sk->sk_v6_daddr) && + !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || + !raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, + dif, sdif)) + return false; + + if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) || + ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr) || + (ipv6_addr_is_multicast(loc_addr) && + inet6_mc_check(sk, loc_addr, rmt_addr))) + return true; + + return false; } -EXPORT_SYMBOL_GPL(__raw_v6_lookup); +EXPORT_SYMBOL_GPL(raw_v6_match); /* * 0 - deliver @@ -156,31 +142,28 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); */ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { + struct net *net = dev_net(skb->dev); const struct in6_addr *saddr; const struct in6_addr *daddr; + struct hlist_head *head; struct sock *sk; bool delivered = false; __u8 hash; - struct net *net; saddr = &ipv6_hdr(skb)->saddr; daddr = saddr + 1; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - + head = &raw_v6_hashinfo.ht[hash]; + if (hlist_empty(head)) + return false; read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - - if (!sk) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, - inet6_iif(skb), inet6_sdif(skb)); - - while (sk) { + sk_for_each(sk, head) { int filtered; + if (!raw_v6_match(net, sk, nexthdr, daddr, saddr, + inet6_iif(skb), inet6_sdif(skb))) + continue; delivered = true; switch (nexthdr) { case IPPROTO_ICMPV6: @@ -219,23 +202,14 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) rawv6_rcv(sk, clone); } } - sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, - inet6_iif(skb), inet6_sdif(skb)); } -out: read_unlock(&raw_v6_hashinfo.lock); return delivered; } bool raw6_local_deliver(struct sk_buff *skb, int nexthdr) { - struct sock *raw_sk; - - raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]); - if (raw_sk && !ipv6_raw_deliver(skb, nexthdr)) - raw_sk = NULL; - - return raw_sk != NULL; + return ipv6_raw_deliver(skb, nexthdr); } /* This cleans up af_inet6 a bit. -DaveM */ @@ -361,28 +335,25 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, void raw6_icmp_error(struct sk_buff *skb, int nexthdr, u8 type, u8 code, int inner_offset, __be32 info) { + const struct in6_addr *saddr, *daddr; + struct net *net = dev_net(skb->dev); + struct hlist_head *head; struct sock *sk; int hash; - const struct in6_addr *saddr, *daddr; - struct net *net; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - + head = &raw_v6_hashinfo.ht[hash]; read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - if (sk) { + sk_for_each(sk, head) { /* Note: ipv6_hdr(skb) != skb->data */ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; saddr = &ip6h->saddr; daddr = &ip6h->daddr; - net = dev_net(skb->dev); - while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, - inet6_iif(skb), inet6_iif(skb)))) { - rawv6_err(sk, skb, NULL, type, code, - inner_offset, info); - sk = sk_next(sk); - } + if (!raw_v6_match(net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr, + inet6_iif(skb), inet6_iif(skb))) + continue; + rawv6_err(sk, skb, NULL, type, code, inner_offset, info); } read_unlock(&raw_v6_hashinfo.lock); } -- cgit v1.2.3 From 0daf07e527095e64ee8927ce297ab626643e9f51 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Jun 2022 20:47:05 -0700 Subject: raw: convert raw sockets to RCU Using rwlock in networking code is extremely risky. writers can starve if enough readers are constantly grabing the rwlock. I thought rwlock were at fault and sent this patch: https://lkml.org/lkml/2022/6/17/272 But Peter and Linus essentially told me rwlock had to be unfair. We need to get rid of rwlock in networking code. Without this fix, following script triggers soft lockups: for i in {1..48} do ping -f -n -q 127.0.0.1 & sleep 0.1 done Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/raw.h | 11 ++++++- include/net/rawv6.h | 1 + net/ipv4/af_inet.c | 2 ++ net/ipv4/raw.c | 83 ++++++++++++++++++++++++----------------------------- net/ipv4/raw_diag.c | 22 ++++++++------ net/ipv6/af_inet6.c | 3 ++ net/ipv6/raw.c | 28 +++++++++--------- 7 files changed, 80 insertions(+), 70 deletions(-) (limited to 'include/net') diff --git a/include/net/raw.h b/include/net/raw.h index 719d3556fc0a..d81eeeb8f1e6 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -33,9 +33,18 @@ int raw_rcv(struct sock *, struct sk_buff *); struct raw_hashinfo { rwlock_t lock; - struct hlist_head ht[RAW_HTABLE_SIZE]; + struct hlist_nulls_head ht[RAW_HTABLE_SIZE]; }; +static inline void raw_hashinfo_init(struct raw_hashinfo *hashinfo) +{ + int i; + + rwlock_init(&hashinfo->lock); + for (i = 0; i < RAW_HTABLE_SIZE; i++) + INIT_HLIST_NULLS_HEAD(&hashinfo->ht[i], i); +} + #ifdef CONFIG_PROC_FS int raw_proc_init(void); void raw_proc_exit(void); diff --git a/include/net/rawv6.h b/include/net/rawv6.h index c48c1298699a..bc70909625f6 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h @@ -3,6 +3,7 @@ #define _NET_RAWV6_H #include +#include extern struct raw_hashinfo raw_v6_hashinfo; bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 30e0e8992085..da81f56fdd1c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1929,6 +1929,8 @@ static int __init inet_init(void) sock_skb_cb_check_size(sizeof(struct inet_skb_parm)); + raw_hashinfo_init(&raw_v4_hashinfo); + rc = proto_register(&tcp_prot, 1); if (rc) goto out; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 05e0de4a7c7f..d28bf0b901a2 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -85,20 +85,19 @@ struct raw_frag_vec { int hlen; }; -struct raw_hashinfo raw_v4_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), -}; +struct raw_hashinfo raw_v4_hashinfo; EXPORT_SYMBOL_GPL(raw_v4_hashinfo); int raw_hash_sk(struct sock *sk) { struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; - struct hlist_head *head; + struct hlist_nulls_head *hlist; - head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; + hlist = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; write_lock_bh(&h->lock); - sk_add_node(sk, head); + hlist_nulls_add_head_rcu(&sk->sk_nulls_node, hlist); + sock_set_flag(sk, SOCK_RCU_FREE); write_unlock_bh(&h->lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); @@ -111,7 +110,7 @@ void raw_unhash_sk(struct sock *sk) struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; write_lock_bh(&h->lock); - if (sk_del_node_init(sk)) + if (__sk_nulls_del_node_init_rcu(sk)) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); write_unlock_bh(&h->lock); } @@ -164,17 +163,16 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) { struct net *net = dev_net(skb->dev); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int sdif = inet_sdif(skb); int dif = inet_iif(skb); - struct hlist_head *head; int delivered = 0; struct sock *sk; - head = &raw_v4_hashinfo.ht[hash]; - if (hlist_empty(head)) - return 0; - read_lock(&raw_v4_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v4_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (!raw_v4_match(net, sk, iph->protocol, iph->saddr, iph->daddr, dif, sdif)) continue; @@ -189,7 +187,7 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) raw_rcv(sk, clone); } } - read_unlock(&raw_v4_hashinfo.lock); + rcu_read_unlock(); return delivered; } @@ -265,25 +263,26 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) { struct net *net = dev_net(skb->dev);; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int dif = skb->dev->ifindex; int sdif = inet_sdif(skb); - struct hlist_head *head; const struct iphdr *iph; struct sock *sk; int hash; hash = protocol & (RAW_HTABLE_SIZE - 1); - head = &raw_v4_hashinfo.ht[hash]; + hlist = &raw_v4_hashinfo.ht[hash]; - read_lock(&raw_v4_hashinfo.lock); - sk_for_each(sk, head) { + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { iph = (const struct iphdr *)skb->data; if (!raw_v4_match(net, sk, iph->protocol, iph->saddr, iph->daddr, dif, sdif)) continue; raw_err(sk, skb, info); } - read_unlock(&raw_v4_hashinfo.lock); + rcu_read_unlock(); } static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) @@ -944,44 +943,41 @@ struct proto raw_prot = { }; #ifdef CONFIG_PROC_FS -static struct sock *raw_get_first(struct seq_file *seq) +static struct sock *raw_get_first(struct seq_file *seq, int bucket) { - struct sock *sk; struct raw_hashinfo *h = pde_data(file_inode(seq->file)); struct raw_iter_state *state = raw_seq_private(seq); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; + struct sock *sk; - for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE; + for (state->bucket = bucket; state->bucket < RAW_HTABLE_SIZE; ++state->bucket) { - sk_for_each(sk, &h->ht[state->bucket]) + hlist = &h->ht[state->bucket]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (sock_net(sk) == seq_file_net(seq)) - goto found; + return sk; + } } - sk = NULL; -found: - return sk; + return NULL; } static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); struct raw_iter_state *state = raw_seq_private(seq); do { - sk = sk_next(sk); -try_again: - ; + sk = sk_nulls_next(sk); } while (sk && sock_net(sk) != seq_file_net(seq)); - if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { - sk = sk_head(&h->ht[state->bucket]); - goto try_again; - } + if (!sk) + return raw_get_first(seq, state->bucket + 1); return sk; } static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) { - struct sock *sk = raw_get_first(seq); + struct sock *sk = raw_get_first(seq, 0); if (sk) while (pos && (sk = raw_get_next(seq, sk)) != NULL) @@ -990,11 +986,9 @@ static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) } void *raw_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(&h->lock) + __acquires(RCU) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); - - read_lock(&h->lock); + rcu_read_lock(); return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } EXPORT_SYMBOL_GPL(raw_seq_start); @@ -1004,7 +998,7 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) struct sock *sk; if (v == SEQ_START_TOKEN) - sk = raw_get_first(seq); + sk = raw_get_first(seq, 0); else sk = raw_get_next(seq, v); ++*pos; @@ -1013,11 +1007,9 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) EXPORT_SYMBOL_GPL(raw_seq_next); void raw_seq_stop(struct seq_file *seq, void *v) - __releases(&h->lock) + __releases(RCU) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); - - read_unlock(&h->lock); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(raw_seq_stop); @@ -1079,6 +1071,7 @@ static __net_initdata struct pernet_operations raw_net_ops = { int __init raw_proc_init(void) { + return register_pernet_subsys(&raw_net_ops); } diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index b6d92dc7b051..5f208e840d85 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -57,31 +57,32 @@ static bool raw_lookup(struct net *net, struct sock *sk, static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) { struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; struct sock *sk; int slot; if (IS_ERR(hashinfo)) return ERR_CAST(hashinfo); - read_lock(&hashinfo->lock); + rcu_read_lock(); for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { - sk_for_each(sk, &hashinfo->ht[slot]) { + hlist = &hashinfo->ht[slot]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (raw_lookup(net, sk, r)) { /* * Grab it and keep until we fill - * diag meaage to be reported, so + * diag message to be reported, so * caller should call sock_put then. - * We can do that because we're keeping - * hashinfo->lock here. */ - sock_hold(sk); - goto out_unlock; + if (refcount_inc_not_zero(&sk->sk_refcnt)) + goto out_unlock; } } } sk = ERR_PTR(-ENOENT); out_unlock: - read_unlock(&hashinfo->lock); + rcu_read_unlock(); return sk; } @@ -141,6 +142,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); struct net *net = sock_net(skb->sk); struct inet_diag_dump_data *cb_data; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int num, s_num, slot, s_slot; struct sock *sk = NULL; struct nlattr *bc; @@ -157,7 +160,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { num = 0; - sk_for_each(sk, &hashinfo->ht[slot]) { + hlist = &hashinfo->ht[slot]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { struct inet_sock *inet = inet_sk(sk); if (!net_eq(sock_net(sk), net)) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 70564ddccc46..658823e91eca 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -1073,6 +1074,8 @@ static int __init inet6_init(void) goto out; } + raw_hashinfo_init(&raw_v6_hashinfo); + err = proto_register(&tcpv6_prot, 1); if (err) goto out; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c0f2e3475984..f6119998700e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -61,9 +61,7 @@ #define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */ -struct raw_hashinfo raw_v6_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock), -}; +struct raw_hashinfo raw_v6_hashinfo; EXPORT_SYMBOL_GPL(raw_v6_hashinfo); bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, @@ -143,9 +141,10 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct net *net = dev_net(skb->dev); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; const struct in6_addr *saddr; const struct in6_addr *daddr; - struct hlist_head *head; struct sock *sk; bool delivered = false; __u8 hash; @@ -154,11 +153,9 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) daddr = saddr + 1; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - head = &raw_v6_hashinfo.ht[hash]; - if (hlist_empty(head)) - return false; - read_lock(&raw_v6_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v6_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { int filtered; if (!raw_v6_match(net, sk, nexthdr, daddr, saddr, @@ -203,7 +200,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) } } } - read_unlock(&raw_v6_hashinfo.lock); + rcu_read_unlock(); return delivered; } @@ -337,14 +334,15 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, { const struct in6_addr *saddr, *daddr; struct net *net = dev_net(skb->dev); - struct hlist_head *head; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; struct sock *sk; int hash; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - head = &raw_v6_hashinfo.ht[hash]; - read_lock(&raw_v6_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v6_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { /* Note: ipv6_hdr(skb) != skb->data */ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; saddr = &ip6h->saddr; @@ -355,7 +353,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, continue; rawv6_err(sk, skb, NULL, type, code, inner_offset, info); } - read_unlock(&raw_v6_hashinfo.lock); + rcu_read_unlock(); } static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb) -- cgit v1.2.3 From 7b0a0e3c3a88260b6fcb017e49f198463aa62ed1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Apr 2022 16:50:57 +0200 Subject: wifi: cfg80211: do some rework towards MLO link APIs In order to support multi-link operation with multiple links, start adding some APIs. The notable addition here is to have the link ID in a new nl80211 attribute, that will be used to differentiate the links in many nl80211 operations. So far, this patch adds the netlink NL80211_ATTR_MLO_LINK_ID attribute (as well as the NL80211_ATTR_MLO_LINKS attribute) and plugs it through the system in some places, checking the validity etc. along with other infrastructure needed for it. For now, I've decided to include only the over-the-air link ID in the API. I know we discussed that we eventually need to have to have other ways of identifying a link, but for local AP mode and auth/assoc commands as well as set_key etc. we'll use the OTA ID. Also included in this patch is some refactoring of the data structures in struct wireless_dev, splitting for the first time the data into type dependent pieces, to make reasoning about these things easier. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 +- drivers/net/wireless/ath/wil6210/cfg80211.c | 9 +- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +- drivers/net/wireless/marvell/libertas/mesh.c | 10 +- drivers/net/wireless/marvell/mwifiex/11h.c | 2 +- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 18 +- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 3 +- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 14 +- drivers/net/wireless/quantenna/qtnfmac/commands.c | 2 +- drivers/net/wireless/quantenna/qtnfmac/event.c | 15 +- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 4 +- include/linux/ieee80211.h | 3 + include/net/cfg80211.h | 99 +++- include/uapi/linux/nl80211.h | 28 + net/mac80211/cfg.c | 8 +- net/mac80211/mlme.c | 2 +- net/wireless/ap.c | 46 +- net/wireless/chan.c | 196 +++++-- net/wireless/core.c | 28 +- net/wireless/core.h | 13 +- net/wireless/ibss.c | 57 +- net/wireless/mesh.c | 31 +- net/wireless/mlme.c | 74 +-- net/wireless/nl80211.c | 623 +++++++++++++++------ net/wireless/ocb.c | 5 +- net/wireless/rdev-ops.h | 32 +- net/wireless/reg.c | 139 +++-- net/wireless/scan.c | 8 +- net/wireless/sme.c | 102 ++-- net/wireless/trace.h | 86 ++- net/wireless/util.c | 44 +- net/wireless/wext-compat.c | 48 +- net/wireless/wext-sme.c | 29 +- 33 files changed, 1255 insertions(+), 533 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index bd1183830e91..33ed54738d47 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1119,7 +1119,7 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); mutex_lock(&vif->wdev.mtx); - cfg80211_ch_switch_notify(vif->ndev, &chandef); + cfg80211_ch_switch_notify(vif->ndev, &chandef, 0); mutex_unlock(&vif->wdev.mtx); } @@ -2967,7 +2967,8 @@ static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, return ath6kl_set_ies(vif, beacon); } -static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -3368,6 +3369,7 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *addr, const struct cfg80211_bitrate_mask *mask) { diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 8f2638f5b87b..f93bdffa4d1d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -2098,8 +2098,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, bcon->tail_len)) privacy = 1; - memcpy(vif->ssid, wdev->ssid, wdev->ssid_len); - vif->ssid_len = wdev->ssid_len; + memcpy(vif->ssid, wdev->u.ap.ssid, wdev->u.ap.ssid_len); + vif->ssid_len = wdev->u.ap.ssid_len; /* in case privacy has changed, need to restart the AP */ if (vif->privacy != privacy) { @@ -2108,7 +2108,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, privacy, - wdev->beacon_interval, + wdev->links[0].ap.beacon_interval, vif->channel, vif->wmi_edmg_channel, bcon, vif->hidden_ssid, @@ -2186,7 +2186,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, } static int wil_cfg80211_stop_ap(struct wiphy *wiphy, - struct net_device *ndev) + struct net_device *ndev, + unsigned int link_id) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(ndev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 605206abe424..11e1f07f83e0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -4965,7 +4965,8 @@ exit: return err; } -static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, + unsigned int link_id) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); @@ -5302,6 +5303,7 @@ exit: static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index a58c1e141f2c..90ffe8d1e0e8 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -109,9 +109,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, if (priv->mesh_dev) { mesh_wdev = priv->mesh_dev->ieee80211_ptr; - ie->val.mesh_id_len = mesh_wdev->mesh_id_up_len; - memcpy(ie->val.mesh_id, mesh_wdev->ssid, - mesh_wdev->mesh_id_up_len); + ie->val.mesh_id_len = mesh_wdev->u.mesh.id_up_len; + memcpy(ie->val.mesh_id, mesh_wdev->u.mesh.id, + mesh_wdev->u.mesh.id_up_len); } ie->len = sizeof(struct mrvl_meshie_val) - @@ -986,8 +986,8 @@ static int lbs_add_mesh(struct lbs_private *priv) mesh_wdev->wiphy = priv->wdev->wiphy; if (priv->mesh_tlv) { - sprintf(mesh_wdev->ssid, "mesh"); - mesh_wdev->mesh_id_up_len = 4; + sprintf(mesh_wdev->u.mesh.id, "mesh"); + mesh_wdev->u.mesh.id_up_len = 4; } mesh_wdev->netdev = mesh_dev; diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 3fa25cd64cda..4ca8d0135708 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -304,6 +304,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) mwifiex_dbg(priv->adapter, MSG, "indicating channel switch completion to kernel\n"); mutex_lock(&priv->wdev.mtx); - cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); mutex_unlock(&priv->wdev.mtx); } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 6f23ec34e2e2..d68c40e0e122 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1753,10 +1753,12 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = { * Function configures data rates to firmware using bitrate mask * provided by cfg80211. */ -static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, - struct net_device *dev, - const u8 *peer, - const struct cfg80211_bitrate_mask *mask) +static int +mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; @@ -1998,7 +2000,8 @@ mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) /* cfg80211 operation handler for stop ap. * Function stops BSS running at uAP interface. */ -static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); @@ -2421,7 +2424,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - if (priv->wdev.current_bss) { + if (priv->wdev.connected) { mwifiex_dbg(adapter, ERROR, "%s: already connected\n", dev->name); return -EALREADY; @@ -2649,7 +2652,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } - if (!priv->wdev.current_bss && priv->scan_block) + if (!priv->wdev.connected && priv->scan_block) priv->scan_block = false; if (!mwifiex_stop_bg_scan(priv)) @@ -4025,6 +4028,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 1ac4684fab25..5c2c7f1dbffd 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1426,7 +1426,8 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev, return wilc_add_beacon(vif, 0, 0, beacon); } -static int stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { int ret; struct wilc_vif *vif = netdev_priv(dev); diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 84b15a655eab..1593e810b3ca 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -352,7 +352,8 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); int ret; @@ -500,7 +501,7 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev, switch (vif->wdev.iftype) { case NL80211_IFTYPE_STATION: - if (idx != 0 || !vif->wdev.current_bss) + if (idx != 0 || !vif->wdev.connected) return -ENOENT; ether_addr_copy(mac, vif->bssid); @@ -729,7 +730,7 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, vif->vifid); - if (vif->wdev.current_bss) { + if (vif->wdev.connected) { netif_carrier_off(vif->netdev); cfg80211_disconnected(vif->netdev, reason_code, NULL, 0, true, GFP_KERNEL); @@ -745,10 +746,11 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, struct qtnf_wmac *mac = wiphy_priv(wiphy); struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_supported_band *sband; - const struct cfg80211_chan_def *chandef = &wdev->chandef; + const struct cfg80211_chan_def *chandef = wdev_chandef(wdev, 0); struct ieee80211_channel *chan; int ret; + sband = wiphy->bands[NL80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; @@ -765,7 +767,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, survey->channel = chan; survey->filled = 0x0; - if (chan == chandef->chan) + if (chandef && chan == chandef->chan) survey->filled = SURVEY_INFO_IN_USE; ret = qtnf_cmd_get_chan_stats(mac, chan->center_freq, survey); @@ -778,7 +780,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, static int qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, - struct cfg80211_chan_def *chandef) + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct net_device *ndev = wdev->netdev; struct qtnf_vif *vif; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c68563c83098..3d734a7a5ba8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2005,7 +2005,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) dwell_active = scan_req->duration; dwell_passive = scan_req->duration; } else if (wdev->iftype == NL80211_IFTYPE_STATION && - wdev->current_bss) { + wdev->connected) { /* let device select dwell based on traffic conditions */ dwell_active = QTNF_SCAN_TIME_AUTO; dwell_passive = QTNF_SCAN_TIME_AUTO; diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 8dc80574d08d..4fafe370101a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -189,7 +189,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, vif->mac->macid, vif->vifid, join_info->bssid, chandef.chan->hw_value); - if (!vif->wdev.ssid_len) { + if (!vif->wdev.u.client.ssid_len) { pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", vif->mac->macid, vif->vifid, join_info->bssid); @@ -197,7 +197,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, goto done; } - ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); + ie = kzalloc(2 + vif->wdev.u.client.ssid_len, GFP_KERNEL); if (!ie) { pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", vif->mac->macid, vif->vifid, @@ -207,14 +207,15 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, } ie[0] = WLAN_EID_SSID; - ie[1] = vif->wdev.ssid_len; - memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); + ie[1] = vif->wdev.u.client.ssid_len; + memcpy(ie + 2, vif->wdev.u.client.ssid, + vif->wdev.u.client.ssid_len); bss = cfg80211_inform_bss(wiphy, chandef.chan, CFG80211_BSS_FTYPE_UNKNOWN, join_info->bssid, 0, WLAN_CAPABILITY_ESS, 100, - ie, 2 + vif->wdev.ssid_len, + ie, 2 + vif->wdev.u.client.ssid_len, 0, GFP_KERNEL); if (!bss) { pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", @@ -470,14 +471,14 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac, continue; if (vif->wdev.iftype == NL80211_IFTYPE_STATION && - !vif->wdev.current_bss) + !vif->wdev.connected) continue; if (!vif->netdev) continue; mutex_lock(&vif->wdev.mtx); - cfg80211_ch_switch_notify(vif->netdev, &chandef); + cfg80211_ch_switch_notify(vif->netdev, &chandef, 0); mutex_unlock(&vif->wdev.mtx); } diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 43b5604c0bca..349aa3c4b668 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -2086,6 +2086,7 @@ static u8 rtw_get_chan_type(struct adapter *adapter) } static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct adapter *adapter = wiphy_to_adapter(wiphy); @@ -2446,7 +2447,8 @@ static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *nd return rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); } -static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev, + unsigned int link_id) { return 0; } diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 5c65ae6b8154..e15771965916 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4376,4 +4376,7 @@ enum ieee80211_range_params_max_total_ltf { IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED, }; +/* multi-link device */ +#define IEEE80211_MLD_MAX_NUM_LINKS 15 + #endif /* LINUX_IEEE80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6d02e12e4702..772e099fc932 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1158,6 +1158,7 @@ struct cfg80211_mbssid_elems { /** * struct cfg80211_beacon_data - beacon data + * @link_id: the link ID for the AP MLD link sending this beacon * @head: head portion of beacon (before TIM IE) * or %NULL if not changed * @tail: tail portion of beacon (after TIM IE) @@ -1188,6 +1189,8 @@ struct cfg80211_mbssid_elems { * attribute is present in beacon data or not. */ struct cfg80211_beacon_data { + unsigned int link_id; + const u8 *head, *tail; const u8 *beacon_ies; const u8 *proberesp_ies; @@ -4201,7 +4204,8 @@ struct cfg80211_ops { struct cfg80211_ap_settings *settings); int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); - int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev); + int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id); int (*add_station)(struct wiphy *wiphy, struct net_device *dev, @@ -4309,6 +4313,7 @@ struct cfg80211_ops { int (*set_bitrate_mask)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *peer, const struct cfg80211_bitrate_mask *mask); @@ -4384,6 +4389,7 @@ struct cfg80211_ops { int (*get_channel)(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef); int (*start_p2p_device)(struct wiphy *wiphy, @@ -4420,6 +4426,7 @@ struct cfg80211_ops { struct cfg80211_qos_map *qos_map); int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, struct cfg80211_chan_def *chandef); int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev, @@ -4545,10 +4552,14 @@ struct cfg80211_ops { * @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation * before connection. * @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys + * @WIPHY_FLAG_SUPPORTS_MLO: This is a temporary flag gating the MLO APIs, + * in order to not have them reachable in normal drivers, until we have + * complete feature/interface combinations/etc. advertisement. No driver + * should set this flag for now. */ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0), - /* use hole at 1 */ + WIPHY_FLAG_SUPPORTS_MLO = BIT(1), WIPHY_FLAG_SPLIT_SCAN_6GHZ = BIT(2), WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), @@ -5505,6 +5516,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @netdev: (private) Used to reference back to the netdev, may be %NULL * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev + * @connected_addr: (private) BSSID or AP MLD address if connected + * @connected: indicates if connected or not (STA mode) * @current_bss: (private) Used by the internal configuration code * @chandef: (private) Used by the internal configuration code to track * the user-set channel definition. @@ -5585,8 +5598,6 @@ struct wireless_dev { u8 address[ETH_ALEN] __aligned(sizeof(u16)); /* currently used for IBSS and SME - might be rearranged later */ - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len, mesh_id_len, mesh_id_up_len; struct cfg80211_conn *conn; struct cfg80211_cached_keys *connect_keys; enum ieee80211_bss_type conn_bss_type; @@ -5598,20 +5609,17 @@ struct wireless_dev { struct list_head event_list; spinlock_t event_lock; - struct cfg80211_internal_bss *current_bss; /* associated / joined */ - struct cfg80211_chan_def preset_chandef; - struct cfg80211_chan_def chandef; + u8 connected:1; bool ps; int ps_timeout; - int beacon_interval; - u32 ap_unexpected_nlportid; u32 owner_nlportid; bool nl_owner_dead; + /* FIXME: need to rework radar detection for MLO */ bool cac_started; unsigned long cac_start_time; unsigned int cac_time_ms; @@ -5639,6 +5647,50 @@ struct wireless_dev { struct work_struct pmsr_free_wk; unsigned long unprot_beacon_reported; + + union { + struct { + u8 connected_addr[ETH_ALEN] __aligned(2); + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } client; + struct { + int beacon_interval; + struct cfg80211_chan_def preset_chandef; + struct cfg80211_chan_def chandef; + u8 id[IEEE80211_MAX_SSID_LEN]; + u8 id_len, id_up_len; + } mesh; + struct { + struct cfg80211_chan_def preset_chandef; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } ap; + struct { + struct cfg80211_internal_bss *current_bss; + struct cfg80211_chan_def chandef; + int beacon_interval; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } ibss; + struct { + struct cfg80211_chan_def chandef; + } ocb; + } u; + + struct { + u8 addr[ETH_ALEN] __aligned(2); + union { + struct { + unsigned int beacon_interval; + struct cfg80211_chan_def chandef; + } ap; + struct { + struct cfg80211_internal_bss *current_bss; + } client; + }; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; + u16 valid_links; }; static inline const u8 *wdev_address(struct wireless_dev *wdev) @@ -5667,6 +5719,31 @@ static inline void *wdev_priv(struct wireless_dev *wdev) return wiphy_priv(wdev->wiphy); } +/** + * wdev_chandef - return chandef pointer from wireless_dev + * @wdev: the wdev + * @link_id: the link ID for MLO + * + * Return: The chandef depending on the mode, or %NULL. + */ +struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev, + unsigned int link_id); + +static inline void WARN_INVALID_LINK_ID(struct wireless_dev *wdev, + unsigned int link_id) +{ + WARN_ON(link_id && !wdev->valid_links); + WARN_ON(wdev->valid_links && + !(wdev->valid_links & BIT(link_id))); +} + +#define for_each_valid_link(wdev, link_id) \ + for (link_id = 0; \ + link_id < ((wdev)->valid_links ? ARRAY_SIZE((wdev)->links) : 1); \ + link_id++) \ + if (!(wdev)->valid_links || \ + ((wdev)->valid_links & BIT(link_id))) + /** * DOC: Utility functions * @@ -7882,12 +7959,14 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy, * cfg80211_ch_switch_notify - update wdev channel and notify userspace * @dev: the device which switched channels * @chandef: the new channel definition + * @link_id: the link ID for MLO, must be 0 for non-MLO * * Caller must acquire wdev_lock, therefore must only be called from sleepable * driver context! */ void cfg80211_ch_switch_notify(struct net_device *dev, - struct cfg80211_chan_def *chandef); + struct cfg80211_chan_def *chandef, + unsigned int link_id); /* * cfg80211_ch_switch_started_notify - notify channel switch start diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 98f905f16411..a9a2c9fef295 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -323,6 +323,17 @@ * Once the association is done, the driver cleans the FILS AAD data. */ +/** + * DOC: Multi-Link Operation + * + * In Multi-Link Operation, a connection between to MLDs utilizes multiple + * links. To use this in nl80211, various commands and responses now need + * to or will include the new %NL80211_ATTR_MLO_LINKS attribute. + * Additionally, various commands that need to operate on a specific link + * now need to be given the %NL80211_ATTR_MLO_LINK_ID attribute, e.g. to + * use %NL80211_CMD_START_AP or similar functions. + */ + /** * enum nl80211_commands - supported nl80211 commands * @@ -1237,6 +1248,12 @@ * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to * specify the timeout value. * + * @NL80211_CMD_ADD_LINK: Add a new link to an interface. The + * %NL80211_ATTR_MLO_LINK_ID attribute is used for the new link. + * @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come + * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links + * in preparation for e.g. roaming to a regular (non-MLO) AP. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1481,6 +1498,9 @@ enum nl80211_commands { NL80211_CMD_ASSOC_COMEBACK, + NL80211_CMD_ADD_LINK, + NL80211_CMD_REMOVE_LINK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2663,6 +2683,11 @@ enum nl80211_commands { * association request when used with NL80211_CMD_NEW_STATION). Can be set * only if %NL80211_STA_FLAG_WME is set. * + * @NL80211_ATTR_MLO_LINK_ID: A (u8) link ID for use with MLO, to be used with + * various commands that need a link ID to operate. + * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some + * per-link information and a link ID. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3177,6 +3202,9 @@ enum nl80211_attrs { NL80211_ATTR_DISABLE_EHT, + NL80211_ATTR_MLO_LINKS, + NL80211_ATTR_MLO_LINK_ID, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 881efbfb96f6..362cac9e2135 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1342,7 +1342,8 @@ static void ieee80211_free_next_beacon(struct ieee80211_sub_if_data *sdata) sdata->u.ap.next_beacon = NULL; } -static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *vlan; @@ -3049,6 +3050,7 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *addr, const struct cfg80211_bitrate_mask *mask) { @@ -3390,7 +3392,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (err) return err; - cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); + cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef, 0); return 0; } @@ -3898,6 +3900,7 @@ unlock: static int ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); @@ -3958,6 +3961,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5ad71ef02c..e0a9b7d63071 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1314,7 +1314,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) return; } - cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); + cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef, 0); } void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 550ac9d827fe..e68923200018 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -1,4 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Parts of this file are + * Copyright (C) 2022 Intel Corporation + */ #include #include #include @@ -7,8 +11,9 @@ #include "rdev-ops.h" -int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify) +static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev, unsigned int link_id, + bool notify) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; @@ -22,15 +27,16 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -ENOENT; - err = rdev_stop_ap(rdev, dev); + err = rdev_stop_ap(rdev, dev, link_id); if (!err) { wdev->conn_owner_nlportid = 0; - wdev->beacon_interval = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); - wdev->ssid_len = 0; + wdev->links[link_id].ap.beacon_interval = 0; + memset(&wdev->links[link_id].ap.chandef, 0, + sizeof(wdev->links[link_id].ap.chandef)); + wdev->u.ap.ssid_len = 0; rdev_set_qos_map(rdev, dev, NULL); if (notify) nl80211_send_ap_stopped(wdev); @@ -46,14 +52,36 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, return err; } +int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev, int link_id, + bool notify) +{ + unsigned int link; + int ret = 0; + + if (link_id >= 0) + return ___cfg80211_stop_ap(rdev, dev, link_id, notify); + + for_each_valid_link(dev->ieee80211_ptr, link) { + int ret1 = ___cfg80211_stop_ap(rdev, dev, link, notify); + + if (ret1) + ret = ret1; + /* try the next one also if one errored */ + } + + return ret; +} + int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify) + struct net_device *dev, int link_id, + bool notify) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); - err = __cfg80211_stop_ap(rdev, dev, notify); + err = __cfg80211_stop_ap(rdev, dev, link_id, notify); wdev_unlock(wdev); return err; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index f74f176e0d9d..efc2de4bab57 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -672,14 +672,21 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, * range of chandef. */ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, - struct ieee80211_channel *chan) + struct ieee80211_channel *chan, + bool primary_only) { int width; u32 freq; + if (!chandef->chan) + return false; + if (chandef->chan->center_freq == chan->center_freq) return true; + if (primary_only) + return false; + width = cfg80211_chandef_get_width(chandef); if (width <= 20) return false; @@ -704,23 +711,25 @@ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) { - bool active = false; + unsigned int link; ASSERT_WDEV_LOCK(wdev); - if (!wdev->chandef.chan) - return false; - switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - active = wdev->beacon_interval != 0; + for_each_valid_link(wdev, link) { + if (wdev->links[link].ap.beacon_interval) + return true; + } break; case NL80211_IFTYPE_ADHOC: - active = wdev->ssid_len != 0; + if (wdev->u.ibss.ssid_len) + return true; break; case NL80211_IFTYPE_MESH_POINT: - active = wdev->mesh_id_len != 0; + if (wdev->u.mesh.id_len) + return true; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_OCB: @@ -737,7 +746,35 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) WARN_ON(1); } - return active; + return false; +} + +bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, + struct ieee80211_channel *chan, + bool primary_only) +{ + unsigned int link; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + for_each_valid_link(wdev, link) { + if (cfg80211_is_sub_chan(&wdev->links[link].ap.chandef, + chan, primary_only)) + return true; + } + break; + case NL80211_IFTYPE_ADHOC: + return cfg80211_is_sub_chan(&wdev->u.ibss.chandef, chan, + primary_only); + case NL80211_IFTYPE_MESH_POINT: + return cfg80211_is_sub_chan(&wdev->u.mesh.chandef, chan, + primary_only); + default: + break; + } + + return false; } static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, @@ -752,7 +789,7 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, continue; } - if (cfg80211_is_sub_chan(&wdev->chandef, chan)) { + if (cfg80211_wdev_on_sub_chan(wdev, chan, false)) { wdev_unlock(wdev); return true; } @@ -772,7 +809,8 @@ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) return false; - return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); + return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel, + false); } bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, @@ -1176,6 +1214,68 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_chandef_usable); +static bool cfg80211_ir_permissive_check_wdev(enum nl80211_iftype iftype, + struct wireless_dev *wdev, + struct ieee80211_channel *chan) +{ + struct ieee80211_channel *other_chan = NULL; + unsigned int link_id; + int r1, r2; + + for_each_valid_link(wdev, link_id) { + if (wdev->iftype == NL80211_IFTYPE_STATION && + wdev->links[link_id].client.current_bss) + other_chan = wdev->links[link_id].client.current_bss->pub.channel; + + /* + * If a GO already operates on the same GO_CONCURRENT channel, + * this one (maybe the same one) can beacon as well. We allow + * the operation even if the station we relied on with + * GO_CONCURRENT is disconnected now. But then we must make sure + * we're not outdoor on an indoor-only channel. + */ + if (iftype == NL80211_IFTYPE_P2P_GO && + wdev->iftype == NL80211_IFTYPE_P2P_GO && + wdev->links[link_id].ap.beacon_interval && + !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) + other_chan = wdev->links[link_id].ap.chandef.chan; + + if (!other_chan) + continue; + + if (chan == other_chan) + return true; + + if (chan->band != NL80211_BAND_5GHZ && + chan->band != NL80211_BAND_6GHZ) + continue; + + r1 = cfg80211_get_unii(chan->center_freq); + r2 = cfg80211_get_unii(other_chan->center_freq); + + if (r1 != -EINVAL && r1 == r2) { + /* + * At some locations channels 149-165 are considered a + * bundle, but at other locations, e.g., Indonesia, + * channels 149-161 are considered a bundle while + * channel 165 is left out and considered to be in a + * different bundle. Thus, in case that there is a + * station interface connected to an AP on channel 165, + * it is assumed that channels 149-161 are allowed for + * GO operations. However, having a station interface + * connected to an AP on channels 149-161, does not + * allow GO operation on channel 165. + */ + if (chan->center_freq == 5825 && + other_chan->center_freq != 5825) + continue; + return true; + } + } + + return false; +} + /* * Check if the channel can be used under permissive conditions mandated by * some regulatory bodies, i.e., the channel is marked with @@ -1219,59 +1319,14 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, * the current registered device. */ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - struct ieee80211_channel *other_chan = NULL; - int r1, r2; + bool ret; wdev_lock(wdev); - if (wdev->iftype == NL80211_IFTYPE_STATION && - wdev->current_bss) - other_chan = wdev->current_bss->pub.channel; - - /* - * If a GO already operates on the same GO_CONCURRENT channel, - * this one (maybe the same one) can beacon as well. We allow - * the operation even if the station we relied on with - * GO_CONCURRENT is disconnected now. But then we must make sure - * we're not outdoor on an indoor-only channel. - */ - if (iftype == NL80211_IFTYPE_P2P_GO && - wdev->iftype == NL80211_IFTYPE_P2P_GO && - wdev->beacon_interval && - !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) - other_chan = wdev->chandef.chan; + ret = cfg80211_ir_permissive_check_wdev(iftype, wdev, chan); wdev_unlock(wdev); - if (!other_chan) - continue; - - if (chan == other_chan) - return true; - - if (chan->band != NL80211_BAND_5GHZ && - chan->band != NL80211_BAND_6GHZ) - continue; - - r1 = cfg80211_get_unii(chan->center_freq); - r2 = cfg80211_get_unii(other_chan->center_freq); - - if (r1 != -EINVAL && r1 == r2) { - /* - * At some locations channels 149-165 are considered a - * bundle, but at other locations, e.g., Indonesia, - * channels 149-161 are considered a bundle while - * channel 165 is left out and considered to be in a - * different bundle. Thus, in case that there is a - * station interface connected to an AP on channel 165, - * it is assumed that channels 149-161 are allowed for - * GO operations. However, having a station interface - * connected to an AP on channels 149-161, does not - * allow GO operation on channel 165. - */ - if (chan->center_freq == 5825 && - other_chan->center_freq != 5825) - continue; - return true; - } + if (ret) + return ret; } return false; @@ -1374,3 +1429,24 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy, return false; } EXPORT_SYMBOL(cfg80211_any_usable_channels); + +struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev, + unsigned int link_id) +{ + ASSERT_WDEV_LOCK(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_MESH_POINT: + return &wdev->u.mesh.chandef; + case NL80211_IFTYPE_ADHOC: + return &wdev->u.ibss.chandef; + case NL80211_IFTYPE_OCB: + return &wdev->u.ocb.chandef; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + return &wdev->links[link_id].ap.chandef; + default: + return NULL; + } +} +EXPORT_SYMBOL(wdev_chandef); diff --git a/net/wireless/core.c b/net/wireless/core.c index f08d4b3bb148..3e5d12040726 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1118,6 +1118,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, bool unregister_netdev) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + unsigned int link_id; ASSERT_RTNL(); lockdep_assert_held(&rdev->wiphy.mtx); @@ -1167,11 +1168,22 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, */ cfg80211_process_wdev_events(wdev); - if (WARN_ON(wdev->current_bss)) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + if (wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) { + for (link_id = 0; link_id < ARRAY_SIZE(wdev->links); link_id++) { + struct cfg80211_internal_bss *curbss; + + curbss = wdev->links[link_id].client.current_bss; + + if (WARN_ON(curbss)) { + cfg80211_unhold_bss(curbss); + cfg80211_put_bss(wdev->wiphy, &curbss->pub); + wdev->links[link_id].client.current_bss = NULL; + } + } } + + wdev->connected = false; } void cfg80211_unregister_wdev(struct wireless_dev *wdev) @@ -1233,7 +1245,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - __cfg80211_stop_ap(rdev, dev, true); + __cfg80211_stop_ap(rdev, dev, -1, true); break; case NL80211_IFTYPE_OCB: __cfg80211_leave_ocb(rdev, dev); @@ -1463,9 +1475,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, memcpy(&setup, &default_mesh_setup, sizeof(setup)); /* back compat only needed for mesh_id */ - setup.mesh_id = wdev->ssid; - setup.mesh_id_len = wdev->mesh_id_up_len; - if (wdev->mesh_id_up_len) + setup.mesh_id = wdev->u.mesh.id; + setup.mesh_id_len = wdev->u.mesh.id_up_len; + if (wdev->u.mesh.id_up_len) __cfg80211_join_mesh(rdev, dev, &setup, &default_mesh_config); diff --git a/net/wireless/core.h b/net/wireless/core.h index 5436ada91b1a..2c195067ddff 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -307,6 +307,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev); void cfg80211_bss_age(struct cfg80211_registered_device *rdev, unsigned long age_secs); void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, + unsigned int link, struct ieee80211_channel *channel); /* IBSS */ @@ -353,9 +354,11 @@ int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, /* AP */ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify); + struct net_device *dev, int link, + bool notify); int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify); + struct net_device *dev, int link, + bool notify); /* MLME */ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, @@ -507,7 +510,11 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev); bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, - struct ieee80211_channel *chan); + struct ieee80211_channel *chan, + bool primary_only); +bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, + struct ieee80211_channel *chan, + bool primary_only); static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 5d89eec2869a..4935f94d1acc 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -28,7 +28,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return; - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return; bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, @@ -37,13 +37,13 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, if (WARN_ON(!bss)) return; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); + if (wdev->u.ibss.current_bss) { + cfg80211_unhold_bss(wdev->u.ibss.current_bss); + cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub); } cfg80211_hold_bss(bss_from_pub(bss)); - wdev->current_bss = bss_from_pub(bss); + wdev->u.ibss.current_bss = bss_from_pub(bss); if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); @@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, lockdep_assert_held(&rdev->wiphy.mtx); ASSERT_WDEV_LOCK(wdev); - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) return -EALREADY; if (!params->basic_rates) { @@ -131,7 +131,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, kfree_sensitive(wdev->connect_keys); wdev->connect_keys = connkeys; - wdev->chandef = params->chandef; + wdev->u.ibss.chandef = params->chandef; if (connkeys) { params->wep_keys = connkeys->params; params->wep_tx_key = connkeys->def; @@ -146,8 +146,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return err; } - memcpy(wdev->ssid, params->ssid, params->ssid_len); - wdev->ssid_len = params->ssid_len; + memcpy(wdev->u.ibss.ssid, params->ssid, params->ssid_len); + wdev->u.ibss.ssid_len = params->ssid_len; return 0; } @@ -173,14 +173,14 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) for (i = 0; i < 6; i++) rdev_del_key(rdev, dev, i, false, NULL); - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); + if (wdev->u.ibss.current_bss) { + cfg80211_unhold_bss(wdev->u.ibss.current_bss); + cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub); } - wdev->current_bss = NULL; - wdev->ssid_len = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + wdev->u.ibss.current_bss = NULL; + wdev->u.ibss.ssid_len = 0; + memset(&wdev->u.ibss.chandef, 0, sizeof(wdev->u.ibss.chandef)); #ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; @@ -205,7 +205,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return -ENOLINK; err = rdev_leave_ibss(rdev, dev); @@ -339,7 +339,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -374,8 +374,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, return -EINVAL; wdev_lock(wdev); - if (wdev->current_bss) - chan = wdev->current_bss->pub.channel; + if (wdev->u.ibss.current_bss) + chan = wdev->u.ibss.current_bss->pub.channel; else if (wdev->wext.ibss.chandef.chan) chan = wdev->wext.ibss.chandef.chan; wdev_unlock(wdev); @@ -408,7 +408,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -419,8 +419,8 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, if (len > 0 && ssid[len - 1] == '\0') len--; - memcpy(wdev->ssid, ssid, len); - wdev->wext.ibss.ssid = wdev->ssid; + memcpy(wdev->u.ibss.ssid, ssid, len); + wdev->wext.ibss.ssid = wdev->u.ibss.ssid; wdev->wext.ibss.ssid_len = len; wdev_lock(wdev); @@ -443,10 +443,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->flags = 0; wdev_lock(wdev); - if (wdev->ssid_len) { + if (wdev->u.ibss.ssid_len) { data->flags = 1; - data->length = wdev->ssid_len; - memcpy(ssid, wdev->ssid, data->length); + data->length = wdev->u.ibss.ssid_len; + memcpy(ssid, wdev->u.ibss.ssid, data->length); } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { data->flags = 1; data->length = wdev->wext.ibss.ssid_len; @@ -494,7 +494,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -527,8 +527,9 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + if (wdev->u.ibss.current_bss) + memcpy(ap_addr->sa_data, wdev->u.ibss.current_bss->pub.bssid, + ETH_ALEN); else if (wdev->wext.ibss.bssid) memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); else diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index e4e363138279..59a3c5c092b1 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -1,4 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Portions + * Copyright (C) 2022 Intel Corporation + */ #include #include #include @@ -114,7 +118,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, setup->is_secure) return -EOPNOTSUPP; - if (wdev->mesh_id_len) + if (wdev->u.mesh.id_len) return -EALREADY; if (!setup->mesh_id_len) @@ -125,7 +129,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!setup->chandef.chan) { /* if no channel explicitly given, use preset channel */ - setup->chandef = wdev->preset_chandef; + setup->chandef = wdev->u.mesh.preset_chandef; } if (!setup->chandef.chan) { @@ -209,10 +213,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, err = rdev_join_mesh(rdev, dev, conf, setup); if (!err) { - memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); - wdev->mesh_id_len = setup->mesh_id_len; - wdev->chandef = setup->chandef; - wdev->beacon_interval = setup->beacon_interval; + memcpy(wdev->u.mesh.id, setup->mesh_id, setup->mesh_id_len); + wdev->u.mesh.id_len = setup->mesh_id_len; + wdev->u.mesh.chandef = setup->chandef; + wdev->u.mesh.beacon_interval = setup->beacon_interval; } return err; @@ -241,15 +245,15 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, chandef->chan); if (!err) - wdev->chandef = *chandef; + wdev->u.mesh.chandef = *chandef; return err; } - if (wdev->mesh_id_len) + if (wdev->u.mesh.id_len) return -EBUSY; - wdev->preset_chandef = *chandef; + wdev->u.mesh.preset_chandef = *chandef; return 0; } @@ -267,15 +271,16 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, if (!rdev->ops->leave_mesh) return -EOPNOTSUPP; - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) return -ENOTCONN; err = rdev_leave_mesh(rdev, dev); if (!err) { wdev->conn_owner_nlportid = 0; - wdev->mesh_id_len = 0; - wdev->beacon_interval = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + wdev->u.mesh.id_len = 0; + wdev->u.mesh.beacon_interval = 0; + memset(&wdev->u.mesh.chandef, 0, + sizeof(wdev->u.mesh.chandef)); rdev_set_qos_map(rdev, dev, NULL); cfg80211_sched_dfs_chan_update(rdev); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index c8155a483ec2..fab2d6206cdd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -92,8 +92,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev, nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); - if (!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) + if (!wdev->connected || !ether_addr_equal(wdev->u.client.connected_addr, bssid)) return; __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); @@ -113,8 +112,8 @@ static void cfg80211_process_disassoc(struct wireless_dev *wdev, nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); - if (WARN_ON(!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + if (WARN_ON(!wdev->connected || + !ether_addr_equal(wdev->u.client.connected_addr, bssid))) return; __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); @@ -260,8 +259,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!key || !key_len || key_idx < 0 || key_idx > 3) return -EINVAL; - if (wdev->current_bss && - ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) + if (wdev->connected && + ether_addr_equal(bssid, wdev->u.client.connected_addr)) return -EALREADY; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, @@ -322,9 +321,9 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (wdev->current_bss && - (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid, - req->prev_bssid))) + if (wdev->connected && + (!req->prev_bssid || + !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid))) return -EALREADY; cfg80211_oper_and_ht_capa(&req->ht_capa_mask, @@ -364,13 +363,13 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); if (local_state_change && - (!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + (!wdev->connected || + !ether_addr_equal(wdev->u.client.connected_addr, bssid))) return 0; if (ether_addr_equal(wdev->disconnect_bssid, bssid) || - (wdev->current_bss && - ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + (wdev->connected && + ether_addr_equal(wdev->u.client.connected_addr, bssid))) wdev->conn_owner_nlportid = 0; return rdev_deauth(rdev, dev, &req); @@ -392,11 +391,12 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (!wdev->current_bss) + if (!wdev->connected) return -ENOTCONN; - if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) - req.bss = &wdev->current_bss->pub; + if (ether_addr_equal(wdev->links[0].client.current_bss->pub.bssid, + bssid)) + req.bss = &wdev->links[0].client.current_bss->pub; else return -ENOTCONN; @@ -405,7 +405,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, return err; /* driver should have reported the disassoc */ - WARN_ON(wdev->current_bss); + WARN_ON(wdev->connected); return 0; } @@ -420,10 +420,10 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, if (!rdev->ops->deauth) return; - if (!wdev->current_bss) + if (!wdev->connected) return; - memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + memcpy(bssid, wdev->u.client.connected_addr, ETH_ALEN); cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, WLAN_REASON_DEAUTH_LEAVING, false); } @@ -676,28 +676,34 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: + /* + * check for IBSS DA must be done by driver as + * cfg80211 doesn't track the stations + */ + if (!wdev->u.ibss.current_bss || + !ether_addr_equal(wdev->u.ibss.current_bss->pub.bssid, + mgmt->bssid)) { + err = -ENOTCONN; + break; + } + break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss) { + if (!wdev->connected) { err = -ENOTCONN; break; } - if (!ether_addr_equal(wdev->current_bss->pub.bssid, + /* FIXME: MLD may address this differently */ + + if (!ether_addr_equal(wdev->u.client.connected_addr, mgmt->bssid)) { err = -ENOTCONN; break; } - /* - * check for IBSS DA must be done by driver as - * cfg80211 doesn't track the stations - */ - if (wdev->iftype == NL80211_IFTYPE_ADHOC) - break; - /* for station, check that DA is the AP */ - if (!ether_addr_equal(wdev->current_bss->pub.bssid, + if (!ether_addr_equal(wdev->u.client.connected_addr, mgmt->da)) { err = -ENOTCONN; break; @@ -743,12 +749,12 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) return -EINVAL; - if (!wdev->current_bss && + if (!wdev->connected && !wiphy_ext_feature_isset( &rdev->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA)) return -EINVAL; - if (wdev->current_bss && + if (wdev->connected && !wiphy_ext_feature_isset( &rdev->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED)) @@ -940,12 +946,16 @@ void cfg80211_cac_event(struct net_device *netdev, struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); unsigned long timeout; + /* not yet supported */ + if (wdev->valid_links) + return; + trace_cfg80211_cac_event(netdev, event); if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED)) return; - if (WARN_ON(!wdev->chandef.chan)) + if (WARN_ON(!wdev->links[0].ap.chandef.chan)) return; switch (event) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 740b29481bc6..af31978fc9cc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -792,6 +792,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NL80211_EHT_MIN_CAPABILITY_LEN, NL80211_EHT_MAX_CAPABILITY_LEN), [NL80211_ATTR_DISABLE_EHT] = { .type = NLA_FLAG }, + [NL80211_ATTR_MLO_LINKS] = + NLA_POLICY_NESTED_ARRAY(nl80211_policy), + [NL80211_ATTR_MLO_LINK_ID] = + NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), }; /* policy for the key attributes */ @@ -1225,6 +1229,37 @@ static bool nl80211_put_txq_stats(struct sk_buff *msg, /* netlink command implementations */ +/** + * nl80211_link_id - return link ID + * @attrs: attributes to look at + * + * Returns: the link ID or 0 if not given + * + * Note this function doesn't do any validation of the link + * ID validity wrt. links that were actually added, so it must + * be called only from ops with %NL80211_FLAG_MLO_VALID_LINK_ID + * or if additional validation is done. + */ +static unsigned int nl80211_link_id(struct nlattr **attrs) +{ + struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!linkid) + return 0; + + return nla_get_u8(linkid); +} + +static int nl80211_link_id_or_invalid(struct nlattr **attrs) +{ + struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!linkid) + return -1; + + return nla_get_u8(linkid); +} + struct key_parse { struct key_params p; int idx; @@ -1496,11 +1531,15 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) case NL80211_IFTYPE_MESH_POINT: break; case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.current_bss) + return 0; + return -ENOLINK; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss) - return -ENOLINK; - break; + /* for MLO, require driver validation of the link ID */ + if (wdev->connected) + return 0; + return -ENOLINK; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_MONITOR: @@ -3232,12 +3271,14 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct genl_info *info) + struct genl_info *info, + int _link_id) { struct cfg80211_chan_def chandef; int result; enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; struct wireless_dev *wdev = NULL; + int link_id = _link_id; if (dev) wdev = dev->ieee80211_ptr; @@ -3246,6 +3287,12 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, if (wdev) iftype = wdev->iftype; + if (link_id < 0) { + if (wdev && wdev->valid_links) + return -EINVAL; + link_id = 0; + } + result = nl80211_parse_chandef(rdev, info, &chandef); if (result) return result; @@ -3254,49 +3301,48 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef, - iftype)) { - result = -EINVAL; - break; - } - if (wdev->beacon_interval) { + iftype)) + return -EINVAL; + if (wdev->links[link_id].ap.beacon_interval) { + struct ieee80211_channel *cur_chan; + if (!dev || !rdev->ops->set_ap_chanwidth || !(rdev->wiphy.features & - NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) { - result = -EBUSY; - break; - } + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) + return -EBUSY; /* Only allow dynamic channel width changes */ - if (chandef.chan != wdev->preset_chandef.chan) { - result = -EBUSY; - break; - } - result = rdev_set_ap_chanwidth(rdev, dev, &chandef); + cur_chan = wdev->links[link_id].ap.chandef.chan; + if (chandef.chan != cur_chan) + return -EBUSY; + + result = rdev_set_ap_chanwidth(rdev, dev, link_id, + &chandef); if (result) - break; + return result; + wdev->links[link_id].ap.chandef = chandef; + } else { + wdev->u.ap.preset_chandef = chandef; } - wdev->preset_chandef = chandef; - result = 0; - break; + return 0; case NL80211_IFTYPE_MESH_POINT: - result = cfg80211_set_mesh_channel(rdev, wdev, &chandef); - break; + return cfg80211_set_mesh_channel(rdev, wdev, &chandef); case NL80211_IFTYPE_MONITOR: - result = cfg80211_set_monitor_channel(rdev, &chandef); - break; + return cfg80211_set_monitor_channel(rdev, &chandef); default: - result = -EINVAL; + break; } - return result; + return -EINVAL; } static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int link_id = nl80211_link_id_or_invalid(info->attrs); struct net_device *netdev = info->user_ptr[1]; - return __nl80211_set_channel(rdev, netdev, info); + return __nl80211_set_channel(rdev, netdev, info, link_id); } static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) @@ -3411,7 +3457,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) result = __nl80211_set_channel( rdev, nl80211_can_set_dev_channel(wdev) ? netdev : NULL, - info); + info, -1); if (result) goto out; } @@ -3696,15 +3742,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr)) goto nla_put_failure; - if (rdev->ops->get_channel) { - int ret; + if (rdev->ops->get_channel && !wdev->valid_links) { struct cfg80211_chan_def chandef = {}; + int ret; - ret = rdev_get_channel(rdev, wdev, &chandef); - if (ret == 0) { - if (nl80211_send_chandef(msg, &chandef)) - goto nla_put_failure; - } + ret = rdev_get_channel(rdev, wdev, 0, &chandef); + if (ret == 0 && nl80211_send_chandef(msg, &chandef)) + goto nla_put_failure; } if (rdev->ops->get_tx_power) { @@ -3721,27 +3765,24 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - if (wdev->ssid_len && - nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) + if (wdev->u.ap.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.ap.ssid_len, + wdev->u.ap.ssid)) goto nla_put_failure_locked; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_ADHOC: { - const struct element *ssid_elem; - - if (!wdev->current_bss) - break; - rcu_read_lock(); - ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, - WLAN_EID_SSID); - if (ssid_elem && - nla_put(msg, NL80211_ATTR_SSID, ssid_elem->datalen, - ssid_elem->data)) - goto nla_put_failure_rcu_locked; - rcu_read_unlock(); + if (wdev->u.client.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.client.ssid_len, + wdev->u.client.ssid)) + goto nla_put_failure_locked; + break; + case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.ibss.ssid_len, + wdev->u.ibss.ssid)) + goto nla_put_failure_locked; break; - } default: /* nothing */ break; @@ -3761,8 +3802,6 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag genlmsg_end(msg, hdr); return 0; - nla_put_failure_rcu_locked: - rcu_read_unlock(); nla_put_failure_locked: wdev_unlock(wdev); nla_put_failure: @@ -4014,10 +4053,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); - wdev->mesh_id_up_len = + wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); - memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), - wdev->mesh_id_up_len); + memcpy(wdev->u.mesh.id, + nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->u.mesh.id_up_len); wdev_unlock(wdev); } @@ -4122,10 +4162,11 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); - wdev->mesh_id_up_len = + wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); - memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), - wdev->mesh_id_up_len); + memcpy(wdev->u.mesh.id, + nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->u.mesh.id_up_len); wdev_unlock(wdev); break; case NL80211_IFTYPE_NAN: @@ -4662,7 +4703,7 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!dev->ieee80211_ptr->beacon_interval) + if (!dev->ieee80211_ptr->links[0].ap.beacon_interval) return -EINVAL; acl = parse_acl_data(&rdev->wiphy, info); @@ -4818,14 +4859,24 @@ static void he_build_mcs_mask(u16 he_mcs_map, } } -static u16 he_get_txmcsmap(struct genl_info *info, +static u16 he_get_txmcsmap(struct genl_info *info, unsigned int link_id, const struct ieee80211_sta_he_cap *he_cap) { struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; - __le16 tx_mcs; + struct cfg80211_chan_def *chandef; + __le16 tx_mcs; - switch (wdev->chandef.width) { + chandef = wdev_chandef(wdev, link_id); + if (!chandef) { + /* + * This is probably broken, but we never maintained + * a chandef in these cases, so it always was. + */ + return le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); + } + + switch (chandef->width) { case NL80211_CHAN_WIDTH_80P80: tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80p80; break; @@ -4836,6 +4887,7 @@ static u16 he_get_txmcsmap(struct genl_info *info, tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80; break; } + return le16_to_cpu(tx_mcs); } @@ -4843,7 +4895,8 @@ static bool he_set_mcs_mask(struct genl_info *info, struct wireless_dev *wdev, struct ieee80211_supported_band *sband, struct nl80211_txrate_he *txrate, - u16 mcs[NL80211_HE_NSS_MAX]) + u16 mcs[NL80211_HE_NSS_MAX], + unsigned int link_id) { const struct ieee80211_sta_he_cap *he_cap; u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {}; @@ -4856,7 +4909,7 @@ static bool he_set_mcs_mask(struct genl_info *info, memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX); - tx_mcs_map = he_get_txmcsmap(info, he_cap); + tx_mcs_map = he_get_txmcsmap(info, link_id, he_cap); /* Build he_mcs_mask from HE capabilities */ he_build_mcs_mask(tx_mcs_map, tx_mcs_mask); @@ -4876,7 +4929,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, enum nl80211_attrs attr, struct cfg80211_bitrate_mask *mask, struct net_device *dev, - bool default_all_enabled) + bool default_all_enabled, + unsigned int link_id) { struct nlattr *tb[NL80211_TXRATE_MAX + 1]; struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -4913,7 +4967,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (!he_cap) continue; - he_tx_mcs_map = he_get_txmcsmap(info, he_cap); + he_tx_mcs_map = he_get_txmcsmap(info, link_id, he_cap); he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs); mask->control[i].he_gi = 0xFF; @@ -4978,7 +5032,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (tb[NL80211_TXRATE_HE] && !he_set_mcs_mask(info, wdev, sband, nla_data(tb[NL80211_TXRATE_HE]), - mask->control[band].he_mcs)) + mask->control[band].he_mcs, + link_id)) return -EINVAL; if (tb[NL80211_TXRATE_HE_GI]) @@ -5215,6 +5270,8 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, memset(bcn, 0, sizeof(*bcn)); + bcn->link_id = nl80211_link_id(attrs); + if (attrs[NL80211_ATTR_BEACON_HEAD]) { bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]); bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]); @@ -5468,22 +5525,20 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, struct cfg80211_ap_settings *params) { struct wireless_dev *wdev; - bool ret = false; list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; - if (!wdev->preset_chandef.chan) + if (!wdev->u.ap.preset_chandef.chan) continue; - params->chandef = wdev->preset_chandef; - ret = true; - break; + params->chandef = wdev->u.ap.preset_chandef; + return true; } - return ret; + return false; } static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, @@ -5541,6 +5596,7 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_ap_settings *params; @@ -5553,7 +5609,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->start_ap) return -EOPNOTSUPP; - if (wdev->beacon_interval) + if (wdev->links[link_id].ap.beacon_interval) return -EALREADY; /* these are required for START_AP */ @@ -5595,6 +5651,18 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; goto out; } + + if (wdev->u.ap.ssid_len && + (wdev->u.ap.ssid_len != params->ssid_len || + memcmp(wdev->u.ap.ssid, params->ssid, params->ssid_len))) { + /* require identical SSID for MLO */ + err = -EINVAL; + goto out; + } + } else if (wdev->valid_links) { + /* require SSID for MLO */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) @@ -5662,8 +5730,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_chandef(rdev, info, ¶ms->chandef); if (err) goto out; - } else if (wdev->preset_chandef.chan) { - params->chandef = wdev->preset_chandef; + } else if (wdev->valid_links) { + /* with MLD need to specify the channel configuration */ + err = -EINVAL; + goto out; + } else if (wdev->u.ap.preset_chandef.chan) { + params->chandef = wdev->u.ap.preset_chandef; } else if (!nl80211_get_ap_channel(rdev, params)) { err = -EINVAL; goto out; @@ -5679,7 +5751,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, ¶ms->beacon_rate, - dev, false); + dev, false, link_id); if (err) goto out; @@ -5779,19 +5851,28 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) params->flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; wdev_lock(wdev); + if (wdev->conn_owner_nlportid && + info->attrs[NL80211_ATTR_SOCKET_OWNER] && + wdev->conn_owner_nlportid != info->snd_portid) { + err = -EINVAL; + goto out_unlock; + } + + /* FIXME: validate MLO/link-id against driver capabilities */ + err = rdev_start_ap(rdev, dev, params); if (!err) { - wdev->preset_chandef = params->chandef; - wdev->beacon_interval = params->beacon_interval; - wdev->chandef = params->chandef; - wdev->ssid_len = params->ssid_len; - memcpy(wdev->ssid, params->ssid, wdev->ssid_len); + wdev->links[link_id].ap.beacon_interval = params->beacon_interval; + wdev->links[link_id].ap.chandef = params->chandef; + wdev->u.ap.ssid_len = params->ssid_len; + memcpy(wdev->u.ap.ssid, params->ssid, + params->ssid_len); if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) wdev->conn_owner_nlportid = info->snd_portid; } +out_unlock: wdev_unlock(wdev); - out: kfree(params->acl); kfree(params->beacon.mbssid_ies); @@ -5807,6 +5888,7 @@ out: static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_beacon_data params; @@ -5819,7 +5901,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->change_beacon) return -EOPNOTSUPP; - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -EINVAL; err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); @@ -5838,9 +5920,10 @@ out: static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; - return cfg80211_stop_ap(rdev, dev, false); + return cfg80211_stop_ap(rdev, dev, link_id, false); } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { @@ -7590,7 +7673,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, wdev_lock(wdev); /* If not connected, get default parameters */ - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); else err = rdev_get_mesh_config(rdev, dev, &cur_params); @@ -7971,7 +8054,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, return err; wdev_lock(wdev); - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) err = -ENOLINK; if (!err) @@ -8463,14 +8546,44 @@ int nl80211_parse_random_mac(struct nlattr **attrs, return 0; } -static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev) +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev, + struct ieee80211_channel *chan) { + unsigned int link_id; + bool all_ok = true; + ASSERT_WDEV_LOCK(wdev); if (!cfg80211_beaconing_iface_active(wdev)) return true; - if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR)) + /* + * FIXME: check if we have a free HW resource/link for chan + * + * This, as well as the FIXME below, requires knowing the link + * capabilities of the hardware. + */ + + /* we cannot leave radar channels */ + for_each_valid_link(wdev, link_id) { + struct cfg80211_chan_def *chandef; + + chandef = wdev_chandef(wdev, link_id); + if (!chandef) + continue; + + /* + * FIXME: don't require all_ok, but rather check only the + * correct HW resource/link onto which 'chan' falls, + * as only that link leaves the channel for doing + * the off-channel operation. + */ + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) + all_ok = false; + } + + if (all_ok) return true; return regulatory_pre_cac_allowed(wdev->wiphy); @@ -8553,7 +8666,7 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev, int err; if (!(wiphy->features & randomness_flag) || - (wdev && wdev->current_bss)) + (wdev && wdev->connected)) return -EOPNOTSUPP; err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask); @@ -8690,17 +8803,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->n_channels = i; wdev_lock(wdev); - if (!cfg80211_off_channel_oper_allowed(wdev)) { - struct ieee80211_channel *chan; + for (i = 0; i < request->n_channels; i++) { + struct ieee80211_channel *chan = request->channels[i]; - if (request->n_channels != 1) { - wdev_unlock(wdev); - err = -EBUSY; - goto out_free; - } + /* if we can go off-channel to the target channel we're good */ + if (cfg80211_off_channel_oper_allowed(wdev, chan)) + continue; - chan = request->channels[0]; - if (chan->center_freq != wdev->chandef.chan->center_freq) { + if (!cfg80211_wdev_on_sub_chan(wdev, chan, true)) { wdev_unlock(wdev); err = -EBUSY; goto out_free; @@ -9445,7 +9555,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms); if (!err) { - wdev->chandef = chandef; + wdev->links[0].ap.chandef = chandef; wdev->cac_started = true; wdev->cac_start_time = jiffies; wdev->cac_time_ms = cac_time_ms; @@ -9513,6 +9623,7 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb, static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_csa_settings params; @@ -9539,15 +9650,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) need_handle_dfs_flag = false; /* useless if AP is not running */ - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -ENOTCONN; break; case NL80211_IFTYPE_ADHOC: - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return -ENOTCONN; break; case NL80211_IFTYPE_MESH_POINT: - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) return -ENOTCONN; break; default: @@ -9718,6 +9829,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, { struct cfg80211_bss *res = &intbss->pub; const struct cfg80211_bss_ies *ies; + unsigned int link_id; void *hdr; struct nlattr *bss; @@ -9822,13 +9934,15 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, switch (wdev->iftype) { case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - if (intbss == wdev->current_bss && - nla_put_u32(msg, NL80211_BSS_STATUS, - NL80211_BSS_STATUS_ASSOCIATED)) - goto nla_put_failure; + for_each_valid_link(wdev, link_id) { + if (intbss == wdev->links[link_id].client.current_bss && + nla_put_u32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_ASSOCIATED)) + goto nla_put_failure; + } break; case NL80211_IFTYPE_ADHOC: - if (intbss == wdev->current_bss && + if (intbss == wdev->u.ibss.current_bss && nla_put_u32(msg, NL80211_BSS_STATUS, NL80211_BSS_STATUS_IBSS_JOINED)) goto nla_put_failure; @@ -11362,7 +11476,7 @@ static int nl80211_update_connect_params(struct sk_buff *skb, } wdev_lock(dev->ieee80211_ptr); - if (!wdev->current_bss) + if (!wdev->connected) ret = -ENOLINK; else ret = rdev_update_connect_params(rdev, dev, &connect, changed); @@ -11575,9 +11689,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct wireless_dev *wdev = info->user_ptr[1]; struct cfg80211_chan_def chandef; - const struct cfg80211_chan_def *compat_chandef; struct sk_buff *msg; void *hdr; u64 cookie; @@ -11607,10 +11721,22 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, return err; wdev_lock(wdev); - if (!cfg80211_off_channel_oper_allowed(wdev) && - !cfg80211_chandef_identical(&wdev->chandef, &chandef)) { - compat_chandef = cfg80211_chandef_compatible(&wdev->chandef, - &chandef); + if (!cfg80211_off_channel_oper_allowed(wdev, chandef.chan)) { + const struct cfg80211_chan_def *oper_chandef, *compat_chandef; + + oper_chandef = wdev_chandef(wdev, link_id); + + if (WARN_ON(!oper_chandef)) { + /* cannot happen since we must beacon to get here */ + WARN_ON(1); + wdev_unlock(wdev); + return -EBUSY; + } + + /* note: returns first one if identical chandefs */ + compat_chandef = cfg80211_chandef_compatible(&chandef, + oper_chandef); + if (compat_chandef != &chandef) { wdev_unlock(wdev); return -EBUSY; @@ -11672,6 +11798,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_bitrate_mask mask; + unsigned int link_id = nl80211_link_id(info->attrs); struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -11683,11 +11810,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, wdev_lock(wdev); err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, &mask, - dev, true); + dev, true, link_id); if (err) goto out; - err = rdev_set_bitrate_mask(rdev, dev, NULL, &mask); + err = rdev_set_bitrate_mask(rdev, dev, link_id, NULL, &mask); out: wdev_unlock(wdev); return err; @@ -11812,7 +11939,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) return -EINVAL; wdev_lock(wdev); - if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) { + if (params.offchan && + !cfg80211_off_channel_oper_allowed(wdev, chandef.chan)) { wdev_unlock(wdev); return -EBUSY; } @@ -12030,12 +12158,13 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev, * connection is established and enough beacons received to calculate * the average. */ - if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && + if (!wdev->cqm_config->last_rssi_event_value && + wdev->links[0].client.current_bss && rdev->ops->get_station) { struct station_info sinfo = {}; u8 *mac_addr; - mac_addr = wdev->current_bss->pub.bssid; + mac_addr = wdev->links[0].client.current_bss->pub.bssid; err = rdev_get_station(rdev, dev, mac_addr, &sinfo); if (err) @@ -12298,7 +12427,7 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, &setup.beacon_rate, - dev, false); + dev, false, 0); if (err) return err; @@ -13268,7 +13397,7 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) rekey_data.akm = nla_get_u32(tb[NL80211_REKEY_DATA_AKM]); wdev_lock(wdev); - if (!wdev->current_bss) { + if (!wdev->connected) { err = -ENOTCONN; goto out; } @@ -14537,7 +14666,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (wdev->current_bss) + if (wdev->connected) break; err = -ENOTCONN; goto out; @@ -14710,13 +14839,13 @@ static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info) return -EINVAL; wdev_lock(wdev); - if (!wdev->current_bss) { + if (!wdev->connected) { ret = -ENOTCONN; goto out; } pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) { + if (memcmp(pmk_conf.aa, wdev->u.client.connected_addr, ETH_ALEN)) { ret = -EINVAL; goto out; } @@ -14844,9 +14973,13 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) case NL80211_IFTYPE_MESH_POINT: break; case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.current_bss) + break; + err = -ENOTCONN; + goto out; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (wdev->current_bss) + if (wdev->connected) break; err = -ENOTCONN; goto out; @@ -14882,12 +15015,14 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb, struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_ftm_responder_stats ftm_stats = {}; + unsigned int link_id = nl80211_link_id(info->attrs); struct sk_buff *msg; void *hdr; struct nlattr *ftm_stats_attr; int err; - if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval) + if (wdev->iftype != NL80211_IFTYPE_AP || + !wdev->links[link_id].ap.beacon_interval) return -EOPNOTSUPP; err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats); @@ -15017,7 +15152,8 @@ static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info) static int parse_tid_conf(struct cfg80211_registered_device *rdev, struct nlattr *attrs[], struct net_device *dev, struct cfg80211_tid_cfg *tid_conf, - struct genl_info *info, const u8 *peer) + struct genl_info *info, const u8 *peer, + unsigned int link_id) { struct netlink_ext_ack *extack = info->extack; u64 mask; @@ -15092,7 +15228,7 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev, attr = NL80211_TID_CONFIG_ATTR_TX_RATE; err = nl80211_parse_tx_bitrate_mask(info, attrs, attr, &tid_conf->txrate_mask, dev, - true); + true, link_id); if (err) return err; @@ -15119,6 +15255,7 @@ static int nl80211_set_tid_config(struct sk_buff *skb, { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct nlattr *attrs[NL80211_TID_CONFIG_ATTR_MAX + 1]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct cfg80211_tid_config *tid_config; struct nlattr *tid; @@ -15156,7 +15293,7 @@ static int nl80211_set_tid_config(struct sk_buff *skb, ret = parse_tid_conf(rdev, attrs, dev, &tid_config->tid_conf[conf_idx], - info, tid_config->peer); + info, tid_config->peer, link_id); if (ret) goto bad_tid_conf; @@ -15295,6 +15432,62 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, return rdev_set_fils_aad(rdev, dev, &fils_aad); } +static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) +{ + unsigned int link_id = nl80211_link_id(info->attrs); + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (!(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + break; + default: + return -EINVAL; + } + + if (!info->attrs[NL80211_ATTR_MAC] || + !is_valid_ether_addr(nla_data(info->attrs[NL80211_ATTR_MAC]))) + return -EINVAL; + + wdev_lock(wdev); + wdev->valid_links |= BIT(link_id); + ether_addr_copy(wdev->links[link_id].addr, + nla_data(info->attrs[NL80211_ATTR_MAC])); + wdev_unlock(wdev); + + return 0; +} + +static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) +{ + unsigned int link_id = nl80211_link_id(info->attrs); + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* cannot remove if there's no link */ + if (!info->attrs[NL80211_ATTR_MLO_LINK_ID]) + return -EINVAL; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + break; + default: + return -EINVAL; + } + + /* FIXME: stop the link operations first */ + + wdev_lock(wdev); + wdev->valid_links &= ~BIT(link_id); + eth_zero_addr(wdev->links[link_id].addr); + wdev_unlock(wdev); + + return 0; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -15307,6 +15500,8 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_CHECK_NETDEV_UP) #define NL80211_FLAG_CLEAR_SKB 0x20 #define NL80211_FLAG_NO_WIPHY_MTX 0x40 +#define NL80211_FLAG_MLO_VALID_LINK_ID 0x80 +#define NL80211_FLAG_MLO_UNSUPPORTED 0x100 #define INTERNAL_FLAG_SELECTORS(__sel) \ SELECTOR(__sel, NONE, 0) /* must be first */ \ @@ -15316,6 +15511,12 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_NEED_WDEV) \ SELECTOR(__sel, NETDEV, \ NL80211_FLAG_NEED_NETDEV) \ + SELECTOR(__sel, NETDEV_LINK, \ + NL80211_FLAG_NEED_NETDEV | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ + SELECTOR(__sel, NETDEV_NO_MLO, \ + NL80211_FLAG_NEED_NETDEV | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, WIPHY_RTNL, \ NL80211_FLAG_NEED_WIPHY | \ NL80211_FLAG_NEED_RTNL) \ @@ -15331,14 +15532,31 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_NEED_RTNL) \ SELECTOR(__sel, NETDEV_UP, \ NL80211_FLAG_NEED_NETDEV_UP) \ + SELECTOR(__sel, NETDEV_UP_LINK, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ + SELECTOR(__sel, NETDEV_UP_NO_MLO, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ + SELECTOR(__sel, NETDEV_UP_NO_MLO_CLEAR, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_CLEAR_SKB | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, NETDEV_UP_NOTMX, \ NL80211_FLAG_NEED_NETDEV_UP | \ NL80211_FLAG_NO_WIPHY_MTX) \ + SELECTOR(__sel, NETDEV_UP_NOTMX_NOMLO, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_NO_WIPHY_MTX | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, NETDEV_UP_CLEAR, \ NL80211_FLAG_NEED_NETDEV_UP | \ NL80211_FLAG_CLEAR_SKB) \ SELECTOR(__sel, WDEV_UP, \ NL80211_FLAG_NEED_WDEV_UP) \ + SELECTOR(__sel, WDEV_UP_LINK, \ + NL80211_FLAG_NEED_WDEV_UP | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ SELECTOR(__sel, WDEV_UP_RTNL, \ NL80211_FLAG_NEED_WDEV_UP | \ NL80211_FLAG_NEED_RTNL) \ @@ -15362,9 +15580,10 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = NULL; - struct wireless_dev *wdev; - struct net_device *dev; + struct wireless_dev *wdev = NULL; + struct net_device *dev = NULL; u32 internal_flags; + int err; if (WARN_ON(ops->internal_flags >= ARRAY_SIZE(nl80211_internal_flags))) return -EINVAL; @@ -15375,8 +15594,8 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, if (internal_flags & NL80211_FLAG_NEED_WIPHY) { rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); if (IS_ERR(rdev)) { - rtnl_unlock(); - return PTR_ERR(rdev); + err = PTR_ERR(rdev); + goto out_unlock; } info->user_ptr[0] = rdev; } else if (internal_flags & NL80211_FLAG_NEED_NETDEV || @@ -15384,17 +15603,18 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info), info->attrs); if (IS_ERR(wdev)) { - rtnl_unlock(); - return PTR_ERR(wdev); + err = PTR_ERR(wdev); + goto out_unlock; } dev = wdev->netdev; + dev_hold(dev); rdev = wiphy_to_rdev(wdev->wiphy); if (internal_flags & NL80211_FLAG_NEED_NETDEV) { if (!dev) { - rtnl_unlock(); - return -EINVAL; + err = -EINVAL; + goto out_unlock; } info->user_ptr[1] = dev; @@ -15404,14 +15624,44 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, if (internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && !wdev_running(wdev)) { - rtnl_unlock(); - return -ENETDOWN; + err = -ENETDOWN; + goto out_unlock; } - dev_hold(dev); info->user_ptr[0] = rdev; } + if (internal_flags & NL80211_FLAG_MLO_VALID_LINK_ID) { + struct nlattr *link_id = info->attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!wdev) { + err = -EINVAL; + goto out_unlock; + } + + /* MLO -> require valid link ID */ + if (wdev->valid_links && + (!link_id || + !(wdev->valid_links & BIT(nla_get_u16(link_id))))) { + err = -EINVAL; + goto out_unlock; + } + + /* non-MLO -> no link ID attribute accepted */ + if (!wdev->valid_links && link_id) { + err = -EINVAL; + goto out_unlock; + } + } + + if (internal_flags & NL80211_FLAG_MLO_UNSUPPORTED) { + if (info->attrs[NL80211_ATTR_MLO_LINK_ID] || + (wdev && wdev->valid_links)) { + err = -EINVAL; + goto out_unlock; + } + } + if (rdev && !(internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) { wiphy_lock(&rdev->wiphy); /* we keep the mutex locked until post_doit */ @@ -15421,6 +15671,10 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, rtnl_unlock(); return 0; +out_unlock: + rtnl_unlock(); + dev_put(dev); + return err; } static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, @@ -15636,6 +15890,7 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_key, .flags = GENL_UNS_ADMIN_PERM, + /* cannot use NL80211_FLAG_MLO_VALID_LINK_ID, depends on key */ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_CLEAR_SKB), }, @@ -15659,21 +15914,24 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_set_beacon, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_START_AP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_start_ap, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_STOP_AP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_stop_ap, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_GET_STATION, @@ -15939,7 +16197,9 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_remain_on_channel, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP), + /* FIXME: requiring a link ID here is probably not good */ + .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, @@ -15953,7 +16213,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_tx_bitrate_mask, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_REGISTER_FRAME, @@ -16002,7 +16263,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_channel, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_JOIN_MESH, @@ -16163,7 +16425,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_mac_acl, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_RADAR_DETECT, @@ -16171,7 +16434,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .doit = nl80211_start_radar_detection, .flags = GENL_UNS_ADMIN_PERM, .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NO_WIPHY_MTX), + NL80211_FLAG_NO_WIPHY_MTX | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, @@ -16217,7 +16481,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_channel_switch, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_VENDOR, @@ -16240,7 +16505,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_add_tx_ts, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_DEL_TX_TS, @@ -16301,7 +16567,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_get_ftm_responder_stats, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_PEER_MEASUREMENT_START, @@ -16333,7 +16600,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .cmd = NL80211_CMD_SET_TID_CONFIG, .doit = nl80211_set_tid_config, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_SET_SAR_SPECS, @@ -16357,6 +16625,19 @@ static const struct genl_small_ops nl80211_small_ops[] = { .flags = GENL_UNS_ADMIN_PERM, .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), }, + { + .cmd = NL80211_CMD_ADD_LINK, + .doit = nl80211_add_link, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + }, + { + .cmd = NL80211_CMD_REMOVE_LINK, + .doit = nl80211_remove_link, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), + }, }; static struct genl_family nl80211_fam __ro_after_init = { @@ -17984,23 +18265,37 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, } void cfg80211_ch_switch_notify(struct net_device *dev, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + unsigned int link_id) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ASSERT_WDEV_LOCK(wdev); + WARN_INVALID_LINK_ID(wdev, link_id); - trace_cfg80211_ch_switch_notify(dev, chandef); - - wdev->chandef = *chandef; - wdev->preset_chandef = *chandef; + trace_cfg80211_ch_switch_notify(dev, chandef, link_id); - if ((wdev->iftype == NL80211_IFTYPE_STATION || - wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && - !WARN_ON(!wdev->current_bss)) - cfg80211_update_assoc_bss_entry(wdev, chandef->chan); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (!WARN_ON(!wdev->links[link_id].client.current_bss)) + cfg80211_update_assoc_bss_entry(wdev, link_id, + chandef->chan); + break; + case NL80211_IFTYPE_MESH_POINT: + wdev->u.mesh.chandef = *chandef; + wdev->u.mesh.preset_chandef = *chandef; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + wdev->links[link_id].ap.chandef = *chandef; + break; + default: + WARN_ON(1); + break; + } cfg80211_sched_dfs_chan_update(rdev); diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c index 2d26a6d980bf..27a1732264f9 100644 --- a/net/wireless/ocb.c +++ b/net/wireless/ocb.c @@ -4,6 +4,7 @@ * * Copyright: (c) 2014 Czech Technical University in Prague * (c) 2014 Volkswagen Group Research + * Copyright (C) 2022 Intel Corporation * Author: Rostislav Lisovy * Funded by: Volkswagen Group Research */ @@ -34,7 +35,7 @@ int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, err = rdev_join_ocb(rdev, dev, setup); if (!err) - wdev->chandef = setup->chandef; + wdev->u.ocb.chandef = setup->chandef; return err; } @@ -69,7 +70,7 @@ int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, err = rdev_leave_ocb(rdev, dev); if (!err) - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + memset(&wdev->u.ocb.chandef, 0, sizeof(wdev->u.ocb.chandef)); return err; } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 439bcf52369c..d2300eff03ae 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018, 2021-2022 Intel Corporation + */ #ifndef __CFG80211_RDEV_OPS #define __CFG80211_RDEV_OPS @@ -172,11 +177,11 @@ static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev, } static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev) + struct net_device *dev, unsigned int link_id) { int ret; - trace_rdev_stop_ap(&rdev->wiphy, dev); - ret = rdev->ops->stop_ap(&rdev->wiphy, dev); + trace_rdev_stop_ap(&rdev->wiphy, dev, link_id); + ret = rdev->ops->stop_ap(&rdev->wiphy, dev, link_id); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -651,12 +656,14 @@ static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev, static inline int rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *peer, + struct net_device *dev, unsigned int link_id, + const u8 *peer, const struct cfg80211_bitrate_mask *mask) { int ret; - trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask); - ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); + trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, link_id, peer, mask); + ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, link_id, + peer, mask); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -944,12 +951,13 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, static inline int rdev_get_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_get_channel(&rdev->wiphy, wdev); - ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); + trace_rdev_get_channel(&rdev->wiphy, wdev, link_id); + ret = rdev->ops->get_channel(&rdev->wiphy, wdev, link_id, chandef); trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); return ret; @@ -1107,12 +1115,14 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev, static inline int rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, - struct net_device *dev, struct cfg80211_chan_def *chandef) + struct net_device *dev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef); - ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef); + trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef); + ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef); trace_rdev_return_int(&rdev->wiphy, ret); return ret; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 58e83ce642ad..c7383ede794f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -5,7 +5,7 @@ * Copyright 2008-2011 Luis R. Rodriguez * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2370,6 +2370,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); enum nl80211_iftype iftype; bool ret; + int link; wdev_lock(wdev); iftype = wdev->iftype; @@ -2378,62 +2379,83 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) if (!wdev->netdev || !netif_running(wdev->netdev)) goto wdev_inactive_unlock; - switch (iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_MESH_POINT: - if (!wdev->beacon_interval) - goto wdev_inactive_unlock; - chandef = wdev->chandef; - break; - case NL80211_IFTYPE_ADHOC: - if (!wdev->ssid_len) - goto wdev_inactive_unlock; - chandef = wdev->chandef; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss || - !wdev->current_bss->pub.channel) - goto wdev_inactive_unlock; - - if (!rdev->ops->get_channel || - rdev_get_channel(rdev, wdev, &chandef)) - cfg80211_chandef_create(&chandef, - wdev->current_bss->pub.channel, - NL80211_CHAN_NO_HT); - break; - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_P2P_DEVICE: - /* no enforcement required */ - break; - default: - /* others not implemented for now */ - WARN_ON(1); - break; - } + for (link = 0; link < ARRAY_SIZE(wdev->links); link++) { + struct ieee80211_channel *chan; - wdev_unlock(wdev); + if (!wdev->valid_links && link > 0) + break; + if (!(wdev->valid_links & BIT(link))) + continue; + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + if (!wdev->u.mesh.beacon_interval) + continue; + chandef = wdev->u.mesh.chandef; + break; + case NL80211_IFTYPE_ADHOC: + if (!wdev->u.ibss.ssid_len) + continue; + chandef = wdev->u.ibss.chandef; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + /* Maybe we could consider disabling that link only? */ + if (!wdev->links[link].client.current_bss) + continue; - switch (iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - wiphy_lock(wiphy); - ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype); - wiphy_unlock(wiphy); + chan = wdev->links[link].client.current_bss->pub.channel; + if (!chan) + continue; - return ret; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - return cfg80211_chandef_usable(wiphy, &chandef, - IEEE80211_CHAN_DISABLED); - default: - break; + if (!rdev->ops->get_channel || + rdev_get_channel(rdev, wdev, link, &chandef)) + cfg80211_chandef_create(&chandef, chan, + NL80211_CHAN_NO_HT); + break; + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_DEVICE: + /* no enforcement required */ + break; + default: + /* others not implemented for now */ + WARN_ON(1); + break; + } + + wdev_unlock(wdev); + + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + wiphy_lock(wiphy); + ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, + iftype); + wiphy_unlock(wiphy); + + if (!ret) + return ret; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + ret = cfg80211_chandef_usable(wiphy, &chandef, + IEEE80211_CHAN_DISABLED); + if (!ret) + return ret; + break; + default: + break; + } + + wdev_lock(wdev); } + wdev_unlock(wdev); + return true; wdev_inactive_unlock: @@ -4215,8 +4237,17 @@ static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) * In both cases we should end the CAC on the wdev. */ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (wdev->cac_started && - !cfg80211_chandef_dfs_usable(&rdev->wiphy, &wdev->chandef)) + struct cfg80211_chan_def *chandef; + + if (!wdev->cac_started) + continue; + + /* FIXME: radar detection is tied to link 0 for now */ + chandef = wdev_chandef(wdev, 0); + if (!chandef) + continue; + + if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef)) rdev_end_cac(rdev, wdev->netdev); } } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 6d82bd9eaf8c..0134e5d5c81a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -5,7 +5,7 @@ * Copyright 2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -2617,7 +2617,8 @@ void cfg80211_bss_iter(struct wiphy *wiphy, spin_lock_bh(&rdev->bss_lock); list_for_each_entry(bss, &rdev->bss_list, list) { - if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel)) + if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel, + false)) iter(wiphy, &bss->pub, iter_data); } @@ -2626,11 +2627,12 @@ void cfg80211_bss_iter(struct wiphy *wiphy, EXPORT_SYMBOL(cfg80211_bss_iter); void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, + unsigned int link_id, struct ieee80211_channel *chan) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss *cbss = wdev->current_bss; + struct cfg80211_internal_bss *cbss = wdev->links[link_id].client.current_bss; struct cfg80211_internal_bss *new = NULL; struct cfg80211_internal_bss *bss; struct cfg80211_bss *nontrans_bss; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index ff4d48fcbfb2..35602201057b 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -5,7 +5,7 @@ * (for nl80211's connect() and wext) * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020 Intel Corporation. All rights reserved. + * Copyright (C) 2009, 2020, 2022 Intel Corporation. All rights reserved. * Copyright 2017 Intel Deutschland GmbH */ @@ -454,6 +454,20 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev) schedule_work(&rdev->conn_work); } +static void cfg80211_wdev_release_bsses(struct wireless_dev *wdev) +{ + unsigned int link; + + for_each_valid_link(wdev, link) { + if (!wdev->links[link].client.current_bss) + continue; + cfg80211_unhold_bss(wdev->links[link].client.current_bss); + cfg80211_put_bss(wdev->wiphy, + &wdev->links[link].client.current_bss->pub); + wdev->links[link].client.current_bss = NULL; + } +} + static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, const u8 *ies, size_t ies_len, const u8 **out_ies, size_t *out_ies_len) @@ -521,12 +535,11 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, if (!rdev->ops->auth || !rdev->ops->assoc) return -EOPNOTSUPP; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + cfg80211_wdev_release_bsses(wdev); + if (wdev->connected) { cfg80211_sme_free(wdev); + wdev->connected = false; } if (wdev->conn) @@ -563,8 +576,8 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, wdev->conn->auto_auth = false; } - wdev->conn->params.ssid = wdev->ssid; - wdev->conn->params.ssid_len = wdev->ssid_len; + wdev->conn->params.ssid = wdev->u.client.ssid; + wdev->conn->params.ssid_len = wdev->u.client.ssid_len; /* see if we have the bss already */ bss = cfg80211_get_conn_bss(wdev); @@ -648,7 +661,7 @@ static bool cfg80211_is_all_idle(void) list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { wdev_lock(wdev); - if (wdev->conn || wdev->current_bss || + if (wdev->conn || wdev->connected || cfg80211_beaconing_iface_active(wdev)) is_all_idle = false; wdev_unlock(wdev); @@ -668,7 +681,6 @@ static void disconnect_work(struct work_struct *work) DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); - /* * API calls for drivers implementing connect/disconnect and * SME event handling @@ -729,23 +741,19 @@ void __cfg80211_connect_result(struct net_device *dev, if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, - wdev->ssid, wdev->ssid_len, + wdev->u.client.ssid, wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (cr->bss) cfg80211_hold_bss(bss_from_pub(cr->bss)); } - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; - } + cfg80211_wdev_release_bsses(wdev); if (cr->status != WLAN_STATUS_SUCCESS) { kfree_sensitive(wdev->connect_keys); wdev->connect_keys = NULL; - wdev->ssid_len = 0; + wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; if (cr->bss) { cfg80211_unhold_bss(bss_from_pub(cr->bss)); @@ -758,7 +766,9 @@ void __cfg80211_connect_result(struct net_device *dev, if (WARN_ON(!cr->bss)) return; - wdev->current_bss = bss_from_pub(cr->bss); + wdev->links[0].client.current_bss = bss_from_pub(cr->bss); + wdev->connected = true; + ether_addr_copy(wdev->u.client.connected_addr, cr->bss->bssid); if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); @@ -801,7 +811,7 @@ void cfg80211_connect_done(struct net_device *dev, found = cfg80211_get_bss(wdev->wiphy, NULL, params->bss->bssid, - wdev->ssid, wdev->ssid_len, + wdev->u.client.ssid, wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (found) { @@ -906,18 +916,17 @@ void __cfg80211_roamed(struct wireless_dev *wdev, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) goto out; - if (WARN_ON(!wdev->current_bss)) + if (WARN_ON(!wdev->connected)) goto out; - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + cfg80211_wdev_release_bsses(wdev); if (WARN_ON(!info->bss)) return; cfg80211_hold_bss(bss_from_pub(info->bss)); - wdev->current_bss = bss_from_pub(info->bss); + wdev->links[0].client.current_bss = bss_from_pub(info->bss); + ether_addr_copy(wdev->u.client.connected_addr, info->bss->bssid); wdev->unprot_beacon_reported = 0; nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), @@ -963,8 +972,8 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, if (!info->bss) { info->bss = cfg80211_get_bss(wdev->wiphy, info->channel, - info->bssid, wdev->ssid, - wdev->ssid_len, + info->bssid, wdev->u.client.ssid, + wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); } @@ -1034,8 +1043,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(!wdev->current_bss) || - WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + if (WARN_ON(!wdev->connected) || + WARN_ON(!ether_addr_equal(wdev->u.client.connected_addr, bssid))) return; nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev, @@ -1087,13 +1096,9 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) return; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - } - - wdev->current_bss = NULL; - wdev->ssid_len = 0; + cfg80211_wdev_release_bsses(wdev); + wdev->connected = false; + wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; kfree_sensitive(wdev->connect_keys); wdev->connect_keys = NULL; @@ -1182,19 +1187,20 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, * already connected, so reject a new SSID unless it's the * same (which is the case for re-association.) */ - if (wdev->ssid_len && - (wdev->ssid_len != connect->ssid_len || - memcmp(wdev->ssid, connect->ssid, wdev->ssid_len))) + if (wdev->u.client.ssid_len && + (wdev->u.client.ssid_len != connect->ssid_len || + memcmp(wdev->u.client.ssid, connect->ssid, wdev->u.client.ssid_len))) return -EALREADY; /* * If connected, reject (re-)association unless prev_bssid * matches the current BSSID. */ - if (wdev->current_bss) { + if (wdev->connected) { if (!prev_bssid) return -EALREADY; - if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) + if (!ether_addr_equal(prev_bssid, + wdev->u.client.connected_addr)) return -ENOTCONN; } @@ -1245,8 +1251,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, } wdev->connect_keys = connkeys; - memcpy(wdev->ssid, connect->ssid, connect->ssid_len); - wdev->ssid_len = connect->ssid_len; + memcpy(wdev->u.client.ssid, connect->ssid, connect->ssid_len); + wdev->u.client.ssid_len = connect->ssid_len; wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : IEEE80211_BSS_TYPE_ESS; @@ -1262,8 +1268,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, * This could be reassoc getting refused, don't clear * ssid_len in that case. */ - if (!wdev->current_bss) - wdev->ssid_len = 0; + if (!wdev->connected) + wdev->u.client.ssid_len = 0; return err; } @@ -1287,7 +1293,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, err = cfg80211_sme_disconnect(wdev, reason); else if (!rdev->ops->disconnect) cfg80211_mlme_down(rdev, dev); - else if (wdev->ssid_len) + else if (wdev->u.client.ssid_len) err = rdev_disconnect(rdev, dev, reason); /* @@ -1295,8 +1301,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, * in which case cfg80211_disconnected() will take care of * this later. */ - if (!wdev->current_bss) - wdev->ssid_len = 0; + if (!wdev->connected) + wdev->u.client.ssid_len = 0; return err; } @@ -1320,7 +1326,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - __cfg80211_stop_ap(rdev, wdev->netdev, false); + __cfg80211_stop_ap(rdev, wdev->netdev, -1, false); break; case NL80211_IFTYPE_MESH_POINT: __cfg80211_leave_mesh(rdev, wdev->netdev); @@ -1332,7 +1338,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) * ops->disconnect not implemented. Otherwise we can * use cfg80211_disconnect. */ - if (rdev->ops->disconnect || wdev->current_bss) + if (rdev->ops->disconnect || wdev->connected) cfg80211_disconnect(rdev, wdev->netdev, WLAN_REASON_DEAUTH_LEAVING, true); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 228079d7690a..3b2c956b8d78 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -569,6 +569,7 @@ TRACE_EVENT(rdev_start_ap, __field(bool, privacy) __field(enum nl80211_auth_type, auth_type) __field(int, inactivity_timeout) + __field(unsigned int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; @@ -583,16 +584,17 @@ TRACE_EVENT(rdev_start_ap, __entry->inactivity_timeout = settings->inactivity_timeout; memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); memcpy(__entry->ssid, settings->ssid, settings->ssid_len); + __entry->link_id = settings->beacon.link_id; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, " CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " "hidden ssid: %d, wpa versions: %u, privacy: %s, " - "auth type: %d, inactivity timeout: %d", + "auth type: %d, inactivity timeout: %d, link_id: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, __entry->beacon_interval, __entry->dtim_period, __entry->hidden_ssid, __entry->wpa_ver, BOOL_TO_STR(__entry->privacy), __entry->auth_type, - __entry->inactivity_timeout) + __entry->inactivity_timeout, __entry->link_id) ); TRACE_EVENT(rdev_change_beacon, @@ -602,6 +604,7 @@ TRACE_EVENT(rdev_change_beacon, TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY + __field(int, link_id) __dynamic_array(u8, head, info ? info->head_len : 0) __dynamic_array(u8, tail, info ? info->tail_len : 0) __dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0) @@ -615,6 +618,7 @@ TRACE_EVENT(rdev_change_beacon, WIPHY_ASSIGN; NETDEV_ASSIGN; if (info) { + __entry->link_id = info->link_id; if (info->head) memcpy(__get_dynamic_array(head), info->head, info->head_len); @@ -635,9 +639,30 @@ TRACE_EVENT(rdev_change_beacon, if (info->probe_resp) memcpy(__get_dynamic_array(probe_resp), info->probe_resp, info->probe_resp_len); + } else { + __entry->link_id = -1; } ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id:%d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id) +); + +TRACE_EVENT(rdev_stop_ap, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id), + TP_ARGS(wiphy, netdev, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(unsigned int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->link_id = link_id; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id) ); DECLARE_EVENT_CLASS(wiphy_netdev_evt, @@ -654,11 +679,6 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt, TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); -DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), - TP_ARGS(wiphy, netdev) -); - DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), TP_ARGS(wiphy, netdev) @@ -1619,20 +1639,24 @@ TRACE_EVENT(rdev_testmode_dump, TRACE_EVENT(rdev_set_bitrate_mask, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id, const u8 *peer, const struct cfg80211_bitrate_mask *mask), - TP_ARGS(wiphy, netdev, peer, mask), + TP_ARGS(wiphy, netdev, link_id, peer, mask), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY + __field(unsigned int, link_id) MAC_ENTRY(peer) ), TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; + __entry->link_id = link_id; MAC_ASSIGN(peer, peer); ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, - WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d, peer: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id, + MAC_PR_ARG(peer)) ); TRACE_EVENT(rdev_update_mgmt_frame_registrations, @@ -2040,9 +2064,22 @@ TRACE_EVENT(rdev_set_noack_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); -DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, - TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev) +TRACE_EVENT(rdev_get_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + __field(unsigned int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + __entry->link_id = link_id; + ), + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id) ); TRACE_EVENT(rdev_return_chandef, @@ -2296,20 +2333,24 @@ TRACE_EVENT(rdev_set_qos_map, TRACE_EVENT(rdev_set_ap_chanwidth, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id, struct cfg80211_chan_def *chandef), - TP_ARGS(wiphy, netdev, chandef), + TP_ARGS(wiphy, netdev, link_id, chandef), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY CHAN_DEF_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->link_id = link_id; ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, - WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, + __entry->link_id) ); TRACE_EVENT(rdev_add_tx_ts, @@ -3022,18 +3063,21 @@ TRACE_EVENT(cfg80211_chandef_dfs_required, TRACE_EVENT(cfg80211_ch_switch_notify, TP_PROTO(struct net_device *netdev, - struct cfg80211_chan_def *chandef), - TP_ARGS(netdev, chandef), + struct cfg80211_chan_def *chandef, + unsigned int link_id), + TP_ARGS(netdev, chandef, link_id), TP_STRUCT__entry( NETDEV_ENTRY CHAN_DEF_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->link_id = link_id; ), - TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, - NETDEV_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id) ); TRACE_EVENT(cfg80211_ch_switch_started_notify, diff --git a/net/wireless/util.c b/net/wireless/util.c index a60d7d638e72..b7257862e0fe 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -5,7 +5,7 @@ * Copyright 2007-2009 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -1041,7 +1041,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EBUSY; dev->ieee80211_ptr->use_4addr = false; - dev->ieee80211_ptr->mesh_id_up_len = 0; wdev_lock(dev->ieee80211_ptr); rdev_set_qos_map(rdev, dev, NULL); wdev_unlock(dev->ieee80211_ptr); @@ -1049,7 +1048,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, switch (otype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - cfg80211_stop_ap(rdev, dev, true); + cfg80211_stop_ap(rdev, dev, -1, true); break; case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, false); @@ -1073,6 +1072,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, cfg80211_process_rdev_events(rdev); cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); + + memset(&dev->ieee80211_ptr->u, 0, + sizeof(dev->ieee80211_ptr->u)); + memset(&dev->ieee80211_ptr->links, 0, + sizeof(dev->ieee80211_ptr->links)); } err = rdev_change_virtual_intf(rdev, dev, ntype, params); @@ -1930,6 +1934,24 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); +static int cfg80211_wdev_bi(struct wireless_dev *wdev) +{ + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + WARN_ON(wdev->valid_links); + return wdev->links[0].ap.beacon_interval; + case NL80211_IFTYPE_MESH_POINT: + return wdev->u.mesh.beacon_interval; + case NL80211_IFTYPE_ADHOC: + return wdev->u.ibss.beacon_interval; + default: + break; + } + + return 0; +} + static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, u32 *beacon_int_gcd, bool *beacon_int_different) @@ -1940,19 +1962,27 @@ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, *beacon_int_different = false; list_for_each_entry(wdev, &wiphy->wdev_list, list) { - if (!wdev->beacon_interval) + int wdev_bi; + + /* this feature isn't supported with MLO */ + if (wdev->valid_links) + continue; + + wdev_bi = cfg80211_wdev_bi(wdev); + + if (!wdev_bi) continue; if (!*beacon_int_gcd) { - *beacon_int_gcd = wdev->beacon_interval; + *beacon_int_gcd = wdev_bi; continue; } - if (wdev->beacon_interval == *beacon_int_gcd) + if (wdev_bi == *beacon_int_gcd) continue; *beacon_int_different = true; - *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); + *beacon_int_gcd = gcd(*beacon_int_gcd, wdev_bi); } if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index a32065d600a1..a9767bfe7330 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -7,7 +7,7 @@ * we directly assign the wireless handlers of wireless interfaces. * * Copyright 2008-2009 Johannes Berg - * Copyright (C) 2019-2021 Intel Corporation + * Copyright (C) 2019-2022 Intel Corporation */ #include @@ -415,6 +415,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, int err, i; bool rejoin = false; + if (wdev->valid_links) + return -EINVAL; + if (pairwise && !addr) return -EINVAL; @@ -437,7 +440,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return -EOPNOTSUPP; if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - if (!wdev->current_bss) + if (!wdev->connected) return -ENOLINK; if (!rdev->ops->set_default_mgmt_key) @@ -450,7 +453,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (remove) { err = 0; - if (wdev->current_bss) { + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) { /* * If removing the current TX key, we will need to * join a new IBSS without the privacy bit clear. @@ -501,7 +506,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return -EINVAL; err = 0; - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && params->cipher != WLAN_CIPHER_SUITE_WEP104) @@ -526,7 +533,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || params->cipher == WLAN_CIPHER_SUITE_WEP104) && (tx_key || (!addr && wdev->wext.default_key == -1))) { - if (wdev->current_bss) { + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) { /* * If we are getting a new TX key from not having * had one before we need to join a new IBSS with @@ -549,7 +558,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_set_default_mgmt_key(rdev, dev, idx); if (!err) wdev->wext.default_mgmt_key = idx; @@ -595,6 +606,11 @@ static int cfg80211_wext_siwencode(struct net_device *dev, return -EOPNOTSUPP; wiphy_lock(&rdev->wiphy); + if (wdev->valid_links) { + err = -EOPNOTSUPP; + goto out; + } + idx = erq->flags & IW_ENCODE_INDEX; if (idx == 0) { idx = wdev->wext.default_key; @@ -613,7 +629,9 @@ static int cfg80211_wext_siwencode(struct net_device *dev, /* No key data - just set the default TX key index */ err = 0; wdev_lock(wdev); - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_set_default_key(rdev, dev, idx, true, true); if (!err) @@ -865,7 +883,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, break; } - ret = rdev_get_channel(rdev, wdev, &chandef); + ret = rdev_get_channel(rdev, wdev, 0, &chandef); if (ret) break; freq->m = chandef.chan->center_freq; @@ -1270,7 +1288,10 @@ static int cfg80211_wext_siwrate(struct net_device *dev, return -EINVAL; wiphy_lock(&rdev->wiphy); - ret = rdev_set_bitrate_mask(rdev, dev, NULL, &mask); + if (dev->ieee80211_ptr->valid_links) + ret = -EOPNOTSUPP; + else + ret = rdev_set_bitrate_mask(rdev, dev, 0, NULL, &mask); wiphy_unlock(&rdev->wiphy); return ret; @@ -1294,8 +1315,9 @@ static int cfg80211_wext_giwrate(struct net_device *dev, err = 0; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); + if (!wdev->valid_links && wdev->links[0].client.current_bss) + memcpy(addr, wdev->links[0].client.current_bss->pub.bssid, + ETH_ALEN); else err = -EOPNOTSUPP; wdev_unlock(wdev); @@ -1339,11 +1361,11 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) /* Grab BSSID of current BSS, if any */ wdev_lock(wdev); - if (!wdev->current_bss) { + if (wdev->valid_links || !wdev->links[0].client.current_bss) { wdev_unlock(wdev); return NULL; } - memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + memcpy(bssid, wdev->links[0].client.current_bss->pub.bssid, ETH_ALEN); wdev_unlock(wdev); memset(&sinfo, 0, sizeof(sinfo)); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index cd09a9042261..68f45afc352d 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -3,7 +3,7 @@ * cfg80211 wext compat for managed mode. * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020-2021 Intel Corporation. + * Copyright (C) 2009, 2020-2022 Intel Corporation */ #include @@ -124,9 +124,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; + if (wdev->valid_links) + return -EOPNOTSUPP; + wdev_lock(wdev); - if (wdev->current_bss) - chan = wdev->current_bss->pub.channel; + if (wdev->links[0].client.current_bss) + chan = wdev->links[0].client.current_bss->pub.channel; else if (wdev->wext.connect.channel) chan = wdev->wext.connect.channel; wdev_unlock(wdev); @@ -208,15 +211,19 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; + if (wdev->valid_links) + return -EINVAL; + data->flags = 0; wdev_lock(wdev); - if (wdev->current_bss) { + if (wdev->links[0].client.current_bss) { const struct element *ssid_elem; rcu_read_lock(); - ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, - WLAN_EID_SSID); + ssid_elem = ieee80211_bss_get_elem( + &wdev->links[0].client.current_bss->pub, + WLAN_EID_SSID); if (ssid_elem) { data->flags = 1; data->length = ssid_elem->datalen; @@ -300,8 +307,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + if (wdev->valid_links) { + wdev_unlock(wdev); + return -EOPNOTSUPP; + } + if (wdev->links[0].client.current_bss) + memcpy(ap_addr->sa_data, + wdev->links[0].client.current_bss->pub.bssid, + ETH_ALEN); else eth_zero_addr(ap_addr->sa_data); wdev_unlock(wdev); -- cgit v1.2.3 From d0a9123ef548def5c8880e83e5df948eb5b55c62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 May 2022 13:26:44 +0200 Subject: wifi: mac80211: move some future per-link data to bss_conf To add MLD, reuse the bss_conf structure later for per-link information, so move some things into it that are per link. Most transformations were done with the following spatch: @@ expression sdata; identifier var = { chanctx_conf, mu_mimo_owner, csa_active, color_change_active, color_change_color }; @@ -sdata->vif.var +sdata->vif.bss_conf.var @@ struct ieee80211_vif *vif; identifier var = { chanctx_conf, mu_mimo_owner, csa_active, color_change_active, color_change_color }; @@ -vif->var +vif->bss_conf.var Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 8 ++--- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 12 +++---- drivers/net/wireless/ath/ath11k/wmi.c | 4 +-- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 6 ++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 4 +-- .../net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 10 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++--- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 4 +-- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 22 +++++++----- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 +-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 10 +++--- drivers/net/wireless/ti/wlcore/main.c | 2 +- include/net/mac80211.h | 40 ++++++++++----------- net/mac80211/airtime.c | 4 +-- net/mac80211/cfg.c | 40 ++++++++++----------- net/mac80211/chan.c | 39 ++++++++++---------- net/mac80211/driver-ops.h | 2 +- net/mac80211/ethtool.c | 4 +-- net/mac80211/ibss.c | 10 +++--- net/mac80211/ieee80211_i.h | 6 ++-- net/mac80211/iface.c | 8 ++--- net/mac80211/main.c | 4 +-- net/mac80211/mesh.c | 14 ++++---- net/mac80211/mlme.c | 42 +++++++++++----------- net/mac80211/ocb.c | 3 +- net/mac80211/offchannel.c | 6 ++-- net/mac80211/rate.c | 5 +-- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/tdls.c | 6 ++-- net/mac80211/tx.c | 28 +++++++-------- net/mac80211/util.c | 16 ++++----- net/mac80211/vht.c | 6 ++-- 45 files changed, 209 insertions(+), 202 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b8461501221a..8a075a711b71 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3840,7 +3840,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, switch (txrate.flags) { case WMI_RATE_PREAMBLE_OFDM: if (arsta->arvif && arsta->arvif->vif) - conf = rcu_dereference(arsta->arvif->vif->chanctx_conf); + conf = rcu_dereference(arsta->arvif->vif->bss_conf.chanctx_conf); if (conf && conf->def.chan->band == NL80211_BAND_5GHZ) arsta->tx_info.status.rates[0].idx = rate_idx - 4; break; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a04e18250dae..42c657b8b73e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -659,7 +659,7 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; @@ -2028,7 +2028,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return; - if (!vif->csa_active) + if (!vif->bss_conf.csa_active) return; if (!arvif->is_up) @@ -8832,7 +8832,7 @@ ath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, { struct ath10k_mac_change_chanctx_arg *arg = data; - if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx) + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) return; arg->n_vifs++; @@ -8845,7 +8845,7 @@ ath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ath10k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; - ctx = rcu_access_pointer(vif->chanctx_conf); + ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); if (ctx != arg->ctx) return; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7efbe03fbca8..876410a47d1d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -205,7 +205,7 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, } arvif = ath10k_get_arvif(ar, vdev_id); - if (arvif && arvif->is_up && arvif->vif->csa_active) + if (arvif && arvif->is_up && arvif->vif->bss_conf.csa_active) ieee80211_queue_work(ar->hw, &arvif->ap_csa_work); kfree(tb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cd438f76f284..af19cab24c76 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3882,7 +3882,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) * Once CSA counter is completed stop sending beacons until * actual channel switch is done */ - if (arvif->vif->csa_active && + if (arvif->vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { ieee80211_csa_finish(arvif->vif); continue; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 42d2e8cf8125..f28e7feca318 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -505,7 +505,7 @@ static int ath11k_mac_vif_chan(struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; @@ -1398,10 +1398,10 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) { struct ieee80211_vif *vif = arvif->vif; - if (!vif->color_change_active && !arvif->bcca_zero_sent) + if (!vif->bss_conf.color_change_active && !arvif->bcca_zero_sent) return; - if (vif->color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { + if (vif->bss_conf.color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { arvif->bcca_zero_sent = true; ieee80211_color_change_finish(vif); return; @@ -1409,7 +1409,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) arvif->bcca_zero_sent = false; - if (vif->color_change_active) + if (vif->bss_conf.color_change_active) ieee80211_beacon_update_cntdwn(vif); ath11k_mac_setup_bcn_tmpl(arvif); } @@ -6849,7 +6849,7 @@ ath11k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, { struct ath11k_mac_change_chanctx_arg *arg = data; - if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx) + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) return; arg->n_vifs++; @@ -6862,7 +6862,7 @@ ath11k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ath11k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; - ctx = rcu_access_pointer(vif->chanctx_conf); + ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); if (ctx != arg->ctx) return; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index f69918b9452a..f2d5e07dc148 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1700,7 +1700,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, cmd->vdev_id = vdev_id; cmd->tim_ie_offset = offs->tim_offset; - if (vif->csa_active) { + if (vif->bss_conf.csa_active) { cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; } @@ -7475,7 +7475,7 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab, continue; } - if (arvif->is_up && arvif->vif->csa_active) + if (arvif->is_up && arvif->vif->bss_conf.csa_active) ieee80211_csa_finish(arvif->vif); } rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 72e2e71aac0e..8b1b966bcef1 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -362,7 +362,7 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) { - if (!vif || !vif->csa_active) + if (!vif || !vif->bss_conf.csa_active) return false; if (!ieee80211_beacon_cntdwn_is_complete(vif)) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index c745897aa3d6..468bc934d848 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -511,7 +511,7 @@ bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) struct ieee80211_vif *vif; vif = priv->csa_vif; - if (!vif || !vif->csa_active) + if (!vif || !vif->bss_conf.csa_active) return false; if (!ieee80211_beacon_cntdwn_is_complete(vif)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 9b194cb8d65e..8760f2c73369 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2020 Intel Corporation + * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH */ #include @@ -106,7 +106,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!chanctx_conf || chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) { @@ -283,7 +283,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 61f9136a333d..8edc8646a23a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -731,7 +731,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EINVAL; rcu_read_lock(); - ctx = rcu_dereference(vif->chanctx_conf); + ctx = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!ctx)) { rcu_read_unlock(); return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 7d9faeffd154..78d8b37eb71a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -234,7 +234,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, } rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (chanctx_conf) pos += scnprintf(buf+pos, bufsz-pos, "idle rx chains %d, active rx chains: %d\n", @@ -597,7 +597,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); /* make sure the channel context is assigned */ if (!chanctx_conf) { rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 9729680476fd..e862d1b43f21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -398,7 +398,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } rcu_read_lock(); - pctx = rcu_dereference(vif->chanctx_conf); + pctx = rcu_dereference(vif->bss_conf.chanctx_conf); /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care * about changes in the ctx after releasing the lock because the driver * is still protected by the mutex. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 56fa20596f16..7756ac0faf3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -481,7 +481,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, eth_broadcast_addr(cmd->bssid_addr); rcu_read_lock(); - chanctx = rcu_dereference(vif->chanctx_conf); + chanctx = rcu_dereference(vif->bss_conf.chanctx_conf); iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band : NL80211_BAND_2GHZ, &cck_ack_rates, &ofdm_ack_rates); @@ -934,7 +934,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, /* Enable FILS on PSC channels only */ rcu_read_lock(); - ctx = rcu_dereference(vif->chanctx_conf); + ctx = rcu_dereference(vif->bss_conf.chanctx_conf); channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq); WARN_ON(channel == 0); if (cfg80211_channel_is_psc(ctx->def.chan) && @@ -1335,7 +1335,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); - if (unlikely(csa_vif && csa_vif->csa_active)) + if (unlikely(csa_vif && csa_vif->bss_conf.csa_active)) iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2, (status == TX_STATUS_SUCCESS)); @@ -1558,7 +1558,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, switch (vif->type) { case NL80211_IFTYPE_AP: csa_vif = rcu_dereference(mvm->csa_vif); - if (WARN_ON(!csa_vif || !csa_vif->csa_active || + if (WARN_ON(!csa_vif || !csa_vif->bss_conf.csa_active || csa_vif != vif)) goto out_unlock; @@ -1587,7 +1587,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, */ if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF, - 0) && !vif->csa_active) { + 0) && !vif->bss_conf.csa_active) { IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n"); iwl_mvm_cancel_channel_switch(mvm, vif, mac_id); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index bb9bd2165355..c5626ff83805 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1768,7 +1768,7 @@ static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - if (vif->mu_mimo_owner) { + if (vif->bss_conf.mu_mimo_owner) { struct iwl_mu_group_mgmt_notif *notif = _data; /* @@ -1965,7 +1965,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; @@ -2337,7 +2337,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * However, on HW restart we should restore this data. */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) { + (changes & BSS_CHANGED_MU_GROUPS) && vif->bss_conf.mu_mimo_owner) { ret = iwl_mvm_update_mu_groups(mvm, vif); if (ret) IWL_ERR(mvm, @@ -4004,7 +4004,7 @@ static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac, { struct iwl_mvm_ftm_responder_iter_data *data = _data; - if (rcu_access_pointer(vif->chanctx_conf) == data->ctx && + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) == data->ctx && vif->type == NL80211_IFTYPE_AP && vif->bss_conf.ftmr_params) data->responder = true; } @@ -4631,7 +4631,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); - if (WARN_ONCE(csa_vif && csa_vif->csa_active, + if (WARN_ONCE(csa_vif && csa_vif->bss_conf.csa_active, "Another CSA is already in progress")) { ret = -EBUSY; goto out_unlock; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index b9bd81242b21..afdf3bb523e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -283,7 +283,7 @@ static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) bool radar_detect = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); WARN_ON(!chanctx_conf); if (chanctx_conf) { chan = chanctx_conf->def.chan; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 974eeecc9153..303975f9e2b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1980,7 +1980,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, #endif rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) band = NUM_NL80211_BANDS; else diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index bf04326e35ff..674dd137fb9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2020, 2022 Intel Corporation */ #include #include "mvm.h" @@ -380,7 +380,7 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, type == TDLS_MOVE_CH) { /* we need to return to base channel */ struct ieee80211_chanctx_conf *chanctx = - rcu_dereference(vif->chanctx_conf); + rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx)) { rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 6edf2b79db43..4f0794a45bf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -123,7 +123,7 @@ static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) rcu_read_lock(); csa_vif = rcu_dereference(mvm->csa_vif); - if (!csa_vif || !csa_vif->csa_active) + if (!csa_vif || !csa_vif->bss_conf.csa_active) goto out_unlock; IWL_DEBUG_TE(mvm, "CSA NOA started\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8125bb76f59e..f9e08b339e0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1959,7 +1959,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid, if (mvmsta->vif) chanctx_conf = - rcu_dereference(mvmsta->vif->chanctx_conf); + rcu_dereference(mvmsta->vif->bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) goto out; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bd408d260e9c..5905803893b8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -888,7 +888,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -921,7 +921,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -1464,11 +1464,11 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, { struct tx_iter_data *data = _data; - if (!vif->chanctx_conf) + if (!vif->bss_conf.chanctx_conf) return; if (!hwsim_chans_compat(data->channel, - rcu_dereference(vif->chanctx_conf)->def.chan)) + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan)) return; data->receive = true; @@ -1686,7 +1686,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } else if (txi->hw_queue == 4) { channel = data->tmp_chan; } else { - chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); + struct ieee80211_bss_conf *bss_conf; + + bss_conf = &txi->control.vif->bss_conf; + + chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); if (chanctx_conf) { channel = chanctx_conf->def.chan; confbw = chanctx_conf->def.width; @@ -1935,14 +1939,14 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, } mac80211_hwsim_tx_frame(hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { mac80211_hwsim_tx_frame(hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); } - if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) ieee80211_csa_finish(vif); } @@ -2204,7 +2208,7 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!WARN_ON(!chanctx_conf)) confbw = chanctx_conf->def.width; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 18b5de55334c..5f75a8945a6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1459,7 +1459,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power); static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) ieee80211_csa_finish(vif); } @@ -1481,7 +1481,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76_dev *dev = priv; - if (!vif->csa_active) + if (!vif->bss_conf.csa_active) return; dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 97e2a85cb728..8fb6c9d735dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -363,7 +363,7 @@ out: static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active) + if (vif->bss_conf.csa_active) ieee80211_csa_finish(vif); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b7e2b365356c..1b3d6634a72e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -322,7 +322,7 @@ int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) static void mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active) + if (vif->bss_conf.csa_active) ieee80211_csa_finish(vif); } @@ -409,7 +409,7 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) static void mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (!vif->color_change_active) + if (!vif->bss_conf.color_change_active) return; ieee80211_color_change_finish(vif); @@ -1818,7 +1818,7 @@ mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, if (!offs->cntdwn_counter_offs[0]) return; - sub_tag = vif->csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; + sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info), &bcn->sub_ntlv, &bcn->len); info = (struct bss_info_bcn_cntdwn *)tlv; @@ -1903,9 +1903,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (offs->cntdwn_counter_offs[0]) { u16 offset = offs->cntdwn_counter_offs[0]; - if (vif->csa_active) + if (vif->bss_conf.csa_active) cont->csa_ofs = cpu_to_le16(offset - 4); - if (vif->color_change_active) + if (vif->bss_conf.color_change_active) cont->bcc_ofs = cpu_to_le16(offset - 3); } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6959efa4bfa9..21a9e3b0cbac 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4675,7 +4675,7 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); rcu_read_lock(); - if (rcu_access_pointer(vif->chanctx_conf) != ctx) { + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != ctx) { rcu_read_unlock(); continue; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5c9e97eca739..e3ded46f70ac 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -636,6 +636,19 @@ struct ieee80211_fils_discovery { * @tx_pwr_env_num: number of @tx_pwr_env. * @pwr_reduction: power constraint of BSS. * @eht_support: does this BSS support EHT + * @csa_active: marks whether a channel switch is going on. Internally it is + * write-protected by sdata_lock and local->mtx so holding either is fine + * for read access. + * @mu_mimo_owner: indicates interface owns MU-MIMO capability + * @chanctx_conf: The channel context this interface is assigned to, or %NULL + * when it is not assigned. This pointer is RCU-protected due to the TX + * path needing to access it; even though the netdev carrier will always + * be off when it is %NULL there can still be races and packets could be + * processed after it switches back to %NULL. + * @color_change_active: marks whether a color change is ongoing. Internally it is + * write-protected by sdata_lock and local->mtx so holding either is fine + * for read access. + * @color_change_color: the bss color that will be used after the change. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -711,6 +724,13 @@ struct ieee80211_bss_conf { u8 tx_pwr_env_num; u8 pwr_reduction; bool eht_support; + + bool csa_active; + bool mu_mimo_owner; + struct ieee80211_chanctx_conf __rcu *chanctx_conf; + + bool color_change_active; + u8 color_change_color; }; /** @@ -1713,10 +1733,6 @@ enum ieee80211_offload_flags { * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively - * @csa_active: marks whether a channel switch is going on. Internally it is - * write-protected by sdata_lock and local->mtx so holding either is fine - * for read access. - * @mu_mimo_owner: indicates interface owns MU-MIMO capability * @driver_flags: flags/capabilities the driver has for this interface, * these need to be set (or cleared) when the interface is added * or, if supported by the driver, the interface type is changed @@ -1728,11 +1744,6 @@ enum ieee80211_offload_flags { * restrictions. * @hw_queue: hardware queue for each AC * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only - * @chanctx_conf: The channel context this interface is assigned to, or %NULL - * when it is not assigned. This pointer is RCU-protected due to the TX - * path needing to access it; even though the netdev carrier will always - * be off when it is %NULL there can still be races and packets could be - * processed after it switches back to %NULL. * @debugfs_dir: debugfs dentry, can be used by drivers to create own per * interface debug files. Note that it will be NULL for the virtual * monitor interface (if that is requested.) @@ -1747,10 +1758,6 @@ enum ieee80211_offload_flags { * protected by fq->lock. * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see * &enum ieee80211_offload_flags. - * @color_change_active: marks whether a color change is ongoing. Internally it is - * write-protected by sdata_lock and local->mtx so holding either is fine - * for read access. - * @color_change_color: the bss color that will be used after the change. * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled. */ struct ieee80211_vif { @@ -1758,16 +1765,12 @@ struct ieee80211_vif { struct ieee80211_bss_conf bss_conf; u8 addr[ETH_ALEN] __aligned(2); bool p2p; - bool csa_active; - bool mu_mimo_owner; u8 cab_queue; u8 hw_queue[IEEE80211_NUM_ACS]; struct ieee80211_txq *txq; - struct ieee80211_chanctx_conf __rcu *chanctx_conf; - u32 driver_flags; u32 offload_flags; @@ -1780,9 +1783,6 @@ struct ieee80211_vif { bool txqs_stopped[IEEE80211_NUM_ACS]; - bool color_change_active; - u8 color_change_color; - struct ieee80211_vif *mbssid_tx_vif; /* must be last */ diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c index 4bab1683652d..2e66598fac79 100644 --- a/net/mac80211/airtime.c +++ b/net/mac80211/airtime.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2019 Felix Fietkau - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation */ #include @@ -637,7 +637,7 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, len += 38; /* Ethernet header length */ - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (conf) { band = conf->def.chan->band; shift = ieee80211_chandef_get_shift(&conf->def); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 362cac9e2135..8a15c71e7c7d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -53,7 +53,7 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, params->vht_mumimo_follow_addr); } - sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; + sdata->vif.bss_conf.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; } static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, @@ -1310,7 +1310,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, /* don't allow changing the beacon while a countdown is in place - offset * of channel switch counter may change */ - if (sdata->vif.csa_active || sdata->vif.color_change_active) + if (sdata->vif.bss_conf.csa_active || sdata->vif.bss_conf.color_change_active) return -EBUSY; old = sdata_dereference(sdata->u.ap.beacon, sdata); @@ -1368,7 +1368,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, /* abort any running channel switch */ mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -3067,7 +3067,7 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, * to send something, and if we're an AP we have to be able to do * so at a basic rate so that all clients can receive it. */ - if (rcu_access_pointer(sdata->vif.chanctx_conf) && + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) && sdata->vif.bss_conf.chandef.chan) { u32 basic_rates = sdata->vif.bss_conf.basic_rates; enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band; @@ -3374,7 +3374,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) &sdata->csa_chandef)) return -EINVAL; - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; err = ieee80211_set_after_csa_beacon(sdata, &changed); if (err) @@ -3418,7 +3418,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) mutex_lock(&local->chanctx_mtx); /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) goto unlock; if (!ieee80211_sdata_running(sdata)) @@ -3570,7 +3570,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, static void ieee80211_color_change_abort(struct ieee80211_sub_if_data *sdata) { - sdata->vif.color_change_active = false; + sdata->vif.bss_conf.color_change_active = false; ieee80211_free_next_beacon(sdata); @@ -3603,11 +3603,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; /* don't allow another channel switch if one is already active. */ - if (sdata->vif.csa_active) + if (sdata->vif.bss_conf.csa_active) return -EBUSY; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { err = -EBUSY; @@ -3646,7 +3646,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, } /* if there is a color change in progress, abort it */ - if (sdata->vif.color_change_active) + if (sdata->vif.bss_conf.color_change_active) ieee80211_color_change_abort(sdata); err = ieee80211_set_csa_beacon(sdata, params, &changed); @@ -3657,7 +3657,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->csa_chandef = params->chandef; sdata->csa_block_tx = params->block_tx; - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; if (sdata->csa_block_tx) ieee80211_stop_vif_queues(local, sdata, @@ -3826,7 +3826,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&local->mtx); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { ret = -EINVAL; goto unlock; @@ -3909,7 +3909,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, int ret = -ENODATA; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { *chandef = sdata->vif.bss_conf.chandef; ret = 0; @@ -4405,7 +4405,7 @@ static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); lockdep_assert_held(&local->mtx); - sdata->vif.color_change_active = false; + sdata->vif.bss_conf.color_change_active = false; err = ieee80211_set_after_color_change_beacon(sdata, &changed); if (err) { @@ -4414,7 +4414,7 @@ static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) } ieee80211_color_change_bss_config_notify(sdata, - sdata->vif.color_change_color, + sdata->vif.bss_conf.color_change_color, 1, changed); cfg80211_color_change_notify(sdata->dev); @@ -4432,7 +4432,7 @@ void ieee80211_color_change_finalize_work(struct work_struct *work) mutex_lock(&local->mtx); /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.color_change_active) + if (!sdata->vif.bss_conf.color_change_active) goto unlock; if (!ieee80211_sdata_running(sdata)) @@ -4460,7 +4460,7 @@ ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - if (sdata->vif.color_change_active || sdata->vif.csa_active) + if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active) return; cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap); @@ -4486,7 +4486,7 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, /* don't allow another color change if one is already active or if csa * is active */ - if (sdata->vif.color_change_active || sdata->vif.csa_active) { + if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active) { err = -EBUSY; goto out; } @@ -4495,8 +4495,8 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - sdata->vif.color_change_active = true; - sdata->vif.color_change_color = params->color; + sdata->vif.bss_conf.color_change_active = true; + sdata->vif.bss_conf.color_change_color = params->color; cfg80211_color_change_started_notify(sdata->dev, params->count); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index d8246e00a10b..eea400902133 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * mac80211 - channel management - * Copyright 2020 - 2021 Intel Corporation + * Copyright 2020 - 2022 Intel Corporation */ #include @@ -72,7 +72,7 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_chanctx_conf *conf; - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return NULL; @@ -260,7 +260,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; switch (vif->type) { @@ -298,7 +298,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, /* use the configured bandwidth in case of monitor interface */ sdata = rcu_dereference(local->monitor_sdata); - if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf) + if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf) max_bw = max(max_bw, conf->def.width); rcu_read_unlock(); @@ -368,7 +368,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, if (!ieee80211_sdata_running(sta->sdata)) continue; - if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) != + if (rcu_access_pointer(sta->sdata->vif.bss_conf.chanctx_conf) != &ctx->conf) continue; @@ -533,7 +533,7 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; if (!sdata->radar_required) continue; @@ -689,7 +689,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; @@ -759,7 +759,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) return -ENOTSUPP; - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { @@ -781,7 +781,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, } out: - rcu_assign_pointer(sdata->vif.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); sdata->vif.bss_conf.idle = !conf; @@ -825,7 +825,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != &chanctx->conf) continue; @@ -874,7 +874,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, /* Disable SMPS for the monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.chanctx_conf) == &chanctx->conf) + rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; rcu_read_unlock(); @@ -917,7 +917,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, * channel context pointer for a while, possibly pointing * to a channel context that has already been freed. */ - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); WARN_ON(!conf); @@ -925,7 +925,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, conf = NULL; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.chanctx_conf, conf); + rcu_assign_pointer(vlan->vif.bss_conf.chanctx_conf, conf); } void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, @@ -1173,7 +1173,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) } list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); - rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, &new_ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); @@ -1515,7 +1515,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) if (!ieee80211_vif_has_in_place_reservation(sdata)) continue; - rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, + &ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) __ieee80211_vif_copy_chanctx_to_vlans(sdata, @@ -1634,7 +1635,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return; @@ -1809,7 +1810,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, goto out; } - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { ret = -EINVAL; @@ -1879,9 +1880,9 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(ap->vif.chanctx_conf, + conf = rcu_dereference_protected(ap->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); - rcu_assign_pointer(sdata->vif.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); mutex_unlock(&local->chanctx_mtx); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4e2fc1a08681..fd2882348211 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -165,7 +165,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || sdata->vif.type == NL80211_IFTYPE_NAN || (sdata->vif.type == NL80211_IFTYPE_MONITOR && - !sdata->vif.mu_mimo_owner && + !sdata->vif.bss_conf.mu_mimo_owner && !(changed & BSS_CHANGED_TXPOWER)))) return; diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c index 31cd3c1ac07f..6e1fc8788101 100644 --- a/net/mac80211/ethtool.c +++ b/net/mac80211/ethtool.c @@ -5,7 +5,7 @@ * Copied from cfg.c - originally * Copyright 2006-2010 Johannes Berg * Copyright 2014 Intel Corporation (Author: Johannes Berg) - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018, 2022 Intel Corporation */ #include #include @@ -150,7 +150,7 @@ do_survey: survey.filled = 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) channel = chanctx_conf->def.chan; else diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 14c04fd48b7a..8ff547ff351e 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -9,7 +9,7 @@ * Copyright 2009, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright(c) 2018-2021 Intel Corporation + * Copyright(c) 2018-2022 Intel Corporation */ #include @@ -622,7 +622,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, } rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) return NULL; band = chanctx_conf->def.chan->band; @@ -923,7 +923,7 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, if (len < required_len) return; - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) ieee80211_ibss_process_chanswitch(sdata, elems, false); } @@ -1143,7 +1143,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* process channel switch */ - if (sdata->vif.csa_active || + if (sdata->vif.bss_conf.csa_active || ieee80211_ibss_process_chanswitch(sdata, elems, true)) goto put_bss; @@ -1220,7 +1220,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1cf331572de1..5a1347727b4a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1076,7 +1076,7 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif) int shift = 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (chanctx_conf) shift = ieee80211_chandef_get_shift(&chanctx_conf->def); rcu_read_unlock(); @@ -1527,7 +1527,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) enum nl80211_band band; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); @@ -2224,7 +2224,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); kfree_skb(skb); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fb8d102fca48..9e0e71ca8068 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -51,7 +51,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) int power; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return false; @@ -275,7 +275,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, * will not add another interface while any channel * switch is active. */ - if (nsdata->vif.csa_active) + if (nsdata->vif.bss_conf.csa_active) return -EBUSY; /* @@ -450,7 +450,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do cancel_work_sync(&sdata->recalc_smps); sdata_lock(sdata); mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.csa_waiting_bcn = false; if (sdata->csa_block_tx) { @@ -502,7 +502,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do mutex_lock(&local->mtx); list_del(&sdata->u.vlan.list); mutex_unlock(&local->mtx); - RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); + RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL); /* see comment in the default case below */ ieee80211_free_keys(sdata, true); /* no need to tell driver */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4f3e93c0819b..ebde131efcaa 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -147,7 +147,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!rcu_access_pointer(sdata->vif.chanctx_conf)) + if (!rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf)) continue; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; @@ -284,7 +284,7 @@ static void ieee80211_restart_work(struct work_struct *work) * Then we can have a race... */ cancel_work_sync(&sdata->u.mgd.csa_connection_drop_work); - if (sdata->vif.csa_active) { + if (sdata->vif.bss_conf.csa_active) { sdata_lock(sdata); ieee80211_sta_connection_lost(sdata, WLAN_REASON_UNSPECIFIED, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5275f4f32a78..f60e257cba95 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -399,7 +399,7 @@ static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata, return -ENOMEM; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -455,7 +455,7 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, u8 *pos; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -527,7 +527,7 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, u8 *pos; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -820,7 +820,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); band = chanctx_conf->def.chan->band; rcu_read_unlock(); @@ -1357,7 +1357,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, rx_status); if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && - !sdata->vif.csa_active) + !sdata->vif.bss_conf.csa_active) ieee80211_mesh_process_chnswitch(sdata, elems, true); } @@ -1488,7 +1488,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, ifmsh->pre_value = pre_value; - if (!sdata->vif.csa_active && + if (!sdata->vif.bss_conf.csa_active && !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { mcsa_dbg(sdata, "Failed to process CSA action frame"); goto free; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e0a9b7d63071..c526af66ff8d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -624,7 +624,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *other; list_for_each_entry_rcu(other, &local->interfaces, list) { - if (other->vif.mu_mimo_owner) { + if (other->vif.bss_conf.mu_mimo_owner) { disable_mu_mimo = true; break; } @@ -632,7 +632,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, if (disable_mu_mimo) cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; else - sdata->vif.mu_mimo_owner = true; + sdata->vif.bss_conf.mu_mimo_owner = true; } mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; @@ -664,7 +664,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, bool reg_cap = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!WARN_ON_ONCE(!chanctx_conf)) reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, &chanctx_conf->def, @@ -705,7 +705,7 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, bool reg_cap = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!WARN_ON_ONCE(!chanctx_conf)) reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, &chanctx_conf->def, @@ -766,7 +766,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -1229,7 +1229,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ifmgd->associated) goto out; - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) goto out; /* @@ -1289,7 +1289,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); - WARN_ON(!sdata->vif.csa_active); + WARN_ON(!sdata->vif.bss_conf.csa_active); if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -1297,7 +1297,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) sdata->csa_block_tx = false; } - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; /* * If the CSA IE is still present on the beacon after the switch, @@ -1361,7 +1361,7 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata) IEEE80211_QUEUE_STOP_REASON_CSA); sdata->csa_block_tx = false; - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; mutex_unlock(&local->mtx); @@ -1412,13 +1412,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (res < 0) goto lock_and_drop_connection; - if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) { + if (beacon && sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) { if (res) ieee80211_sta_abort_chanswitch(sdata); else drv_channel_switch_rx_beacon(sdata, &ch_switch); return; - } else if (sdata->vif.csa_active || res) { + } else if (sdata->vif.bss_conf.csa_active || res) { /* disregard subsequent announcements if already processing */ return; } @@ -1471,7 +1471,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { sdata_info(sdata, @@ -1504,7 +1504,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->chanctx_mtx); - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; sdata->csa_chandef = csa_ie.chandef; sdata->csa_block_tx = csa_ie.mode; ifmgd->csa_ignored_same_chan = false; @@ -1543,7 +1543,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, * send a deauthentication frame. Those two fields will be * reset when the disconnection worker runs. */ - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; sdata->csa_block_tx = csa_ie.mode; ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); @@ -2447,7 +2447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(sdata->vif.bss_conf.mu_group.position, 0, sizeof(sdata->vif.bss_conf.mu_group.position)); changed |= BSS_CHANGED_MU_GROUPS; - sdata->vif.mu_mimo_owner = false; + sdata->vif.bss_conf.mu_mimo_owner = false; sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; @@ -2482,7 +2482,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->mtx); ieee80211_vif_release_channel(sdata); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; ifmgd->csa_ignored_same_chan = false; if (sdata->csa_block_tx) { @@ -2808,7 +2808,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, tx, frame_buf); mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -2948,7 +2948,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, eth_zero_addr(sdata->u.mgd.bssid); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; - sdata->vif.mu_mimo_owner = false; + sdata->vif.bss_conf.mu_mimo_owner = false; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -4134,7 +4134,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return; @@ -4803,7 +4803,7 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) from_timer(sdata, t, u.mgd.bcn_mon_timer); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) + if (sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) return; if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) @@ -4823,7 +4823,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) struct sta_info *sta; unsigned long timeout; - if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) + if (sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) return; sta = sta_info_get(sdata, ifmgd->bssid); diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index f97cb4c453d3..d0f0d96b0948 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -4,6 +4,7 @@ * * Copyright: (c) 2014 Czech Technical University in Prague * (c) 2014 Volkswagen Group Research + * Copyright (C) 2022 Intel Corporation * Author: Rostislav Lisovy * Funded by: Volkswagen Group Research */ @@ -59,7 +60,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c5d2ab9df1e7..a1fbd562cac1 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -8,7 +8,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu * Copyright 2009 Johannes Berg - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019, 2022 Intel Corporation */ #include #include @@ -845,7 +845,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { need_offchan = params->chan && @@ -876,7 +876,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, data = skb_put_data(skb, params->buf, params->len); /* Update CSA counters */ - if (sdata->vif.csa_active && + if (sdata->vif.bss_conf.csa_active && (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_MESH_POINT || sdata->vif.type == NL80211_IFTYPE_ADHOC) && diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index ae9700e0a1a5..f22381127948 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -4,6 +4,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc * Copyright 2017 Intel Deutschland GmbH + * Copyright (C) 2022 Intel Corporation */ #include @@ -43,7 +44,7 @@ void rate_control_rate_init(struct sta_info *sta) rcu_read_lock(); - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sta->sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; @@ -100,7 +101,7 @@ void rate_control_rate_update(struct ieee80211_local *local, if (ref && ref->ops->rate_update) { rcu_read_lock(); - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sta->sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a9f4e90ad893..9a179a18aafc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3167,7 +3167,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) return; - if (rx->sdata->vif.csa_active) + if (rx->sdata->vif.bss_conf.csa_active) return; baselen = mgmt->u.beacon.variable - rx->skb->data; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e04a0905e941..7eeb6919d2b7 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1467,7 +1467,7 @@ static void ieee80211_send_null_response(struct sta_info *sta, int tid, skb->dev = sdata->dev; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); kfree_skb(skb); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4e2d22e47429..fa04021d4c0f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -6,7 +6,7 @@ * Copyright 2014, Intel Corporation * Copyright 2014 Intel Mobile Communications GmbH * Copyright 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation */ #include @@ -1254,7 +1254,7 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { width = conf->def.width; @@ -1372,7 +1372,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, switch (oper) { case NL80211_TDLS_ENABLE_LINK: - if (sdata->vif.csa_active) { + if (sdata->vif.bss_conf.csa_active) { tdls_dbg(sdata, "TDLS: disallow link during CSA\n"); ret = -EBUSY; break; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 37fe72bb5ab0..e5edc6fd21c0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -57,7 +57,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, return 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(tx->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(tx->sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { shift = ieee80211_chandef_get_shift(&chanctx_conf->def); rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); @@ -2345,12 +2345,12 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, } } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { tmp_sdata = rcu_dereference(local->monitor_sdata); if (tmp_sdata) chanctx_conf = - rcu_dereference(tmp_sdata->vif.chanctx_conf); + rcu_dereference(tmp_sdata->vif.bss_conf.chanctx_conf); } if (chanctx_conf) @@ -2599,7 +2599,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2610,7 +2610,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, fallthrough; case NL80211_IFTYPE_AP: if (sdata->vif.type == NL80211_IFTYPE_AP) - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2689,7 +2689,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, skb->data + ETH_ALEN); } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2732,7 +2732,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2745,7 +2745,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); eth_broadcast_addr(hdr.addr3); hdrlen = 24; - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2758,7 +2758,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); hdrlen = 24; - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2981,7 +2981,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) goto out; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); goto out; @@ -4604,7 +4604,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, sdata = vif_to_sdata(info->control.vif); if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (unlikely(!chanctx_conf)) { dev_kfree_skb(skb); return true; @@ -4808,7 +4808,7 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, bcn_offsets = beacon->cntdwn_counter_offsets; count = beacon->cntdwn_current_counter; - if (sdata->vif.csa_active) + if (sdata->vif.bss_conf.csa_active) max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; for (i = 0; i < max_count; ++i) { @@ -5119,7 +5119,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_lock(); sdata = vif_to_sdata(vif); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; @@ -5536,7 +5536,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) goto out; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9e6c4dcef280..48d8f0aad69f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1566,7 +1566,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) center_freq = chanctx_conf->def.chan->center_freq; @@ -1613,7 +1613,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, memset(&qparam, 0, sizeof(qparam)); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); use_11b = (chanctx_conf && chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); @@ -2264,7 +2264,7 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, return; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); @@ -2523,7 +2523,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) BSS_CHANGED_TXPOWER | BSS_CHANGED_MCAST_RATE; - if (sdata->vif.mu_mimo_owner) + if (sdata->vif.bss_conf.mu_mimo_owner) changed |= BSS_CHANGED_MU_GROUPS; switch (sdata->vif.type) { @@ -2806,8 +2806,8 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); + chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); /* * This function can be called from a work, thus it may be possible @@ -2832,8 +2832,8 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); + chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); if (WARN_ON_ONCE(!chanctx_conf)) goto unlock; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index ff26e0c4787b..ac97584b3a0b 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -4,7 +4,7 @@ * * Portions of this file * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation */ #include @@ -649,7 +649,7 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - if (!sdata->vif.mu_mimo_owner) + if (!sdata->vif.bss_conf.mu_mimo_owner) return; if (!memcmp(mgmt->u.action.u.vht_group_notif.position, @@ -673,7 +673,7 @@ void ieee80211_update_mu_groups(struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if (WARN_ON_ONCE(!vif->mu_mimo_owner)) + if (WARN_ON_ONCE(!vif->bss_conf.mu_mimo_owner)) return; memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); -- cgit v1.2.3 From f276e20b182dbfc069d192fda259d85feea71143 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 May 2022 17:05:04 +0200 Subject: wifi: mac80211: move interface config to new struct We'll use bss_conf for per-link configuration later, so move out all the non-link-specific data out into a new struct ieee80211_vif_cfg used in the vif. Some adjustments were done with the following spatch: @@ expression sdata; struct ieee80211_vif *vifp; identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator }; @@ ( -sdata->vif.bss_conf.var +sdata->vif.cfg.var | -vifp->bss_conf.var +vifp->cfg.var ) @bss_conf@ struct ieee80211_bss_conf *bss_conf; identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator }; @@ -bss_conf->var +vif_cfg->var (though more manual fixups were needed, e.g. replacing "vif_cfg->" by "vif->cfg." in many files.) Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ar5523/ar5523.c | 10 ++-- drivers/net/wireless/ath/ath10k/mac.c | 29 +++++----- drivers/net/wireless/ath/ath11k/mac.c | 22 ++++---- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 12 ++-- drivers/net/wireless/ath/ath9k/beacon.c | 11 ++-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 16 +++--- drivers/net/wireless/ath/ath9k/main.c | 8 +-- drivers/net/wireless/ath/carl9170/main.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 16 +++--- drivers/net/wireless/ath/wcn36xx/smd.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 12 ++-- drivers/net/wireless/intel/iwlegacy/3945-mac.c | 6 +- drivers/net/wireless/intel/iwlegacy/4965.c | 6 +- drivers/net/wireless/intel/iwlegacy/common.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 22 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 12 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 12 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 28 ++++----- .../net/wireless/intel/iwlwifi/mvm/offloading.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/quota.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 8 +-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 +- drivers/net/wireless/intersil/p54/main.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 6 +- drivers/net/wireless/marvell/mwl8k.c | 10 ++-- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 10 ++-- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt7601u/phy.c | 9 ++- drivers/net/wireless/ralink/rt2x00/rt2x00config.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 2 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++-- drivers/net/wireless/realtek/rtlwifi/core.c | 4 +- drivers/net/wireless/realtek/rtw88/bf.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 4 +- drivers/net/wireless/realtek/rtw88/main.c | 13 +++-- drivers/net/wireless/realtek/rtw89/cam.c | 2 +- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw89/phy.c | 4 +- drivers/net/wireless/rsi/rsi_91x_core.c | 3 +- drivers/net/wireless/rsi/rsi_91x_hal.c | 7 +-- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 31 +++++----- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 3 +- drivers/net/wireless/silabs/wfx/hif_tx.c | 12 ++-- drivers/net/wireless/silabs/wfx/sta.c | 24 ++++---- drivers/net/wireless/st/cw1200/sta.c | 36 ++++++------ drivers/net/wireless/st/cw1200/txrx.c | 4 +- drivers/net/wireless/ti/wl1251/main.c | 8 +-- drivers/net/wireless/ti/wlcore/cmd.c | 4 +- drivers/net/wireless/ti/wlcore/main.c | 37 ++++++------ drivers/staging/vt6655/device_main.c | 6 +- drivers/staging/vt6656/main_usb.c | 4 +- include/net/mac80211.h | 66 +++++++++++++--------- net/mac80211/cfg.c | 10 ++-- net/mac80211/chan.c | 2 +- net/mac80211/debugfs_netdev.c | 6 +- net/mac80211/ibss.c | 26 ++++----- net/mac80211/iface.c | 2 +- net/mac80211/main.c | 10 ++-- net/mac80211/mlme.c | 26 +++++---- net/mac80211/offchannel.c | 2 +- net/mac80211/scan.c | 2 +- net/mac80211/tdls.c | 4 +- net/mac80211/trace.h | 49 +++++++++------- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 2 +- 79 files changed, 402 insertions(+), 368 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 9f84a6fde0c2..4cd06a0942d4 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1256,14 +1256,14 @@ static int ar5523_create_connection(struct ar5523 *ar, sizeof(create), 0); } -static int ar5523_write_associd(struct ar5523 *ar, - struct ieee80211_bss_conf *bss) +static int ar5523_write_associd(struct ar5523 *ar, struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss = &vif->bss_conf; struct ar5523_cmd_set_associd associd; memset(&associd, 0, sizeof(associd)); associd.defaultrateix = cpu_to_be32(0); /* XXX */ - associd.associd = cpu_to_be32(bss->aid); + associd.associd = cpu_to_be32(vif->cfg.aid); associd.timoffset = cpu_to_be32(0x3b); /* XXX */ memcpy(associd.bssid, bss->bssid, ETH_ALEN); return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd, @@ -1284,7 +1284,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, if (!(changed & BSS_CHANGED_ASSOC)) goto out_unlock; - if (bss->assoc) { + if (vif->cfg.assoc) { error = ar5523_create_connection(ar, vif, bss); if (error) { ar5523_err(ar, "could not create connection\n"); @@ -1297,7 +1297,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, goto out_unlock; } - error = ar5523_write_associd(ar, bss); + error = ar5523_write_associd(ar, vif); if (error) { ar5523_err(ar, "could not set association\n"); goto out_unlock; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 42c657b8b73e..4e7e2da3c859 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1509,8 +1509,8 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, arg.channel.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - arg.ssid = arvif->vif->bss_conf.ssid; - arg.ssid_len = arvif->vif->bss_conf.ssid_len; + arg.ssid = arvif->vif->cfg.ssid; + arg.ssid_len = arvif->vif->cfg.ssid_len; } ath10k_dbg(ar, ATH10K_DBG_MAC, @@ -1823,8 +1823,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, } static void ath10k_control_ibss(struct ath10k_vif *arvif, - struct ieee80211_bss_conf *info, - const u8 self_peer[ETH_ALEN]) + struct ieee80211_vif *vif) { struct ath10k *ar = arvif->ar; u32 vdev_param; @@ -1832,7 +1831,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, lockdep_assert_held(&arvif->ar->conf_mutex); - if (!info->ibss_joined) { + if (!vif->cfg.ibss_joined) { if (is_zero_ether_addr(arvif->bssid)) return; @@ -2163,7 +2162,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, lockdep_assert_held(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_STATION) - aid = vif->bss_conf.aid; + aid = vif->cfg.aid; else aid = sta->aid; @@ -2193,7 +2192,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, return; bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, - info->ssid_len ? info->ssid : NULL, info->ssid_len, + vif->cfg.ssid_len ? vif->cfg.ssid : NULL, + vif->cfg.ssid_len, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); if (bss) { const struct cfg80211_bss_ies *ies; @@ -3118,11 +3118,11 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", - arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); WARN_ON(arvif->is_up); - arvif->aid = bss_conf->aid; + arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); ret = ath10k_wmi_pdev_set_param(ar, @@ -6082,7 +6082,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); if (changed & BSS_CHANGED_IBSS) - ath10k_control_ibss(arvif, info, vif->addr); + ath10k_control_ibss(arvif, vif); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -6147,9 +6147,10 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = info->ssid_len; - if (info->ssid_len) - memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len); + arvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(arvif->u.ap.ssid, vif->cfg.ssid, + vif->cfg.ssid_len); arvif->u.ap.hidden_ssid = info->hidden_ssid; } @@ -6226,7 +6227,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { + if (vif->cfg.assoc) { /* Workaround: Make sure monitor vdev is not running * when associating to prevent some firmware revisions * (e.g. 10.1 and 10.2) from crashing. diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f28e7feca318..169161549361 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1539,7 +1539,7 @@ static void ath11k_peer_assoc_h_basic(struct ath11k *ar, lockdep_assert_held(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_STATION) - aid = vif->bss_conf.aid; + aid = vif->cfg.aid; else aid = sta->aid; @@ -2749,7 +2749,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, WARN_ON(arvif->is_up); - arvif->aid = bss_conf->aid; + arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); @@ -2764,7 +2764,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", - arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); spin_lock_bh(&ar->ab->base_lock); @@ -3185,9 +3185,10 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = info->ssid_len; - if (info->ssid_len) - memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len); + arvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(arvif->u.ap.ssid, vif->cfg.ssid, + vif->cfg.ssid_len); arvif->u.ap.hidden_ssid = info->hidden_ssid; } @@ -3275,7 +3276,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) + if (vif->cfg.assoc) ath11k_bss_assoc(hw, vif, info); else ath11k_bss_disassoc(hw, vif); @@ -3406,14 +3407,15 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_mac_fils_discovery(arvif, info); if (changed & BSS_CHANGED_ARP_FILTER) { - ipv4_cnt = min(info->arp_addr_cnt, ATH11K_IPV4_MAX_COUNT); - memcpy(arvif->arp_ns_offload.ipv4_addr, info->arp_addr_list, + ipv4_cnt = min(vif->cfg.arp_addr_cnt, ATH11K_IPV4_MAX_COUNT); + memcpy(arvif->arp_ns_offload.ipv4_addr, + vif->cfg.arp_addr_list, ipv4_cnt * sizeof(u32)); memcpy(arvif->arp_ns_offload.mac_addr, vif->addr, ETH_ALEN); arvif->arp_ns_offload.ipv4_count = ipv4_cnt; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", - info->arp_addr_cnt, + vif->cfg.arp_addr_cnt, vif->addr, arvif->arp_ns_offload.ipv4_addr); } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 532eeac9e83e..0df0fa1da181 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -278,9 +278,9 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes & BSS_CHANGED_ASSOC) { - avf->assoc = bss_conf->assoc; - if (bss_conf->assoc) - ah->assoc = bss_conf->assoc; + avf->assoc = vif->cfg.assoc; + if (vif->cfg.assoc) + ah->assoc = vif->cfg.assoc; else ah->assoc = ath5k_any_vif_assoc(ah); @@ -288,11 +288,11 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath5k_set_beacon_filter(hw, ah->assoc); ath5k_hw_set_ledstate(ah, ah->assoc ? AR5K_LED_ASSOC : AR5K_LED_INIT); - if (bss_conf->assoc) { + if (vif->cfg.assoc) { ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - common->curaid = bss_conf->aid; + vif->cfg.aid, common->curbssid); + common->curaid = vif->cfg.aid; ath5k_hw_set_bssid(ah); /* Once ANI is available you would start it here */ } diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 8b1b966bcef1..d41988f8ea3f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -585,8 +585,9 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, static void ath9k_cache_beacon_config(struct ath_softc *sc, struct ath_chanctx *ctx, - struct ieee80211_bss_conf *bss_conf) + struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &ctx->beacon; @@ -596,7 +597,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->dtim_count = 1; - cur_conf->ibss_creator = bss_conf->ibss_creator; + cur_conf->ibss_creator = vif->cfg.ibss_creator; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -649,7 +650,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, cur_conf->enable_beacon = beacons; if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); + ath9k_cache_beacon_config(sc, ctx, main_vif); ath9k_set_beacon(sc); set_bit(ATH_OP_BEACONS, &common->op_flags); @@ -657,7 +658,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, } /* Update the beacon configuration. */ - ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); + ath9k_cache_beacon_config(sc, ctx, main_vif); /* * Configure the HW beacon registers only when we have a valid @@ -670,7 +671,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, * IBSS interface. */ if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && - !enabled && beacons && !main_vif->bss_conf.ibss_creator) { + !enabled && beacons && !main_vif->cfg.ibss_creator) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index cfee732a89b1..3a5ec4da6a38 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -100,7 +100,7 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) priv->rearm_ani = true; } - if (bss_conf->assoc) { + if (vif->cfg.assoc) { priv->rearm_ani = true; priv->reconfig_beacon = true; } @@ -1488,8 +1488,8 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) { - common->curaid = bss_conf->aid; + if ((vif->type == NL80211_IFTYPE_STATION) && vif->cfg.assoc) { + common->curaid = vif->cfg.aid; common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); @@ -1521,17 +1521,17 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); + vif->cfg.assoc); - bss_conf->assoc ? + vif->cfg.assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; - if (!bss_conf->assoc) + if (!vif->cfg.assoc) clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); - if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) + if (vif->cfg.assoc && (priv->num_sta_assoc_vif == 1)) ath9k_htc_start_ani(priv); else if (priv->num_sta_assoc_vif == 0) ath9k_htc_stop_ani(priv); @@ -1540,7 +1540,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_htc_set_bssid(priv); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 77144647f4fc..56c2681e5192 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1881,11 +1881,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", - bss_conf->bssid, bss_conf->assoc); + bss_conf->bssid, vif->cfg.assoc); memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - avp->aid = bss_conf->aid; - avp->assoc = bss_conf->assoc; + avp->aid = vif->cfg.aid; + avp->assoc = vif->cfg.assoc; ath9k_calculate_summary_state(sc, avp->chanctx); } @@ -1893,7 +1893,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_IBSS) || (changed & BSS_CHANGED_OCB)) { memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; ath9k_hw_write_associd(sc->sc_ah); } diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 101295162967..e28a5f3085c0 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1115,7 +1115,7 @@ static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - ar->common.curaid = bss_conf->aid; + ar->common.curaid = vif->cfg.aid; err = carl9170_set_beacon_timers(ar); if (err) goto out; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e34d3d0b7082..72ba2e2fc93a 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -919,17 +919,17 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ssid\n"); wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ", - bss_conf->ssid, bss_conf->ssid_len); + vif->cfg.ssid, vif->cfg.ssid_len); - vif_priv->ssid.length = bss_conf->ssid_len; + vif_priv->ssid.length = vif->cfg.ssid_len; memcpy(&vif_priv->ssid.ssid, - bss_conf->ssid, - bss_conf->ssid_len); + vif->cfg.ssid, + vif->cfg.ssid_len); } if (changed & BSS_CHANGED_ASSOC) { vif_priv->is_joining = false; - if (bss_conf->assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *sta; struct wcn36xx_sta *sta_priv; @@ -937,7 +937,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, "mac assoc bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = true; @@ -963,7 +963,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, sta, bss_conf->bssid, true); - sta_priv->aid = bss_conf->aid; + sta_priv->aid = vif->cfg.aid; /* * config_sta must be called from because this is the * place where AID is available. @@ -977,7 +977,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, "disassociated bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = false; wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 7ac9a1e6f768..46ab21824d63 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -3005,7 +3005,7 @@ int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, msg_body.host_offload_params.enable = WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; memcpy(&msg_body.host_offload_params.u, - &vif->bss_conf.arp_addr_list[0], sizeof(__be32)); + &vif->cfg.arp_addr_list[0], sizeof(__be32)); } msg_body.ns_offload_params.bss_index = vif_priv->bss_index; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 8c741b98d8e5..e6cd638a85d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -507,7 +507,7 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) brcms_c_start_station(wl->wlc, vif->addr); else if (vif->type == NL80211_IFTYPE_AP) brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid, - vif->bss_conf.ssid, vif->bss_conf.ssid_len); + vif->cfg.ssid, vif->cfg.ssid_len); else if (vif->type == NL80211_IFTYPE_ADHOC) brcms_c_start_adhoc(wl->wlc, vif->addr); spin_unlock_bh(&wl->lock); @@ -592,9 +592,9 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, * also implies a change in the AID. */ brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME, - __func__, info->assoc ? "" : "dis"); + __func__, vif->cfg.assoc ? "" : "dis"); spin_lock_bh(&wl->lock); - brcms_c_associate_upd(wl->wlc, info->assoc); + brcms_c_associate_upd(wl->wlc, vif->cfg.assoc); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -669,7 +669,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID) { /* BSSID changed, for whatever reason (IBSS and managed mode) */ spin_lock_bh(&wl->lock); - brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len); + brcms_c_set_ssid(wl->wlc, vif->cfg.ssid, vif->cfg.ssid_len); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BEACON) { @@ -715,13 +715,13 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ brcms_err(core, "%s: IBSS joined: %s (implement)\n", - __func__, info->ibss_joined ? "true" : "false"); + __func__, vif->cfg.ibss_joined ? "true" : "false"); } if (changed & BSS_CHANGED_ARP_FILTER) { /* Hardware ARP filter address list or state changed */ brcms_err(core, "%s: arp filtering: %d addresses" - " (implement)\n", __func__, info->arp_addr_cnt); + " (implement)\n", __func__, vif->cfg.arp_addr_cnt); } if (changed & BSS_CHANGED_QOS) { diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index bd4e7d752958..846138d6e33d 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -2701,7 +2701,7 @@ il3945_post_associate(struct il_priv *il) if (!il->vif || !il->is_open) return; - D_ASSOC("Associated as %d to: %pM\n", il->vif->bss_conf.aid, + D_ASSOC("Associated as %d to: %pM\n", il->vif->cfg.aid, il->active.bssid_addr); if (test_bit(S_EXIT_PENDING, &il->status)) @@ -2718,9 +2718,9 @@ il3945_post_associate(struct il_priv *il) il->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - il->staging.assoc_id = cpu_to_le16(il->vif->bss_conf.aid); + il->staging.assoc_id = cpu_to_le16(il->vif->cfg.aid); - D_ASSOC("assoc id %d beacon interval %d\n", il->vif->bss_conf.aid, + D_ASSOC("assoc id %d beacon interval %d\n", il->vif->cfg.aid, il->vif->bss_conf.beacon_int); if (il->vif->bss_conf.use_short_preamble) diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c index 9fa556486511..c34729f576cd 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965.c +++ b/drivers/net/wireless/intel/iwlegacy/4965.c @@ -1756,9 +1756,9 @@ il4965_post_associate(struct il_priv *il) if (il->ops->set_rxon_chain) il->ops->set_rxon_chain(il); - il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + il->staging.assoc_id = cpu_to_le16(vif->cfg.aid); - D_ASSOC("assoc id %d beacon interval %d\n", vif->bss_conf.aid, + D_ASSOC("assoc id %d beacon interval %d\n", vif->cfg.aid, vif->bss_conf.beacon_int); if (vif->bss_conf.use_short_preamble) @@ -1775,7 +1775,7 @@ il4965_post_associate(struct il_priv *il) il_commit_rxon(il); - D_ASSOC("Associated as %d to: %pM\n", vif->bss_conf.aid, + D_ASSOC("Associated as %d to: %pM\n", vif->cfg.aid, il->active.bssid_addr); switch (vif->type) { diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 8299d89e7505..b01945415be6 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5427,8 +5427,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes & BSS_CHANGED_ASSOC) { - D_MAC80211("ASSOC %d\n", bss_conf->assoc); - if (bss_conf->assoc) { + D_MAC80211("ASSOC %d\n", vif->cfg.assoc); + if (vif->cfg.assoc) { il->timestamp = bss_conf->sync_tsf; if (!il_is_rfkill(il)) @@ -5437,7 +5437,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, il_set_no_assoc(il, vif); } - if (changes && il_is_associated(il) && bss_conf->aid) { + if (changes && il_is_associated(il) && vif->cfg.aid) { D_MAC80211("Changes (%#x) while associated\n", changes); ret = il_send_rxon_assoc(il); if (!ret) { @@ -5459,10 +5459,10 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_IBSS) { ret = il->ops->manage_ibss_station(il, vif, - bss_conf->ibss_joined); + vif->cfg.ibss_joined); if (ret) IL_ERR("failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", + vif->cfg.ibss_joined ? "add" : "remove", bss_conf->bssid); } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 5dd2d43a01d8..17a14970edec 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -562,12 +562,12 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) slot1 = bcnint - slot0; if (test_bit(STATUS_SCAN_HW, &priv->status) || - (!ctx_bss->vif->bss_conf.idle && - !ctx_bss->vif->bss_conf.assoc)) { + (!ctx_bss->vif->cfg.idle && + !ctx_bss->vif->cfg.assoc)) { slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot1 = IWL_MIN_SLOT_TIME; - } else if (!ctx_pan->vif->bss_conf.idle && - !ctx_pan->vif->bss_conf.assoc) { + } else if (!ctx_pan->vif->cfg.idle && + !ctx_pan->vif->cfg.assoc) { slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot0 = IWL_MIN_SLOT_TIME; } @@ -1392,7 +1392,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { + if (changes & BSS_CHANGED_IDLE && vif->cfg.idle) { /* * If we go idle, then clearly no "passive-no-rx" * workaround is needed any more, this is a reset. @@ -1420,14 +1420,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, iwlagn_update_qos(priv, ctx); } - ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + ctx->staging.assoc_id = cpu_to_le16(vif->cfg.aid); if (vif->bss_conf.use_short_preamble) ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; else ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; if (changes & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { priv->timestamp = bss_conf->sync_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { @@ -1483,7 +1483,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_STATION) { - if (!bss_conf->assoc) + if (!vif->cfg.assoc) ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; else ctx->staging.filter_flags &= @@ -1493,7 +1493,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); - if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { + if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { /* * The chain noise calibration will enable PM upon * completion. If calibration has already been run @@ -1509,10 +1509,10 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_IBSS) { ret = iwlagn_manage_ibss_station(priv, vif, - bss_conf->ibss_joined); + vif->cfg.ibss_joined); if (ret) IWL_ERR(priv, "failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", + vif->cfg.ibss_joined ? "add" : "remove", bss_conf->bssid); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 8760f2c73369..ee3c8a786199 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -311,7 +311,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_DYNAMIC; /* relax SMPS constraints for next association */ - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) smps_mode = IEEE80211_SMPS_AUTOMATIC; if (mvmvif->phy_ctxt && @@ -382,7 +382,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, * we are not associated */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || - mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || + mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc || le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 8edc8646a23a..aeb0015b73d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -749,7 +749,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* add back the MAC */ mvmvif->uploaded = false; - if (WARN_ON(!vif->bss_conf.assoc)) + if (WARN_ON(!vif->cfg.assoc)) return -EINVAL; ret = iwl_mvm_mac_ctxt_add(mvm, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 430044bc4755..777c568f35a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -67,7 +67,7 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; @@ -222,7 +222,7 @@ static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, for (i = 0; i < ETH_ALEN; i++) cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); else eth_broadcast_addr(cmd->range_req_bssid); @@ -254,7 +254,7 @@ static void iwl_mvm_ftm_cmd_common(struct iwl_mvm *mvm, for (i = 0; i < ETH_ALEN; i++) cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); /* AP's TSF is only relevant if associated */ @@ -503,7 +503,7 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; @@ -693,7 +693,7 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif, target->cipher = entry->cipher; memcpy(target->hltk, entry->hltk, sizeof(target->hltk)); - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(vif->bss_conf.bssid, target->bssid, sizeof(target->bssid))) ieee80211_iter_keys(mvm->hw, vif, iter, target); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7756ac0faf3f..65df8cbb57d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -570,7 +570,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } /* We need the dtim_period to set the MAC as associated */ - if (vif->bss_conf.assoc && vif->bss_conf.dtim_period && + if (vif->cfg.assoc && vif->bss_conf.dtim_period && !force_assoc_off) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u32 dtim_offs; @@ -628,9 +628,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, vif->bss_conf.dtim_period); ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval); - ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid); + ctxt_sta->assoc_id = cpu_to_le32(vif->cfg.aid); - if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p) + if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { @@ -944,8 +944,8 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, IWL_MAC_BEACON_FILS : IWL_MAC_BEACON_FILS_V1; beacon_cmd.short_ssid = - cpu_to_le32(~crc32_le(~0, vif->bss_conf.ssid, - vif->bss_conf.ssid_len)); + cpu_to_le32(~crc32_le(~0, vif->cfg.ssid, + vif->cfg.ssid_len)); } rcu_read_unlock(); @@ -1031,7 +1031,7 @@ static void iwl_mvm_mac_ap_iterator(void *_data, u8 *mac, { struct iwl_mvm_mac_ap_iterator_data *data = _data; - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return; /* Station client has higher priority over P2P client*/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c5626ff83805..b5257b4fd000 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1614,7 +1614,7 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, return; if (vif->type != NL80211_IFTYPE_STATION || - !vif->bss_conf.assoc) + !vif->cfg.assoc) return; cmd->port_id = data->port_id++; @@ -1740,7 +1740,7 @@ static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw, return; /* Supported only for p2p client interfaces */ - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc || + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc || !vif->p2p) return; @@ -2191,7 +2191,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * on the beacon interval, which was not known when the station * interface was added. */ - if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { + if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id); @@ -2201,7 +2201,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* Update MU EDCA params */ if (changes & BSS_CHANGED_QOS && mvmvif->associated && - bss_conf->assoc && vif->bss_conf.he_support && + vif->cfg.assoc && vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id); @@ -2220,10 +2220,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* after sending it once, adopt mac80211 data */ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); - mvmvif->associated = bss_conf->assoc; + mvmvif->associated = vif->cfg.assoc; if (changes & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { /* clear statistics to get clean beacon counter */ iwl_mvm_request_statistics(mvm, true); memset(&mvmvif->beacon_stats, 0, @@ -2627,7 +2627,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) + if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle) iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); switch (vif->type) { @@ -3020,7 +3020,7 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, #if IS_ENABLED(CONFIG_IWLMEI) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mei_conn_info conn_info = { - .ssid_len = vif->bss_conf.ssid_len, + .ssid_len = vif->cfg.ssid_len, .channel = vif->bss_conf.chandef.chan->hw_value, }; @@ -3068,7 +3068,7 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, return; } - memcpy(conn_info.ssid, vif->bss_conf.ssid, vif->bss_conf.ssid_len); + memcpy(conn_info.ssid, vif->cfg.ssid, vif->cfg.ssid_len); memcpy(conn_info.bssid, vif->bss_conf.bssid, ETH_ALEN); /* TODO: add support for collocated AP data */ @@ -3381,7 +3381,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (!vif->bss_conf.idle) { + if (!vif->cfg.idle) { ret = -EBUSY; goto out; } @@ -3747,7 +3747,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, * like the delay to be for 2-3 dtim intervals, in case there are * other time events with higher priority. */ - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY); /* We cannot remain off-channel longer than the DTIM interval */ if (dtim_interval <= req_dur) { @@ -4502,7 +4502,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, case IWL_MVM_TM_CMD_SET_BEACON_FILTER: /* must be associated client vif - ignore authorized */ if (!vif || vif->type != NL80211_IFTYPE_STATION || - !vif->bss_conf.assoc || !vif->bss_conf.dtim_period || + !vif->cfg.assoc || !vif->bss_conf.dtim_period || !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) return -EINVAL; @@ -4670,7 +4670,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, * we don't know the dtim period. In this case, the firmware can't * track the beacons. */ - if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period) { + if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) { ret = -EBUSY; goto out_unlock; } @@ -5069,7 +5069,7 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index c7dabc6b3765..a8bd0f5f795c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2021-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -192,9 +192,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, size = sizeof(cmd.v1); } - if (vif->bss_conf.arp_addr_cnt) { + if (vif->cfg.arp_addr_cnt) { enabled |= IWL_D3_PROTO_OFFLOAD_ARP | IWL_D3_PROTO_IPV4_VALID; - common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; + common->host_ipv4_addr = vif->cfg.arp_addr_list[0]; memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index b2f33ebdf485..db43c8a83a31 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -162,7 +162,7 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, vif->bss_conf.chandef.width < NL80211_CHAN_WIDTH_40) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; /* this shouldn't happen *again*, ignore it */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index afdf3bb523e9..b49f265a421f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -223,7 +223,7 @@ static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac, *is_p2p_standalone = false; break; case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) *is_p2p_standalone = false; break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c index c862bd243b55..cea1a34f9130 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2021-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -47,7 +47,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) break; return; case NL80211_IFTYPE_AP: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index a4077053e374..582a95ffc7ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1948,14 +1948,14 @@ static void iwl_mvm_scan_6ghz_passive_scan(struct iwl_mvm *mvm, * reset or resume flow, or while not associated and a large interval * has passed since the last 6GHz passive scan. */ - if ((vif->bss_conf.assoc || + if ((vif->cfg.assoc || time_after(mvm->last_6ghz_passive_scan_jiffies + (IWL_MVM_6GHZ_PASSIVE_SCAN_TIMEOUT * HZ), jiffies)) && (time_before(mvm->last_reset_or_resume_time_jiffies + (IWL_MVM_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT * HZ), jiffies))) { IWL_DEBUG_SCAN(mvm, "6GHz passive scan: %s\n", - vif->bss_conf.assoc ? "associated" : + vif->cfg.assoc ? "associated" : "timeout did not expire"); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 693752d8f65b..1f4ac1e93cee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2019 Intel Corporation + * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #include "mvm.h" @@ -31,7 +31,7 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) { data->sta_vif_ap_sta_id = mvmvif->ap_sta_id; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) data->sta_vif_state = SF_FULL_ON; else data->sta_vif_state = SF_INIT_OFF; @@ -261,7 +261,7 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, return -EINVAL; if (changed_vif->type != NL80211_IFTYPE_STATION) { new_state = SF_UNINIT; - } else if (changed_vif->bss_conf.assoc && + } else if (changed_vif->cfg.assoc && changed_vif->bss_conf.dtim_period) { mvmvif = iwl_mvm_vif_from_mac80211(changed_vif); sta_id = mvmvif->ap_sta_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bbb1522e7280..b296f4965895 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1948,7 +1948,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION && mvmvif->ap_sta_id == sta_id) { /* if associated - we can't remove the AP STA now */ - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) return ret; /* unassoc - go ahead - remove the AP STA now */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 4f0794a45bf5..ed8ba81a6043 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -160,7 +160,7 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, if (vif->type != NL80211_IFTYPE_STATION) return false; - if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc && + if (!mvmvif->csa_bcn_pending && vif->cfg.assoc && vif->bss_conf.dtim_period) return false; if (errmsg) @@ -176,7 +176,7 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, rcu_read_unlock(); } - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { /* * When not associated, this will be called from * iwl_mvm_event_mlme_callback_ini() @@ -346,7 +346,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, - !te_data->vif->bss_conf.assoc ? + !te_data->vif->cfg.assoc ? "Not associated and the time event is over already..." : "No beacon heard and the time event is over already..."); break; @@ -859,7 +859,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, vif, - !vif->bss_conf.assoc ? + !vif->cfg.assoc ? "Not associated and the session protection is over already..." : "No beacon heard and the session protection is over already..."); spin_lock_bh(&mvm->time_event_lock); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index bc947733d982..3ee5ea3484be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -604,7 +604,7 @@ static void iwl_mvm_sta_iface_iterator(void *_data, u8 *mac, if (vif->type != NL80211_IFTYPE_STATION) return; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) data->assoc = true; } @@ -816,7 +816,7 @@ static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm, if (vif->type != NL80211_IFTYPE_STATION) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; if (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd && diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index a3ca6620dc0c..a9dfe6a3da0d 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -480,8 +480,8 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, p54_scan(priv, P54_SCAN_EXIT, 0); } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { - priv->aid = info->aid; + if (vif->cfg.assoc) { + priv->aid = vif->cfg.aid; priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; p54_setup_mac(priv); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5905803893b8..5aaf34f6f43b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2118,9 +2118,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", - info->assoc, info->aid); - vp->assoc = info->assoc; - vp->aid = info->aid; + vif->cfg.assoc, vif->cfg.aid); + vp->assoc = vif->cfg.assoc; + vp->aid = vif->cfg.aid; } if (changed & BSS_CHANGED_BEACON_ENABLED) { diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 36c24d17136c..5f1bcfb5e3f6 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -3250,7 +3250,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(vif->bss_conf.aid); + cmd->aid = cpu_to_le16(vif->cfg.aid); memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); if (vif->bss_conf.use_cts_prot) { @@ -5013,13 +5013,13 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* * No need to capture a beacon if we're no longer associated. */ - if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) + if ((changed & BSS_CHANGED_ASSOC) && !vif->cfg.assoc) priv->capture_beacon = false; /* * Get the AP's legacy and MCS rates. */ - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *ap; rcu_read_lock(); @@ -5085,7 +5085,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if (vif->bss_conf.assoc && !priv->ap_fw && + if (vif->cfg.assoc && !priv->ap_fw && (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))) { rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); @@ -5093,7 +5093,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { /* * Finalize the join. Tell rx handler to process diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 91425b454cae..1f14ecda1f55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -305,7 +305,7 @@ mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID)) { - if (info->assoc || info->ibss_joined) { + if (vif->cfg.assoc || vif->cfg.ibss_joined) { mt76_wr(dev, MT_BSSID0(mvif->idx), get_unaligned_le32(info->bssid)); mt76_wr(dev, MT_BSSID1(mvif->idx), diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index a9c9b97d173e..d992fdea0f32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -616,7 +616,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) - mt7615_mac_set_beacon_filter(phy, vif, info->assoc); + mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc); mt7615_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 8fb6c9d735dc..f58376733c67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2530,7 +2530,7 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, u8 pad; } req = { .bss_idx = mvif->mt76.idx, - .aid = cpu_to_le16(vif->bss_conf.aid), + .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index faa279bbbcb2..d3da54e6670b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -402,7 +402,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, else conn_type = CONNECTION_INFRA_AP; basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(vif->bss_conf.aid); + basic->aid = cpu_to_le16(vif->cfg.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); @@ -546,7 +546,7 @@ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, if (sta) { if (vif->type == NL80211_IFTYPE_STATION) - generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); + generic->partial_aid = cpu_to_le16(vif->cfg.aid); else generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); @@ -2157,8 +2157,10 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, struct mt76_vif *vif, struct ieee80211_bss_conf *info) { + struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif, + bss_conf); struct sk_buff *skb; - int i, len = min_t(int, info->arp_addr_cnt, + int i, len = min_t(int, mvif->cfg.arp_addr_cnt, IEEE80211_BSS_ARP_ADDR_LIST_LEN); struct { struct { @@ -2186,7 +2188,7 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, skb_put_data(skb, &req_hdr, sizeof(req_hdr)); for (i = 0; i < len; i++) - skb_put_data(skb, &info->arp_addr_list[i], sizeof(__be32)); + skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 710ca757fb52..05327b0b6fc3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -593,7 +593,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - mt7915_mcu_add_bss_info(phy, vif, info->assoc); + mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc); mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 80279f342109..8532033794bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -678,7 +678,7 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); if (dev->pm.enable) - mt7921_mcu_set_beacon_filter(dev, vif, info->assoc); + mt7921_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); } if (changed & BSS_CHANGED_ARP_FILTER) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 12bab18c4171..64fc400bd981 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1036,7 +1036,7 @@ mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, u8 pad; } req = { .bss_idx = mvif->mt76.idx, - .aid = cpu_to_le16(vif->bss_conf.aid), + .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 8a00f6a75ca9..d4cd2215aba9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -1097,7 +1097,10 @@ static void mt7601u_phy_freq_cal(struct work_struct *work) void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, struct ieee80211_bss_conf *info) { - if (!info->assoc) + struct ieee80211_vif *vif = container_of(info, struct ieee80211_vif, + bss_conf); + + if (!vif->cfg.assoc) cancel_delayed_work_sync(&dev->freq_cal.work); /* Start/stop collecting beacon data */ @@ -1108,10 +1111,10 @@ void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, spin_unlock_bh(&dev->con_mon_lock); dev->freq_cal.freq = dev->ee->rf_freq_off; - dev->freq_cal.enabled = info->assoc; + dev->freq_cal.enabled = vif->cfg.assoc; dev->freq_cal.adjusting = false; - if (info->assoc) + if (vif->cfg.assoc) ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, MT_FREQ_CAL_INIT_DELAY); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c index 6bafdd991171..f895f560a185 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c @@ -70,6 +70,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct ieee80211_bss_conf *bss_conf, u32 changed) { + struct ieee80211_vif *vif = container_of(bss_conf, struct ieee80211_vif, + bss_conf); struct rt2x00lib_erp erp; memset(&erp, 0, sizeof(erp)); @@ -87,7 +89,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.beacon_int = bss_conf->beacon_int; /* Update the AID, this is needed for dynamic PS support */ - rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; + rt2x00dev->aid = vif->cfg.assoc ? vif->cfg.aid : 0; rt2x00dev->last_beacon = bss_conf->sync_tsf; /* Update global beacon interval time, this is needed for PS support */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index dea5babd30fe..660554a01894 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -645,7 +645,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { rt2x00dev->link.count = 0; - if (bss_conf->assoc) + if (vif->cfg.assoc) rt2x00dev->intf_associated++; else rt2x00dev->intf_associated--; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 8b2ca9e8eac6..0239e12ec8a5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4570,11 +4570,11 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rarpt = &priv->ra_report; if (changed & BSS_CHANGED_ASSOC) { - dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc); + dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc); rtl8xxxu_set_linktype(priv, vif->type); - if (bss_conf->assoc) { + if (vif->cfg.assoc) { u32 ramask; int sgi = 0; u8 highest_rate; @@ -4639,7 +4639,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* joinbss sequence */ rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, - 0xc000 | bss_conf->aid); + 0xc000 | vif->cfg.aid); priv->fops->report_connect(priv, 0, true); } else { @@ -5405,7 +5405,7 @@ void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->bss_conf.assoc); + wifi_connected = (vif && vif->cfg.assoc); if (!wifi_connected) { rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); @@ -5431,7 +5431,7 @@ void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->bss_conf.assoc); + wifi_connected = (vif && vif->cfg.assoc); if (wifi_connected) { u32 val32 = 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 99a1d91ced5a..5177eb02740e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1094,7 +1094,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { u8 mstatus; - if (bss_conf->assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *sta = NULL; u8 keep_alive = 10; @@ -1111,7 +1111,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; - mac->assoc_id = bss_conf->aid; + mac->assoc_id = vif->cfg.aid; memcpy(mac->bssid, bss_conf->bssid, ETH_ALEN); if (rtlpriv->cfg->ops->linked_set_reg) diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index e76841d3417b..76c7f3257dd3 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -67,7 +67,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, ether_addr_copy(bfee->mac_addr, bssid); bfee->role = RTW_BFEE_MU; bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); - bfee->aid = bss_conf->aid; + bfee->aid = vif->cfg.aid; bfinfo->bfer_mu_cnt++; rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 4310362dc333..c5954c18862d 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -369,12 +369,12 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { rtw_vif_assoc_changed(rtwvif, conf); - if (conf->assoc) { + if (vif->cfg.assoc) { rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH); rtw_fw_download_rsvd_page(rtwdev); rtw_send_rsvd_page_h2c(rtwdev); - rtw_coex_media_status_notify(rtwdev, conf->assoc); + rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc); if (rtw_bf_support) rtw_bf_assoc(rtwdev, vif, conf); rtw_store_op_chan(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a44b1810165d..f78b9f28d5f6 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -171,7 +171,7 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; if (vif->type == NL80211_IFTYPE_STATION) - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) iter_data->rtwvif = rtwvif; rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); @@ -525,8 +525,13 @@ EXPORT_SYMBOL(rtw_dump_reg); void rtw_vif_assoc_changed(struct rtw_vif *rtwvif, struct ieee80211_bss_conf *conf) { - if (conf && conf->assoc) { - rtwvif->aid = conf->aid; + struct ieee80211_vif *vif = NULL; + + if (conf) + vif = container_of(conf, struct ieee80211_vif, bss_conf); + + if (conf && vif->cfg.assoc) { + rtwvif->aid = vif->cfg.aid; rtwvif->net_type = RTW_NET_MGD_LINKED; } else { rtwvif->aid = 0; @@ -1591,7 +1596,7 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, { struct rtw_dev *rtwdev = (struct rtw_dev *)data; - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return; if (rtwdev->hal.txrx_1ss) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index db3c55f0ccd0..cfa939e26ffd 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -701,7 +701,7 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) - FWCMD_SET_ADDR_AID12(cmd, vif->bss_conf.aid & 0xfff); + FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff); else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d2f2a3d65ef6..bd7b66e98480 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1374,7 +1374,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, if (aid == RTW89_TF_PAD) break; - if (aid == vif->bss_conf.aid) { + if (aid == vif->cfg.aid) { rtwvif->stats.rx_tf_acc++; rtwdev->stats.rx_tf_acc++; break; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 239d47d0ec6d..cf60adaed64a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3715,7 +3715,7 @@ void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_chip_info *chip = rtwdev->chip; - if (!vif->bss_conf.he_support || !vif->bss_conf.assoc) + if (!vif->bss_conf.he_support || !vif->cfg.assoc) return; if (chip->ops->set_txpwr_ul_tb_offset) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 6d0c62c545a7..ac8b9bf2b0bb 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -345,7 +345,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, rtw89_leave_ps_mode(rtwdev); if (changed & BSS_CHANGED_ASSOC) { - if (conf->assoc) { + if (vif->cfg.assoc) { rtw89_station_mode_sta_assoc(rtwdev, vif, conf); rtw89_phy_set_bss_color(rtwdev, vif); rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 217aacb6e8c1..af89c011b0db 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3630,7 +3630,7 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif enum rtw89_phy_idx phy_idx = RTW89_PHY_0; u8 bss_color; - if (!vif->bss_conf.he_support || !vif->bss_conf.assoc) + if (!vif->bss_conf.he_support || !vif->cfg.assoc) return; bss_color = vif->bss_conf.he_bss_color.color; @@ -3640,7 +3640,7 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_TGT, bss_color, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_STAID, - vif->bss_conf.aid, phy_idx); + vif->cfg.aid, phy_idx); } static void diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 6bfaab48b507..0f3a80f66b61 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -420,7 +420,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) rsi_hal_send_sta_notify_frame(common, RSI_IFTYPE_STATION, STA_CONNECTED, bss->bssid, - bss->qos, bss->aid, 0, + bss->qos, vif->cfg.aid, + 0, vif); } diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index dca81a4bbdd7..d3634ad986ac 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -295,7 +295,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; int status = -EINVAL; if (!skb) @@ -307,11 +306,10 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) if (!info->control.vif) goto err; vif = info->control.vif; - bss = &vif->bss_conf; if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && - (!bss->assoc)) + (!vif->cfg.assoc)) goto err; status = rsi_send_pkt_to_bus(common, skb); @@ -367,7 +365,8 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; /* Indicate to firmware to give cfm for probe */ - if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) { + if (ieee80211_is_probe_req(wh->frame_control) && + !info->control.vif->cfg.assoc) { rsi_dbg(INFO_ZONE, "%s: blocking mgmt queue\n", __func__); mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index f01e82b90c07..d4b3834388ab 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -237,7 +237,6 @@ static int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, struct cfg80211_scan_request *scan_req = &hw_req->req; struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; - struct ieee80211_bss_conf *bss = &vif->bss_conf; rsi_dbg(INFO_ZONE, "***** Hardware scan start *****\n"); common->mac_ops_resumed = false; @@ -256,7 +255,7 @@ static int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, /* If STA is not connected, return with special value 1, in order * to start sw_scan in mac80211 */ - if (!bss->assoc) + if (!vif->cfg.assoc) return 1; mutex_lock(&common->mutex); @@ -579,7 +578,6 @@ static int rsi_channel_change(struct ieee80211_hw *hw) struct ieee80211_channel *curchan = hw->conf.chandef.chan; u16 channel = curchan->hw_value; struct ieee80211_vif *vif; - struct ieee80211_bss_conf *bss; bool assoc = false; int i; @@ -593,8 +591,7 @@ static int rsi_channel_change(struct ieee80211_hw *hw) if (!vif) continue; if (vif->type == NL80211_IFTYPE_STATION) { - bss = &vif->bss_conf; - if (bss->assoc) { + if (vif->cfg.assoc) { assoc = true; break; } @@ -700,7 +697,7 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, } if ((vif->type == NL80211_IFTYPE_STATION || vif->type == NL80211_IFTYPE_P2P_CLIENT) && - (!sta_vif || vif->bss_conf.assoc)) + (!sta_vif || vif->cfg.assoc)) sta_vif = vif; } if (set_ps && sta_vif) { @@ -797,8 +794,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&common->mutex); if (changed & BSS_CHANGED_ASSOC) { rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", - __func__, bss_conf->assoc); - if (bss_conf->assoc) { + __func__, vif->cfg.assoc); + if (vif->cfg.assoc) { /* Send the RX filter frame */ rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER | @@ -807,17 +804,17 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, } rsi_inform_bss_status(common, RSI_OPMODE_STA, - bss_conf->assoc, + vif->cfg.assoc, bss_conf->bssid, bss_conf->qos, - bss_conf->aid, + vif->cfg.aid, NULL, 0, bss_conf->assoc_capability, vif); adapter->ps_info.dtim_interval_duration = bss->dtim_period; adapter->ps_info.listen_interval = conf->listen_interval; /* If U-APSD is updated, send ps parameters to firmware */ - if (bss->assoc) { + if (vif->cfg.assoc) { if (common->uapsd_bitmap) { rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); rsi_conf_uapsd(adapter, vif); @@ -1359,7 +1356,7 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, if (!bss) return; /* CQM only for connected AP beacons, the RSSI is a weighted avg */ - if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { + if (vif->cfg.assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { if (ieee80211_is_beacon(hdr->frame_control)) rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif); } @@ -1737,7 +1734,7 @@ static void rsi_resume_conn_channel(struct rsi_common *common) } if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && - vif->bss_conf.assoc) { + vif->cfg.assoc) { rsi_switch_channel(adapter, vif); break; } @@ -1862,17 +1859,15 @@ static u16 rsi_wow_map_triggers(struct rsi_common *common, int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) { struct rsi_common *common = adapter->priv; + struct ieee80211_vif *vif = adapter->vifs[0]; u16 triggers = 0; u16 rx_filter_word = 0; - struct ieee80211_bss_conf *bss = NULL; rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); - if (!adapter->vifs[0]) + if (!vif) return -EINVAL; - bss = &adapter->vifs[0]->bss_conf; - if (WARN_ON(!wowlan)) { rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); return -EINVAL; @@ -1884,7 +1879,7 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); return -EINVAL; } - if (!bss->assoc) { + if (!vif->cfg.assoc) { rsi_dbg(ERR_ZONE, "Cannot configure WoWLAN (Station not connected)\n"); common->wow_flags |= RSI_WOW_NO_CONNECTION; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index c14689266fec..1b309e47a1f1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1635,7 +1635,6 @@ int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, struct ieee80211_vif *vif) { struct rsi_common *common = adapter->priv; - struct ieee80211_bss_conf *bss = &vif->bss_conf; struct rsi_request_ps *ps; struct rsi_ps_info *ps_info; struct sk_buff *skb; @@ -1669,7 +1668,7 @@ int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, ps->ps_sleep.sleep_duration = cpu_to_le32(ps_info->deep_sleep_wakeup_period); - if (bss->assoc) + if (vif->cfg.assoc) ps->ps_sleep.connected_sleep = RSI_CONNECTED_SLEEP; else ps->ps_sleep.connected_sleep = RSI_DEEP_SLEEP; diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c index d35dd940d968..9402503fbde3 100644 --- a/drivers/net/wireless/silabs/wfx/hif_tx.c +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -282,6 +282,8 @@ int wfx_hif_stop_scan(struct wfx_vif *wvif) int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, struct ieee80211_channel *channel, const u8 *ssid, int ssid_len) { + struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif, + bss_conf); int ret; struct wfx_hif_msg *hif; struct wfx_hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); @@ -289,10 +291,10 @@ int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, WARN_ON(!conf->beacon_int); WARN_ON(!conf->basic_rates); WARN_ON(sizeof(body->ssid) < ssid_len); - WARN(!conf->ibss_joined && !ssid_len, "joining an unknown BSS"); + WARN(!vif->cfg.ibss_joined && !ssid_len, "joining an unknown BSS"); if (!hif) return -ENOMEM; - body->infrastructure_bss_mode = !conf->ibss_joined; + body->infrastructure_bss_mode = !vif->cfg.ibss_joined; body->short_preamble = conf->use_short_preamble; body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR); body->channel_number = channel->hw_value; @@ -417,6 +419,8 @@ int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, const struct ieee80211_channel *channel) { + struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif, + bss_conf); int ret; struct wfx_hif_msg *hif; struct wfx_hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); @@ -429,8 +433,8 @@ int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, body->channel_number = channel->hw_value; body->beacon_interval = cpu_to_le32(conf->beacon_int); body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); - body->ssid_length = conf->ssid_len; - memcpy(body->ssid, conf->ssid, conf->ssid_len); + body->ssid_length = vif->cfg.ssid_len; + memcpy(body->ssid, vif->cfg.ssid, vif->cfg.ssid_len); wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); kfree(hif); diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 329d7f4a2b2e..79fafe8143d9 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -156,7 +156,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) struct ieee80211_conf *conf = &wvif->wdev->hw->conf; struct ieee80211_vif *vif = wvif_to_vif(wvif); - WARN(!vif->bss_conf.assoc && enable_ps, + WARN(!vif->cfg.assoc && enable_ps, "enable_ps is reliable only if associated"); if (wdev_to_wvif(wvif->wdev, 0)) { struct wfx_vif *wvif_ch0 = wdev_to_wvif(wvif->wdev, 0); @@ -175,7 +175,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) /* It is useless to enable PS if channels are the same. */ if (enable_ps) *enable_ps = false; - if (vif->bss_conf.assoc && vif->bss_conf.ps) + if (vif->cfg.assoc && vif->bss_conf.ps) dev_info(wvif->wdev->dev, "ignoring requested PS mode"); return -1; } @@ -189,7 +189,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) } if (enable_ps) *enable_ps = vif->bss_conf.ps; - if (vif->bss_conf.assoc && vif->bss_conf.ps) + if (vif->cfg.assoc && vif->bss_conf.ps) return conf->dynamic_ps_timeout; else return -1; @@ -201,7 +201,7 @@ int wfx_update_pm(struct wfx_vif *wvif) int ps_timeout; bool ps; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return 0; ps_timeout = wfx_get_ps_timeout(wvif, &ps); if (!ps) @@ -417,7 +417,7 @@ static void wfx_join(struct wfx_vif *wvif) bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, conf->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { + if (!bss && !vif->cfg.ibss_joined) { wfx_tx_unlock(wvif->wdev); return; } @@ -458,7 +458,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *i bool greenfield = false; rcu_read_lock(); /* protect sta */ - if (info->bssid && !info->ibss_joined) + if (info->bssid && !vif->cfg.ibss_joined) sta = ieee80211_find_sta(vif, info->bssid); if (sta && sta->deflink.ht_cap.ht_supported) ampdu_density = sta->deflink.ht_cap.ampdu_density; @@ -471,7 +471,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *i wfx_hif_set_association_mode(wvif, ampdu_density, greenfield, info->use_short_preamble); wfx_hif_keep_alive_period(wvif, 0); /* beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use the same value. */ - wfx_hif_set_bss_params(wvif, info->aid, 7); + wfx_hif_set_bss_params(wvif, vif->cfg.aid, 7); wfx_hif_set_beacon_wakeup_period(wvif, 1, 1); wfx_update_pm(wvif); } @@ -522,9 +522,9 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc || info->ibss_joined) + if (vif->cfg.assoc || vif->cfg.ibss_joined) wfx_join_finalize(wvif, info); - else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) + else if (!vif->cfg.assoc && vif->type == NL80211_IFTYPE_STATION) wfx_reset(wvif); else dev_warn(wdev->dev, "misunderstood change: ASSOC\n"); @@ -540,11 +540,11 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ARP_FILTER) { for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { - __be32 *arp_addr = &info->arp_addr_list[i]; + __be32 *arp_addr = &vif->cfg.arp_addr_list[i]; - if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) + if (vif->cfg.arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) arp_addr = NULL; - if (i >= info->arp_addr_cnt) + if (i >= vif->cfg.arp_addr_cnt) arp_addr = NULL; wfx_hif_set_arp_ipv4_filter(wvif, i, arp_addr); } diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 321df124d449..3f48def51ebc 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1208,8 +1208,8 @@ static void cw1200_do_join(struct cw1200_common *priv) struct cfg80211_bss *bss = NULL; struct wsm_protected_mgmt_policy mgmt_policy; struct wsm_join join = { - .mode = conf->ibss_joined ? - WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, + .mode = priv->vif->cfg.ibss_joined ? + WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, .preamble_type = WSM_JOIN_PREAMBLE_LONG, .probe_for_join = 1, .atim_window = 0, @@ -1230,7 +1230,7 @@ static void cw1200_do_join(struct cw1200_common *priv) bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { + if (!bss && !priv->vif->cfg.ibss_joined) { wsm_unlock_tx(priv); return; } @@ -1284,7 +1284,7 @@ static void cw1200_do_join(struct cw1200_common *priv) join.bssid, join.dtim_period, priv->beacon_int); - if (!conf->ibss_joined) { + if (!priv->vif->cfg.ibss_joined) { const u8 *ssidie; rcu_read_lock(); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); @@ -1302,7 +1302,7 @@ static void cw1200_do_join(struct cw1200_common *priv) } /* Enable asynchronous join calls */ - if (!conf->ibss_joined) { + if (!priv->vif->cfg.ibss_joined) { join.flags |= WSM_JOIN_FLAGS_FORCE; join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND; } @@ -1813,15 +1813,15 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, int i; pr_debug("[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", - info->arp_addr_cnt); + vif->cfg.arp_addr_cnt); /* Currently only one IP address is supported by firmware. * In case of more IPs arp filtering will be disabled. */ - if (info->arp_addr_cnt > 0 && - info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { - for (i = 0; i < info->arp_addr_cnt; i++) { - filter.ipv4addrs[i] = info->arp_addr_list[i]; + if (vif->cfg.arp_addr_cnt > 0 && + vif->cfg.arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { + for (i = 0; i < vif->cfg.arp_addr_cnt; i++) { + filter.ipv4addrs[i] = vif->cfg.arp_addr_list[i]; pr_debug("[STA] addr[%d]: 0x%X\n", i, filter.ipv4addrs[i]); } @@ -1857,7 +1857,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, if (changed & BSS_CHANGED_BEACON_INT) { pr_debug("CHANGED_BEACON_INT\n"); - if (info->ibss_joined) + if (vif->cfg.ibss_joined) do_join = true; else if (priv->join_status == CW1200_JOIN_STATUS_AP) cw1200_update_beaconing(priv); @@ -1882,7 +1882,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, BSS_CHANGED_BASIC_RATES | BSS_CHANGED_HT)) { pr_debug("BSS_CHANGED_ASSOC\n"); - if (info->assoc) { + if (vif->cfg.assoc) { if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) { ieee80211_connection_loss(vif); mutex_unlock(&priv->conf_mutex); @@ -1894,7 +1894,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, do_join = true; } - if (info->assoc || info->ibss_joined) { + if (vif->cfg.assoc || vif->cfg.ibss_joined) { struct ieee80211_sta *sta = NULL; __le32 htprot = 0; @@ -1904,7 +1904,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, rcu_read_lock(); - if (info->bssid && !info->ibss_joined) + if (info->bssid && !vif->cfg.ibss_joined) sta = ieee80211_find_sta(vif, info->bssid); if (sta) { priv->ht_info.ht_cap = sta->deflink.ht_cap; @@ -1958,7 +1958,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, cancel_work_sync(&priv->unjoin_work); priv->bss_params.beacon_lost_count = priv->cqm_beacon_loss_count; - priv->bss_params.aid = info->aid; + priv->bss_params.aid = vif->cfg.aid; if (priv->join_dtim_period < 1) priv->join_dtim_period = 1; @@ -1973,7 +1973,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, priv->association_mode.basic_rate_set); wsm_set_association_mode(priv, &priv->association_mode); - if (!info->ibss_joined) { + if (!vif->cfg.ibss_joined) { wsm_keep_alive_period(priv, 30 /* sec */); wsm_set_bss_params(priv, &priv->bss_params); priv->setbssparams_done = true; @@ -2330,8 +2330,8 @@ static int cw1200_start_ap(struct cw1200_common *priv) memset(start.ssid, 0, sizeof(start.ssid)); if (!conf->hidden_ssid) { - start.ssid_len = conf->ssid_len; - memcpy(start.ssid, conf->ssid, start.ssid_len); + start.ssid_len = priv->vif->cfg.ssid_len; + memcpy(start.ssid, priv->vif->cfg.ssid, start.ssid_len); } priv->beacon_int = conf->beacon_int; diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index 7de666b90ff5..fde21fca6c5e 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -1183,8 +1183,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, /* Disable beacon filter once we're associated... */ if (priv->disable_beacon_filter && - (priv->vif->bss_conf.assoc || - priv->vif->bss_conf.ibss_joined)) { + (priv->vif->cfg.assoc || + priv->vif->cfg.ibss_joined)) { priv->disable_beacon_filter = false; queue_work(priv->workqueue, &priv->update_filtering_work); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index a25a6143e65f..bdc93c4f54ba 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1123,7 +1123,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { wl->beacon_int = bss_conf->beacon_int; skb = ieee80211_pspoll_get(wl->hw, wl->vif); @@ -1137,7 +1137,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - ret = wl1251_acx_aid(wl, bss_conf->aid); + ret = wl1251_acx_aid(wl, vif->cfg.aid); if (ret < 0) goto out_sleep; } else { @@ -1176,10 +1176,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ARP_FILTER) { - __be32 addr = bss_conf->arp_addr_list[0]; + __be32 addr = vif->cfg.arp_addr_list[0]; WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); - enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; + enable = vif->cfg.arp_addr_cnt == 1 && vif->cfg.assoc; ret = wl1251_acx_arp_ip_filter(wl, enable, addr); if (ret < 0) goto out_sleep; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index df6029ef6304..138edd28b0de 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -675,8 +675,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); } else { cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; - cmd->ap.ssid_len = bss_conf->ssid_len; - memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + cmd->ap.ssid_len = vif->cfg.ssid_len; + memcpy(cmd->ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); } supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 21a9e3b0cbac..ad9560bd9512 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2904,10 +2904,12 @@ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_bss_conf *bss_conf, u32 sta_rate_set) { + struct ieee80211_vif *vif = container_of(bss_conf, struct ieee80211_vif, + bss_conf); int ieoffset; int ret; - wlvif->aid = bss_conf->aid; + wlvif->aid = vif->cfg.aid; wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); wlvif->beacon_int = bss_conf->beacon_int; wlvif->wmm_enabled = bss_conf->qos; @@ -3935,7 +3937,6 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, u32 rates) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; int ssid_ie_offset, ie_offset, templ_len; const u8 *ptr; @@ -3948,7 +3949,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, probe_rsp_len, 0, rates); - if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + if (probe_rsp_len + vif->cfg.ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { wl1271_error("probe_rsp template too big"); return -EINVAL; } @@ -3970,12 +3971,12 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, /* insert SSID from bss_conf */ probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; - probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + probe_rsp_templ[ssid_ie_offset + 1] = vif->cfg.ssid_len; memcpy(probe_rsp_templ + ssid_ie_offset + 2, - bss_conf->ssid, bss_conf->ssid_len); - templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + vif->cfg.ssid, vif->cfg.ssid_len); + templ_len = ssid_ie_offset + 2 + vif->cfg.ssid_len; - memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + vif->cfg.ssid_len, ptr, probe_rsp_len - (ptr - probe_rsp_data)); templ_len += probe_rsp_len - (ptr - probe_rsp_data); @@ -4255,15 +4256,15 @@ out: } static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_bss_conf *bss_conf, - u32 sta_rate_set) + struct ieee80211_vif *vif, u32 sta_rate_set) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u32 rates; int ret; wl1271_debug(DEBUG_MAC80211, "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x", - bss_conf->bssid, bss_conf->aid, + bss_conf->bssid, vif->cfg.aid, bss_conf->beacon_int, bss_conf->basic_rates, sta_rate_set); @@ -4351,7 +4352,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_IBSS) { - if (bss_conf->ibss_joined) { + if (vif->cfg.ibss_joined) { set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); ibss_joined = true; } else { @@ -4375,7 +4376,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_IDLE && !is_ibss) - wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); + wl1271_sta_handle_idle(wl, wlvif, vif->cfg.idle); if (changed & BSS_CHANGED_CQM) { bool enable = false; @@ -4411,7 +4412,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (changed & BSS_CHANGED_BSSID) { if (!is_zero_ether_addr(bss_conf->bssid)) { - ret = wlcore_set_bssid(wl, wlvif, bss_conf, + ret = wlcore_set_bssid(wl, wlvif, vif, sta_rate_set); if (ret < 0) goto out; @@ -4427,9 +4428,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (changed & BSS_CHANGED_IBSS) { wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", - bss_conf->ibss_joined); + vif->cfg.ibss_joined); - if (bss_conf->ibss_joined) { + if (vif->cfg.ibss_joined) { u32 rates = bss_conf->basic_rates; wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, @@ -4466,7 +4467,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { ret = wlcore_set_assoc(wl, wlvif, bss_conf, sta_rate_set); if (ret < 0) @@ -4541,11 +4542,11 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* Handle arp filtering. Done after join. */ if ((changed & BSS_CHANGED_ARP_FILTER) || (!is_ibss && (changed & BSS_CHANGED_QOS))) { - __be32 addr = bss_conf->arp_addr_list[0]; + __be32 addr = vif->cfg.arp_addr_list[0]; wlvif->sta.qos = bss_conf->qos; WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); - if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) { + if (vif->cfg.arp_addr_cnt == 1 && vif->cfg.assoc) { wlvif->ip_addr = addr; /* * The template should have been configured only upon diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index afaf331fe125..8c5de30478ec 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -979,7 +979,7 @@ static void vnt_check_bb_vga(struct vnt_private *priv) if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) return; - if (!(priv->vif->bss_conf.assoc && priv->current_rssi)) + if (!(priv->vif->cfg.assoc && priv->current_rssi)) return; RFvRSSITodBm(priv, (u8)priv->current_rssi, &dbm); @@ -1399,7 +1399,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, { struct vnt_private *priv = hw->priv; - priv->current_aid = conf->aid; + priv->current_aid = vif->cfg.aid; if (changed & BSS_CHANGED_BSSID && conf->bssid) { unsigned long flags; @@ -1468,7 +1468,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && priv->op_mode != NL80211_IFTYPE_AP) { - if (conf->assoc && conf->beacon_rate) { + if (vif->cfg.assoc && conf->beacon_rate) { CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, conf->sync_tsf); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index ae7f5916d4d6..3ab8a7bb9715 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -749,7 +749,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, { struct vnt_private *priv = hw->priv; - priv->current_aid = conf->aid; + priv->current_aid = vif->cfg.aid; if (changed & BSS_CHANGED_BSSID && conf->bssid) vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid); @@ -811,7 +811,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && priv->op_mode != NL80211_IFTYPE_AP) { - if (conf->assoc && conf->beacon_rate) { + if (vif->cfg.assoc && conf->beacon_rate) { u16 ps_beacon_int = conf->beacon_int; if (conf->dtim_period) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e3ded46f70ac..1520922d21a5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -526,11 +526,6 @@ struct ieee80211_fils_discovery { * mode only, set if the AP advertises TWT responder role) * @twt_protected: does this BSS support protected TWT frames * @twt_broadcast: does this BSS support broadcast TWT - * @assoc: association status - * @ibss_joined: indicates whether this station is part of an IBSS - * or not - * @ibss_creator: indicates if a new IBSS network is being created - * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble * @use_short_slot: use short slot time (only relevant for ERP) @@ -551,6 +546,8 @@ struct ieee80211_fils_discovery { * IMPORTANT: These three sync_* parameters would possibly be out of sync * by the time the driver will use them. The synchronized view is currently * guaranteed only in certain callbacks. + * Note also that this is not used with MLD associations, mac80211 doesn't + * know how to track beacons for all of the links for this. * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp * @basic_rates: bitmap of basic rates, each bit stands for an @@ -576,21 +573,9 @@ struct ieee80211_fils_discovery { * threshold event and can't be enabled simultaneously with it. * @cqm_rssi_high: Connection quality monitor RSSI upper threshold. * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis - * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The - * may filter ARP queries targeted for other addresses than listed here. - * The driver must allow ARP queries targeted for all address listed here - * to pass through. An empty list implies no ARP queries need to pass. - * @arp_addr_cnt: Number of addresses currently on the list. Note that this - * may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list - * array size), it's up to the driver what to do in that case. * @qos: This is a QoS-enabled BSS. - * @idle: This interface is idle. There's also a global idle flag in the - * hardware config which may be more appropriate depending on what - * your driver/device needs to do. * @ps: power-save mode (STA only). This flag is NOT affected by * offchannel/dynamic_ps operations. - * @ssid: The SSID of the current vif. Valid in AP and IBSS mode. - * @ssid_len: Length of SSID given in @ssid. * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. * @txpower: TX power in dBm. INT_MIN means not configured. * @txpower_type: TX power adjustment used to control per packet Transmit @@ -628,7 +613,6 @@ struct ieee80211_fils_discovery { * @fils_discovery: FILS discovery configuration * @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response * interval. - * @s1g: BSS is S1G BSS (affects Association Request format). * @beacon_tx_rate: The configured beacon transmit rate that needs to be passed * to driver when rate control is offloaded to firmware. * @power_type: power type of BSS for 6 GHz @@ -661,10 +645,6 @@ struct ieee80211_bss_conf { bool twt_responder; bool twt_protected; bool twt_broadcast; - /* association related data */ - bool assoc, ibss_joined; - bool ibss_creator; - u16 aid; /* erp related data */ bool use_cts_prot; bool use_short_preamble; @@ -686,13 +666,8 @@ struct ieee80211_bss_conf { s32 cqm_rssi_high; struct cfg80211_chan_def chandef; struct ieee80211_mu_group_data mu_group; - __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; - int arp_addr_cnt; bool qos; - bool idle; bool ps; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; bool hidden_ssid; int txpower; enum nl80211_tx_power_setting txpower_type; @@ -717,7 +692,6 @@ struct ieee80211_bss_conf { struct cfg80211_he_bss_color he_bss_color; struct ieee80211_fils_discovery fils_discovery; u32 unsol_bcast_probe_resp_interval; - bool s1g; struct cfg80211_bitrate_mask beacon_tx_rate; enum ieee80211_ap_reg_power power_type; struct ieee80211_tx_pwr_env tx_pwr_env[IEEE80211_TPE_MAX_IE_COUNT]; @@ -1721,6 +1695,40 @@ enum ieee80211_offload_flags { IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), }; +/** + * struct ieee80211_vif_cfg - interface configuration + * @assoc: association status + * @ibss_joined: indicates whether this station is part of an IBSS or not + * @ibss_creator: indicates if a new IBSS network is being created + * @aid: association ID number, valid only when @assoc is true + * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The + * may filter ARP queries targeted for other addresses than listed here. + * The driver must allow ARP queries targeted for all address listed here + * to pass through. An empty list implies no ARP queries need to pass. + * @arp_addr_cnt: Number of addresses currently on the list. Note that this + * may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list + * array size), it's up to the driver what to do in that case. + * @ssid: The SSID of the current vif. Valid in AP and IBSS mode. + * @ssid_len: Length of SSID given in @ssid. + * @s1g: BSS is S1G BSS (affects Association Request format). + * @idle: This interface is idle. There's also a global idle flag in the + * hardware config which may be more appropriate depending on what + * your driver/device needs to do. + */ +struct ieee80211_vif_cfg { + /* association related data */ + bool assoc, ibss_joined; + bool ibss_creator; + u16 aid; + + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; + int arp_addr_cnt; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + size_t ssid_len; + bool s1g; + bool idle; +}; + /** * struct ieee80211_vif - per-interface data * @@ -1728,6 +1736,7 @@ enum ieee80211_offload_flags { * use during the life of a virtual interface. * * @type: type of this virtual interface + * @cfg: vif configuration, see &struct ieee80211_vif_cfg * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to * @addr: address of this interface @@ -1762,6 +1771,7 @@ enum ieee80211_offload_flags { */ struct ieee80211_vif { enum nl80211_iftype type; + struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; u8 addr[ETH_ALEN] __aligned(2); bool p2p; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8a15c71e7c7d..fd57bad38681 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1216,12 +1216,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.twt_responder = params->twt_responder; sdata->vif.bss_conf.he_obss_pd = params->he_obss_pd; sdata->vif.bss_conf.he_bss_color = params->beacon.he_bss_color; - sdata->vif.bss_conf.s1g = params->chandef.chan->band == + sdata->vif.cfg.s1g = params->chandef.chan->band == NL80211_BAND_S1GHZ; - sdata->vif.bss_conf.ssid_len = params->ssid_len; + sdata->vif.cfg.ssid_len = params->ssid_len; if (params->ssid_len) - memcpy(sdata->vif.bss_conf.ssid, params->ssid, + memcpy(sdata->vif.cfg.ssid, params->ssid, params->ssid_len); sdata->vif.bss_conf.hidden_ssid = (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); @@ -1405,7 +1405,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); @@ -3488,7 +3488,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_ADHOC: - if (!sdata->vif.bss_conf.ibss_joined) + if (!sdata->vif.cfg.ibss_joined) return -EINVAL; if (params->chandef.width != sdata->u.ibss.chandef.width) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index eea400902133..deb358eef9d0 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -783,7 +783,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, out: rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); - sdata->vif.bss_conf.idle = !conf; + sdata->vif.cfg.idle = !conf; if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) { ieee80211_recalc_chanctx_chantype(local, curr_ctx); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cf71484658c6..59b33de0f3b0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2006 Jiri Benc * Copyright 2007 Johannes Berg - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation */ #include @@ -233,7 +233,7 @@ IEEE80211_IF_FILE_R(hw_queues); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); -IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC); +IEEE80211_IF_FILE(aid, vif.cfg.aid, DEC); IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS); static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, @@ -366,7 +366,7 @@ IEEE80211_IF_FILE_W(tkip_mic_test); static ssize_t ieee80211_if_parse_beacon_loss( struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) { - if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc) + if (!ieee80211_sdata_running(sdata) || !sdata->vif.cfg.assoc) return -ENOTCONN; ieee80211_beacon_loss(&sdata->vif); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8ff547ff351e..afb5982a1d42 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -244,9 +244,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sta_info_flush(sdata); /* if merging, indicate to driver that we leave the old IBSS */ - if (sdata->vif.bss_conf.ibss_joined) { - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + if (sdata->vif.cfg.ibss_joined) { + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; netif_carrier_off(sdata->dev); ieee80211_bss_info_change_notify(sdata, @@ -326,8 +326,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.beacon_int = beacon_int; sdata->vif.bss_conf.basic_rates = basic_rates; - sdata->vif.bss_conf.ssid_len = ifibss->ssid_len; - memcpy(sdata->vif.bss_conf.ssid, ifibss->ssid, ifibss->ssid_len); + sdata->vif.cfg.ssid_len = ifibss->ssid_len; + memcpy(sdata->vif.cfg.ssid, ifibss->ssid, ifibss->ssid_len); bss_change = BSS_CHANGED_BEACON_INT; bss_change |= ieee80211_reset_erp_info(sdata); bss_change |= BSS_CHANGED_BSSID; @@ -359,15 +359,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ieee80211_set_wmm_default(sdata, true, false); - sdata->vif.bss_conf.ibss_joined = true; - sdata->vif.bss_conf.ibss_creator = creator; + sdata->vif.cfg.ibss_joined = true; + sdata->vif.cfg.ibss_creator = creator; err = drv_join_ibss(local, sdata); if (err) { - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; RCU_INIT_POINTER(ifibss->presp, NULL); kfree_rcu(presp, rcu_head); mutex_lock(&local->mtx); @@ -708,10 +708,10 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; /* remove beacon */ presp = rcu_dereference_protected(ifibss->presp, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9e0e71ca8068..cce0a9aad2cd 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1642,7 +1642,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_encrypt = false; sdata->control_port_over_nl80211 = false; sdata->control_port_no_preauth = false; - sdata->vif.bss_conf.idle = true; + sdata->vif.cfg.idle = true; sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ sdata->noack_map = 0; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ebde131efcaa..0c81ae492df4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -349,7 +349,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, struct wireless_dev *wdev = ndev->ieee80211_ptr; struct in_device *idev; struct ieee80211_sub_if_data *sdata; - struct ieee80211_bss_conf *bss_conf; + struct ieee80211_vif_cfg *vif_cfg; struct ieee80211_if_managed *ifmgd; int c = 0; @@ -361,7 +361,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, return NOTIFY_DONE; sdata = IEEE80211_DEV_TO_SUB_IF(ndev); - bss_conf = &sdata->vif.bss_conf; + vif_cfg = &sdata->vif.cfg; /* ARP filtering is only supported in managed mode */ if (sdata->vif.type != NL80211_IFTYPE_STATION) @@ -374,16 +374,16 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ifmgd = &sdata->u.mgd; sdata_lock(sdata); - /* Copy the addresses to the bss_conf list */ + /* Copy the addresses to the vif config list */ ifa = rtnl_dereference(idev->ifa_list); while (ifa) { if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) - bss_conf->arp_addr_list[c] = ifa->ifa_address; + vif_cfg->arp_addr_list[c] = ifa->ifa_address; ifa = rtnl_dereference(ifa->ifa_next); c++; } - bss_conf->arp_addr_cnt = c; + vif_cfg->arp_addr_cnt = c; /* Configure driver only if associated (which also implies it is up) */ if (ifmgd->associated) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c526af66ff8d..4a792e88568d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2258,6 +2258,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_local *local = sdata->local; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; bss_info_changed |= BSS_CHANGED_ASSOC; bss_info_changed |= ieee80211_handle_bss_capability(sdata, @@ -2317,7 +2318,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_conf->dtim_period = 0; } - bss_conf->assoc = 1; + vif_cfg->assoc = 1; /* Tell the driver to monitor connection quality (if supported) */ if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && @@ -2325,7 +2326,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= BSS_CHANGED_CQM; /* Enable ARP filtering */ - if (bss_conf->arp_addr_cnt) + if (vif_cfg->arp_addr_cnt) bss_info_changed |= BSS_CHANGED_ARP_FILTER; ieee80211_bss_info_change_notify(sdata, bss_info_changed); @@ -2419,7 +2420,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* clear bssid only after building the needed mgmt frames */ eth_zero_addr(ifmgd->bssid); - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; /* remove AP and TDLS peers */ sta_info_flush(sdata); @@ -2429,7 +2430,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_led_assoc(local, 0); changed |= BSS_CHANGED_ASSOC; - sdata->vif.bss_conf.assoc = false; + sdata->vif.cfg.assoc = false; ifmgd->p2p_noa_index = -1; memset(&sdata->vif.bss_conf.p2p_noa_attr, 0, @@ -2455,7 +2456,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, cancel_work_sync(&local->dynamic_ps_enable_work); /* Disable ARP filtering */ - if (sdata->vif.bss_conf.arp_addr_cnt) + if (sdata->vif.cfg.arp_addr_cnt) changed |= BSS_CHANGED_ARP_FILTER; sdata->vif.bss_conf.qos = false; @@ -2642,8 +2643,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_nullfunc(sdata->local, sdata, false); } else { ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst, - sdata->vif.bss_conf.ssid, - sdata->vif.bss_conf.ssid_len, + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len, ifmgd->assoc_bss->channel); } @@ -3425,7 +3426,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, goto out; } - sdata->vif.bss_conf.aid = aid; + sdata->vif.cfg.aid = aid; ifmgd->tdls_chan_switch_prohibited = elems->ext_capab && elems->ext_capab_len >= 5 && (elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); @@ -4102,6 +4103,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; struct ieee80211_mgmt *mgmt = (void *) hdr; size_t baselen; struct ieee802_11_elems *elems; @@ -4226,7 +4228,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ncrc = elems->crc; if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && - ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { + ieee80211_check_tim(elems->tim, elems->tim_len, vif_cfg->aid)) { if (local->hw.conf.dynamic_ps_timeout > 0) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; @@ -5877,7 +5879,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data; const struct cfg80211_bss_ies *beacon_ies; struct ieee80211_supported_band *sband; - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; const struct element *ssid_elem, *ht_elem, *vht_elem; int i, err; bool override = false; @@ -5895,8 +5897,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } memcpy(assoc_data->ssid, ssid_elem->data, ssid_elem->datalen); assoc_data->ssid_len = ssid_elem->datalen; - memcpy(bss_conf->ssid, assoc_data->ssid, assoc_data->ssid_len); - bss_conf->ssid_len = assoc_data->ssid_len; + memcpy(vif_cfg->ssid, assoc_data->ssid, assoc_data->ssid_len); + vif_cfg->ssid_len = assoc_data->ssid_len; rcu_read_unlock(); if (ifmgd->associated) { diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index a1fbd562cac1..7da6b49598ab 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -785,7 +785,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: - if (!sdata->vif.bss_conf.ibss_joined) + if (!sdata->vif.cfg.ibss_joined) need_offchan = true; #ifdef CONFIG_MAC80211_MESH fallthrough; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b698756887eb..f80284eee055 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -177,7 +177,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, rcu_read_lock(); scan_sdata = rcu_dereference(local->scan_sdata); if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && - scan_sdata->vif.bss_conf.assoc && + scan_sdata->vif.cfg.assoc && ieee80211_have_rx_timestamp(rx_status)) { bss_meta.parent_tsf = ieee80211_calculate_rx_timestamp(local, rx_status, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index fa04021d4c0f..7eb6d8c4f25c 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -230,7 +230,7 @@ ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) *pos++ = WLAN_EID_AID; *pos++ = 2; /* len */ - put_unaligned_le16(sdata->vif.bss_conf.aid, pos); + put_unaligned_le16(sdata->vif.cfg.aid, pos); } /* translate numbering in the WMM parameter IE to the mac80211 notation */ @@ -1444,7 +1444,7 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) { sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", oper); return; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 743adfbb9b15..74ef7e71e1ef 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* -* Portions of this file -* Copyright(c) 2016-2017 Intel Deutschland GmbH -* Copyright (C) 2018 - 2021 Intel Corporation -*/ + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018 - 2022 Intel Corporation + */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) #define __MAC80211_DRIVER_TRACE @@ -425,14 +425,14 @@ TRACE_EVENT(drv_bss_info_changed, __field(u32, channel_cfreq1) __field(u32, channel_cfreq1_offset) __dynamic_array(u32, arp_addr_list, - info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? IEEE80211_BSS_ARP_ADDR_LIST_LEN : - info->arp_addr_cnt) + sdata->vif.cfg.arp_addr_cnt) __field(int, arp_addr_cnt) __field(bool, qos) __field(bool, idle) __field(bool, ps) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) __field(int, txpower) __field(u8, p2p_oppps_ctwindow) @@ -442,10 +442,10 @@ TRACE_EVENT(drv_bss_info_changed, LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; - __entry->aid = info->aid; - __entry->assoc = info->assoc; - __entry->ibss_joined = info->ibss_joined; - __entry->ibss_creator = info->ibss_creator; + __entry->aid = sdata->vif.cfg.aid; + __entry->assoc = sdata->vif.cfg.assoc; + __entry->ibss_joined = sdata->vif.cfg.ibss_joined; + __entry->ibss_creator = sdata->vif.cfg.ibss_creator; __entry->shortpre = info->use_short_preamble; __entry->cts = info->use_cts_prot; __entry->shortslot = info->use_short_slot; @@ -465,15 +465,18 @@ TRACE_EVENT(drv_bss_info_changed, __entry->channel_width = info->chandef.width; __entry->channel_cfreq1 = info->chandef.center_freq1; __entry->channel_cfreq1_offset = info->chandef.freq1_offset; - __entry->arp_addr_cnt = info->arp_addr_cnt; - memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, - sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; + memcpy(__get_dynamic_array(arp_addr_list), + sdata->vif.cfg.arp_addr_list, + sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? IEEE80211_BSS_ARP_ADDR_LIST_LEN : - info->arp_addr_cnt)); + sdata->vif.cfg.arp_addr_cnt)); __entry->qos = info->qos; - __entry->idle = info->idle; + __entry->idle = sdata->vif.cfg.idle; __entry->ps = info->ps; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); __entry->hidden_ssid = info->hidden_ssid; __entry->txpower = info->txpower; __entry->p2p_oppps_ctwindow = info->p2p_noa_attr.oppps_ctwindow; @@ -1719,7 +1722,7 @@ TRACE_EVENT(drv_start_ap, VIF_ENTRY __field(u8, dtimper) __field(u16, bcnint) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) ), @@ -1728,7 +1731,9 @@ TRACE_EVENT(drv_start_ap, VIF_ASSIGN; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); __entry->hidden_ssid = info->hidden_ssid; ), @@ -1786,7 +1791,7 @@ TRACE_EVENT(drv_join_ibss, VIF_ENTRY __field(u8, dtimper) __field(u16, bcnint) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) ), TP_fast_assign( @@ -1794,7 +1799,9 @@ TRACE_EVENT(drv_join_ibss, VIF_ASSIGN; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); ), TP_printk( diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e5edc6fd21c0..a4270e9ec10e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5381,7 +5381,7 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, pspoll = skb_put_zero(skb, sizeof(*pspoll)); pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - pspoll->aid = cpu_to_le16(sdata->vif.bss_conf.aid); + pspoll->aid = cpu_to_le16(sdata->vif.cfg.aid); /* aid in PS-Poll has its two MSBs each set to 1 */ pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 48d8f0aad69f..dccc757baab2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2496,7 +2496,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_ADHOC: - if (sdata->vif.bss_conf.ibss_joined) + if (sdata->vif.cfg.ibss_joined) WARN_ON(drv_join_ibss(local, sdata)); fallthrough; default: -- cgit v1.2.3 From 7b7090b4c6a906cc7c3e2a460335f705b93f4506 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 24 May 2022 10:55:56 +0200 Subject: wifi: mac80211: split bss_info_changed method Split the bss_info_changed method to vif_cfg_changed and link_info_changed, with the latter getting a link ID. Also change the 'changed' parameter to u64 already, we know we need that. Signed-off-by: Johannes Berg --- drivers/net/wireless/admtek/adm8211.c | 2 +- drivers/net/wireless/ath/ar5523/ar5523.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/carl9170/main.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 4 +- drivers/net/wireless/atmel/at76c50x-usb.c | 2 +- drivers/net/wireless/broadcom/b43/main.c | 4 +- drivers/net/wireless/broadcom/b43legacy/main.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 2 +- drivers/net/wireless/intel/iwlegacy/common.c | 6 +- drivers/net/wireless/intel/iwlegacy/common.h | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +- drivers/net/wireless/intersil/p54/main.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 4 +- drivers/net/wireless/marvell/libertas_tf/main.c | 2 +- drivers/net/wireless/marvell/mwl8k.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt7601u/main.c | 2 +- drivers/net/wireless/purelifi/plfxlc/mac.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- drivers/net/wireless/silabs/wfx/sta.c | 2 +- drivers/net/wireless/silabs/wfx/sta.h | 2 +- drivers/net/wireless/st/cw1200/sta.c | 4 +- drivers/net/wireless/st/cw1200/sta.h | 2 +- drivers/net/wireless/ti/wl1251/main.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 2 +- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 4 +- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6656/main_usb.c | 2 +- include/net/mac80211.h | 28 ++++- net/mac80211/cfg.c | 31 ++--- net/mac80211/chan.c | 9 +- net/mac80211/driver-ops.h | 35 ++++-- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 6 +- net/mac80211/iface.c | 5 +- net/mac80211/main.c | 84 ++++++++++++- net/mac80211/mesh.c | 6 +- net/mac80211/mlme.c | 16 +-- net/mac80211/offchannel.c | 8 +- net/mac80211/sta_info.c | 2 +- net/mac80211/tdls.c | 2 +- net/mac80211/trace.h | 138 +++++++++++++-------- net/mac80211/util.c | 4 +- net/mac80211/vht.c | 2 +- 64 files changed, 324 insertions(+), 170 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 2db9c948c0fc..6bee16b207d1 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1311,7 +1311,7 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed) static void adm8211_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changes) + u64 changes) { struct adm8211_priv *priv = dev->priv; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 4cd06a0942d4..6f937d2cc126 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1273,7 +1273,7 @@ static int ar5523_write_associd(struct ar5523 *ar, struct ieee80211_vif *vif) static void ar5523_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss, - u32 changed) + u64 changed) { struct ar5523 *ar = hw->priv; int error; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4e7e2da3c859..c1f8123d81fe 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6068,7 +6068,7 @@ static void ath10k_recalculate_mgmt_rate(struct ath10k *ar, static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 169161549361..3e07b1454fe4 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3091,7 +3091,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 0df0fa1da181..8da232e81518 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -250,7 +250,7 @@ unlock: static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes) + struct ieee80211_bss_conf *bss_conf, u64 changes) { struct ath5k_vif *avf = (void *)vif->drv_priv; struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 3a5ec4da6a38..14d713e03872 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1509,7 +1509,7 @@ static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 56c2681e5192..729f8ee9644d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1863,7 +1863,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { #define CHECK_ANI \ (BSS_CHANGED_ASSOC | \ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index e28a5f3085c0..3d881028bd00 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1032,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct ar9170 *ar = hw->priv; struct ath_common *common = &ar->common; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 72ba2e2fc93a..04fb26cb8322 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -872,7 +872,7 @@ void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates) static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wcn36xx *wcn = hw->priv; struct sk_buff *skb = NULL; @@ -880,7 +880,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, enum wcn36xx_hal_link_state link_state; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); - wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%llx\n", vif, changed); mutex_lock(&wcn->conf_mutex); diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 7582761c61e2..24e609c1f523 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2033,7 +2033,7 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) static void at76_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct at76_priv *priv = hw->priv; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 17bcec5f3ff7..e3121a9d0579 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -366,7 +366,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev); static void b43_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed); + u64 changed); static int b43_ratelimit(struct b43_wl *wl) { @@ -4097,7 +4097,7 @@ static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates) static void b43_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index eec3af9c3745..96d5a034c09b 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -2806,7 +2806,7 @@ static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u32 brates static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index e6cd638a85d6..fd3c131c622c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -582,7 +582,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) static void brcms_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct brcms_info *wl = hw->priv; struct bcma_device *core = wl->wlc->hw->d11core; diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index b01945415be6..affad34f70f0 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5311,13 +5311,13 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) void il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes) + struct ieee80211_bss_conf *bss_conf, u64 changes) { struct il_priv *il = hw->priv; int ret; mutex_lock(&il->mutex); - D_MAC80211("enter: changes 0x%x\n", changes); + D_MAC80211("enter: changes 0x%llx\n", changes); if (!il_is_alive(il)) { D_MAC80211("leave - not alive\n"); @@ -5438,7 +5438,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes && il_is_associated(il) && vif->cfg.aid) { - D_MAC80211("Changes (%#x) while associated\n", changes); + D_MAC80211("Changes (%#llx) while associated\n", changes); ret = il_send_rxon_assoc(il); if (!ret) { /* Sync active_rxon with latest change. */ diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 40877ef1fbf2..d1383b4f0f05 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -1947,7 +1947,7 @@ il_get_hw_mode(struct il_priv *il, enum nl80211_band band) int il_mac_config(struct ieee80211_hw *hw, u32 changed); void il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes); + struct ieee80211_bss_conf *bss_conf, u64 changes); void il_tx_cmd_protection(struct il_priv *il, struct ieee80211_tx_info *info, __le16 fc, __le32 *tx_flags); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index abb8696ba294..411a6f6638b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -92,7 +92,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed); void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes); + u64 changes); void iwlagn_config_ht40(struct ieee80211_conf *conf, struct iwl_rxon_context *ctx); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 17a14970edec..45e382fe45a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -1383,7 +1383,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b5257b4fd000..586208506275 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2181,7 +2181,7 @@ static void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -2590,7 +2590,7 @@ static void iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2621,7 +2621,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index a9dfe6a3da0d..cc6769a4fec7 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -449,7 +449,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, static void p54_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5aaf34f6f43b..de10a40d5306 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2100,14 +2100,14 @@ static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct mac80211_hwsim_data *data = hw->priv; hwsim_check_magic(vif); - wiphy_dbg(hw->wiphy, "%s(changed=0x%x vif->addr=%pM)\n", + wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", __func__, changed, vif->addr); if (changed & BSS_CHANGED_BSSID) { diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 02a1e1f547d8..21c3e0bdc444 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -417,7 +417,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw, static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct lbtf_private *priv = hw->priv; struct sk_buff *beacon; diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 5f1bcfb5e3f6..7eef3a74d124 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5163,7 +5163,7 @@ out: static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { if (vif->type == NL80211_IFTYPE_STATION) mwl8k_bss_info_changed_sta(hw, vif, info, changed); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 1f14ecda1f55..088c0a4cf774 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -297,7 +297,7 @@ mt7603_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, static void mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct mt7603_dev *dev = hw->priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index d992fdea0f32..277c22a4d049 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -576,7 +576,7 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, static void mt7615_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f76fd22ee035..74ad418f5a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -187,7 +187,7 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); + struct ieee80211_bss_conf *info, u64 changed); void mt76x02_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 5bd0a0bae688..a0e2d042751b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -636,7 +636,7 @@ EXPORT_SYMBOL_GPL(mt76x02_sta_ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76x02_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 05327b0b6fc3..fbeac9aa2af6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -573,7 +573,7 @@ mt7915_update_bss_color(struct ieee80211_hw *hw, static void mt7915_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 8532033794bd..63583605d1cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -637,7 +637,7 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, static void mt7921_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7921_phy *phy = mt7921_hw_phy(hw); struct mt7921_dev *dev = mt7921_hw_dev(hw); diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 671d8897ae76..6c9c7a61c5c9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -132,7 +132,7 @@ mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, static void mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct mt7601u_dev *dev = hw->priv; diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 90e552532701..1fc1682683e1 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -587,12 +587,12 @@ static void plfxlc_op_configure_filter(struct ieee80211_hw *hw, static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct plfxlc_mac *mac = plfxlc_hw_mac(hw); int associated; - dev_dbg(plfxlc_mac_dev(mac), "changes: %x\n", changes); + dev_dbg(plfxlc_mac_dev(mac), "changes: %llx\n", changes); if (mac->type != NL80211_IFTYPE_ADHOC) { /* for STATION */ associated = is_valid_ether_addr(bss_conf->bssid); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 9f6fc40649be..918e0477bb7d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1479,7 +1479,7 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes); + u64 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 660554a01894..6205d22765c7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -574,7 +574,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index 025619cd14e8..10e8fdc31879 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1500,7 +1500,7 @@ static void rtl8180_conf_erp(struct ieee80211_hw *dev, static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct rtl8180_priv *priv = dev->priv; struct rtl8180_vif *vif_priv; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index eb68b2d3caa1..8ab65c888baf 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1251,7 +1251,7 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct rtl8187_priv *priv = dev->priv; struct rtl8187_vif *vif_priv; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 0239e12ec8a5..65c4cb1e030c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4558,7 +4558,7 @@ rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changed) + struct ieee80211_bss_conf *bss_conf, u64 changed) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 5177eb02740e..2f7fd8888d3a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1040,7 +1040,7 @@ EXPORT_SYMBOL_GPL(rtl_update_beacon_work_callback); static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index c5954c18862d..9e0b5692fbab 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -355,7 +355,7 @@ static void rtw_conf_tx(struct rtw_dev *rtwdev, static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct rtw_dev *rtwdev = hw->priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index ac8b9bf2b0bb..5afb8fe5708e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -336,7 +336,7 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index d4b3834388ab..1dff3d263382 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -783,7 +783,7 @@ static void rsi_switch_channel(struct rsi_hw *adapter, static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 79fafe8143d9..f4103a653e3b 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -506,7 +506,7 @@ static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) } void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct wfx_dev *wdev = hw->priv; struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index c69b2227e9ac..d9c6bd632b20 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -36,7 +36,7 @@ void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); + struct ieee80211_bss_conf *info, u64 changed); int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 3f48def51ebc..5fa6878ee109 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1796,14 +1796,14 @@ static int cw1200_set_btcoexinfo(struct cw1200_common *priv) void cw1200_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct cw1200_common *priv = dev->priv; bool do_join = false; mutex_lock(&priv->conf_mutex); - pr_debug("BSS CHANGED: %08x\n", changed); + pr_debug("BSS CHANGED: %llx\n", changed); /* TODO: BSS_CHANGED_QOS */ /* TODO: BSS_CHANGED_TXPOWER */ diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index 706dab8e73bf..05e3ab7ccef1 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -103,7 +103,7 @@ void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, void cw1200_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed); + u64 changed); int cw1200_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index bdc93c4f54ba..340ab4985fe2 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1077,7 +1077,7 @@ out: static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wl1251 *wl = hw->priv; struct sk_buff *beacon, *skb; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ad9560bd9512..d365bdce2a10 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4580,7 +4580,7 @@ out: static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 3ef8533205f9..b42fedba519d 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1278,12 +1278,12 @@ static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble) static void zd_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct zd_mac *mac = zd_hw_mac(hw); int associated; - dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + dev_dbg_f(zd_mac_dev(mac), "changes: %llx\n", changes); if (mac->type == NL80211_IFTYPE_MESH_POINT || mac->type == NL80211_IFTYPE_ADHOC || diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 8c5de30478ec..e8ac7b93b58c 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1395,7 +1395,7 @@ static int vnt_config(struct ieee80211_hw *hw, u32 changed) static void vnt_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u32 changed) + struct ieee80211_bss_conf *conf, u64 changed) { struct vnt_private *priv = hw->priv; diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 3ab8a7bb9715..897ee0f7fc6b 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -745,7 +745,7 @@ static int vnt_config(struct ieee80211_hw *hw, u32 changed) static void vnt_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u32 changed) + struct ieee80211_bss_conf *conf, u64 changed) { struct vnt_private *priv = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1520922d21a5..17b6eb426356 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -273,8 +273,8 @@ struct ieee80211_vif_chanctx_switch { /** * enum ieee80211_bss_change - BSS change notification flags * - * These flags are used with the bss_info_changed() callback - * to indicate which BSS parameter changed. + * These flags are used with the bss_info_changed(), link_info_changed() + * and vif_cfg_changed() callbacks to indicate which parameter(s) changed. * * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), * also implies a change in the AID. @@ -3524,6 +3524,22 @@ struct ieee80211_prep_tx_info { * for association indication. The @changed parameter indicates which * of the bss parameters has changed when a call is made. The callback * can sleep. + * Note: this callback is called if @vif_cfg_changed or @link_info_changed + * are not implemented. + * + * @vif_cfg_changed: Handler for configuration requests related to interface + * (MLD) parameters from &struct ieee80211_vif_cfg that vary during the + * lifetime of the interface (e.g. assoc status, IP addresses, etc.) + * The @changed parameter indicates which value changed. + * The callback can sleep. + * + * @link_info_changed: Handler for configuration requests related to link + * parameters from &struct ieee80211_bss_conf that are related to an + * individual link. e.g. legacy/HT/VHT/... rate information. + * The @changed parameter indicates which value changed, and the @link_id + * parameter indicates the link ID. Note that the @link_id will be 0 for + * non-MLO connections. + * The callback can sleep. * * @prepare_multicast: Prepare for multicast filter configuration. * This callback is optional, and its return value is passed @@ -4032,7 +4048,13 @@ struct ieee80211_ops { void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed); + u64 changed); + void (*vif_cfg_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed); + void (*link_info_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0a717cb95400..a1404fe5cfe4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -39,7 +39,8 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, memcpy(sdata->vif.bss_conf.mu_group.position, params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, WLAN_USER_POSITION_LEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_MU_GROUPS); /* don't care about endianness - just check for 0 */ memcpy(&membership, params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); @@ -1333,7 +1334,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, err |= BSS_CHANGED_HE_BSS_COLOR; } - ieee80211_bss_info_change_notify(sdata, err); + ieee80211_link_info_change_notify(sdata, 0, err); return 0; } @@ -1414,7 +1415,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, sdata->beacon_rate_set = false; sdata->vif.cfg.ssid_len = 0; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED); if (sdata->wdev.cac_started) { chandef = sdata->vif.bss_conf.chandef; @@ -2347,7 +2348,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) { conf->ht_opmode = nconf->ht_opmode; sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); } if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) conf->dot11MeshHWMPactivePathToRootTimeout = @@ -2502,7 +2503,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, changed |= BSS_CHANGED_P2P_PS; } - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); return 0; } @@ -2543,7 +2544,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); return 0; } @@ -2692,7 +2693,7 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(int) * NUM_NL80211_BANDS); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MCAST_RATE); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MCAST_RATE); return 0; } @@ -3026,7 +3027,7 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); return 0; } @@ -3051,7 +3052,7 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); return 0; } @@ -3389,7 +3390,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (err) return err; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); if (sdata->deflink.csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -3677,7 +3678,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->count, params->block_tx); if (changed) { - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); drv_channel_switch_beacon(sdata, ¶ms->chandef); } else { /* if the beacon didn't change, we can finalize immediately */ @@ -3980,7 +3981,7 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); if (ret == 0) - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); return ret; } @@ -4389,7 +4390,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.he_bss_color.enabled = enable; changed |= BSS_CHANGED_HE_BSS_COLOR; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) { struct ieee80211_sub_if_data *child; @@ -4399,8 +4400,8 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) { child->vif.bss_conf.he_bss_color.color = color; child->vif.bss_conf.he_bss_color.enabled = enable; - ieee80211_bss_info_change_notify(child, - BSS_CHANGED_HE_BSS_COLOR); + ieee80211_link_info_change_notify(child, 0, + BSS_CHANGED_HE_BSS_COLOR); } } mutex_unlock(&sdata->local->iflist_mtx); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 67131ca3f649..5d8b49f20198 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -799,8 +799,7 @@ out: if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_MONITOR) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_IDLE); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE); ieee80211_check_fast_xmit_iface(sdata); @@ -1188,7 +1187,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) ieee80211_recalc_radar_chanctx(local, new_ctx); if (changed) - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); out: ieee80211_vif_chanctx_reservation_complete(sdata); @@ -1533,8 +1532,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_vif_update_chandef(sdata, &sdata->deflink.reserved_chandef); if (changed) - ieee80211_bss_info_change_notify(sdata, - changed); + ieee80211_link_info_change_notify(sdata, 0, + changed); ieee80211_recalc_txpower(sdata, false); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fd2882348211..15ab8d00815b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -147,10 +147,27 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed) return ret; } -static inline void drv_bss_info_changed(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info, - u32 changed) +static inline void drv_vif_cfg_changed(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 changed) +{ + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return; + + trace_drv_vif_cfg_changed(local, sdata, changed); + if (local->ops->vif_cfg_changed) + local->ops->vif_cfg_changed(&local->hw, &sdata->vif, changed); + else if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); + trace_drv_return_void(local); +} + +static inline void drv_link_info_changed(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed) { might_sleep(); @@ -172,9 +189,13 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_bss_info_changed(local, sdata, info, changed); - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); + trace_drv_link_info_changed(local, sdata, link_id, changed); + if (local->ops->link_info_changed) + local->ops->link_info_changed(&local->hw, &sdata->vif, + link_id, changed); + else if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); trace_drv_return_void(local); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 066f7c5adeec..3b68e9f4345b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1851,7 +1851,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | IEEE80211_HT_PARAM_RIFS_MODE; changed |= BSS_CHANGED_HT | BSS_CHANGED_MCAST_RATE; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f0a8bb444033..20153957cdee 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1836,7 +1836,11 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed); + u64 changed); +void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, + u64 changed); +void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed); void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2ee34d898821..978dfa48e098 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -80,7 +80,8 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, { if (__ieee80211_recalc_txpower(sdata) || (update_bss && ieee80211_sdata_running(sdata))) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_TXPOWER); } static u32 __ieee80211_idle_off(struct ieee80211_local *local) @@ -1281,7 +1282,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_NAN) changed |= ieee80211_reset_erp_info(sdata); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c81ae492df4..5c71b522013f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -199,15 +199,88 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) return ret; } +#define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\ + BSS_CHANGED_IDLE |\ + BSS_CHANGED_IBSS |\ + BSS_CHANGED_ARP_FILTER |\ + BSS_CHANGED_SSID) + void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed) + u64 changed) { struct ieee80211_local *local = sdata->local; + might_sleep(); + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) return; - drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); + if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED) && + sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_ADHOC && + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_OCB)) + return; + + if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || + sdata->vif.type == NL80211_IFTYPE_NAN || + (sdata->vif.type == NL80211_IFTYPE_MONITOR && + !sdata->vif.bss_conf.mu_mimo_owner && + !(changed & BSS_CHANGED_TXPOWER)))) + return; + + if (!check_sdata_in_driver(sdata)) + return; + + if (changed & BSS_CHANGED_VIF_CFG_FLAGS) { + u64 ch = changed & BSS_CHANGED_VIF_CFG_FLAGS; + + trace_drv_vif_cfg_changed(local, sdata, changed); + if (local->ops->vif_cfg_changed) + local->ops->vif_cfg_changed(&local->hw, &sdata->vif, ch); + } + + if (changed & ~BSS_CHANGED_VIF_CFG_FLAGS) { + u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS; + + /* FIXME: should be for each link */ + trace_drv_link_info_changed(local, sdata, 0, changed); + if (local->ops->link_info_changed) + local->ops->link_info_changed(&local->hw, &sdata->vif, + 0, ch); + } + + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); + trace_drv_return_void(local); +} + +void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, + u64 changed) +{ + struct ieee80211_local *local = sdata->local; + + WARN_ON_ONCE(changed & ~BSS_CHANGED_VIF_CFG_FLAGS); + + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return; + + drv_vif_cfg_changed(local, sdata, changed); +} + +void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed) +{ + struct ieee80211_local *local = sdata->local; + + WARN_ON_ONCE(changed & BSS_CHANGED_VIF_CFG_FLAGS); + + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return; + + drv_link_info_changed(local, sdata, link_id, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -387,8 +460,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, /* Configure driver only if associated (which also implies it is up) */ if (ifmgd->associated) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_ARP_FILTER); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_ARP_FILTER); sdata_unlock(sdata); @@ -557,6 +629,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) return NULL; + if (WARN_ON(!!ops->link_info_changed != !!ops->vif_cfg_changed || + (ops->link_info_changed && ops->bss_info_changed))) + return NULL; + /* check all or no channel context operations exist */ i = !!ops->add_chanctx + !!ops->remove_chanctx + !!ops->change_chanctx + !!ops->assign_vif_chanctx + diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f60e257cba95..13722a7f2254 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1057,7 +1057,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) } ieee80211_recalc_dtim(local, sdata); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); netif_carrier_on(sdata->dev); return 0; @@ -1081,7 +1081,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED); /* remove beacon */ bcn = rcu_dereference_protected(ifmsh->beacon, @@ -1581,7 +1581,7 @@ static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) if (ieee80211_mesh_rebuild_beacon(sdata)) return; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); } void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fd1b97e1e990..e172bdfe9b0a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1835,7 +1835,7 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) if (sdata->vif.bss_conf.ps != ps_allowed) { sdata->vif.bss_conf.ps = ps_allowed; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_PS); } } @@ -2031,7 +2031,7 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) { if (__ieee80211_sta_handle_tspec_ac_params(sdata)) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); } static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) @@ -2920,7 +2920,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, auth_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -2949,7 +2949,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, assoc_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; sdata->vif.bss_conf.mu_mimo_owner = false; @@ -4387,7 +4387,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, elems->pwr_constr_elem, elems->cisco_dtpc_elem); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); free: kfree(elems); } @@ -5697,7 +5697,7 @@ skip_rates: * tell driver about BSSID, basic rates and timing * this was set up above, before setting the channel */ - ieee80211_bss_info_change_notify(sdata, + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT); @@ -5865,7 +5865,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -6212,7 +6212,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, return 0; err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; err_free: kfree(assoc_data); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 6cd3df1eb687..2ed4e2325914 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -118,8 +118,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); sdata->vif.bss_conf.enable_beacon = false; - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify( + sdata, 0, BSS_CHANGED_BEACON_ENABLED); } if (sdata->vif.type == NL80211_IFTYPE_STATION && @@ -155,8 +155,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state)) { sdata->vif.bss_conf.enable_beacon = true; - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify( + sdata, 0, BSS_CHANGED_BEACON_ENABLED); } } mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 115efa830673..9a70d846d0dd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -630,7 +630,7 @@ ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata) if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) { sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_P2P_PS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_P2P_PS); } } diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 8a2ec9c31240..11a3b950b490 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1335,7 +1335,7 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, return; sdata->vif.bss_conf.ht_operation_mode = opmode; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); } int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 74ef7e71e1ef..9417378b4fc0 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -390,22 +390,71 @@ TRACE_EVENT(drv_config, ) ); -TRACE_EVENT(drv_bss_info_changed, +TRACE_EVENT(drv_vif_cfg_changed, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info, - u32 changed), + u64 changed), - TP_ARGS(local, sdata, info, changed), + TP_ARGS(local, sdata, changed), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY - __field(u32, changed) + __field(u64, changed) __field(bool, assoc) __field(bool, ibss_joined) __field(bool, ibss_creator) __field(u16, aid) + __dynamic_array(u32, arp_addr_list, + sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + IEEE80211_BSS_ARP_ADDR_LIST_LEN : + sdata->vif.cfg.arp_addr_cnt) + __field(int, arp_addr_cnt) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) + __field(int, s1g) + __field(bool, idle) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->changed = changed; + __entry->aid = sdata->vif.cfg.aid; + __entry->assoc = sdata->vif.cfg.assoc; + __entry->ibss_joined = sdata->vif.cfg.ibss_joined; + __entry->ibss_creator = sdata->vif.cfg.ibss_creator; + + __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; + memcpy(__get_dynamic_array(arp_addr_list), + sdata->vif.cfg.arp_addr_list, + sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + IEEE80211_BSS_ARP_ADDR_LIST_LEN : + sdata->vif.cfg.arp_addr_cnt)); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); + __entry->s1g = sdata->vif.cfg.s1g; + __entry->idle = sdata->vif.cfg.idle; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " changed:%#llx", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + ) +); + +TRACE_EVENT(drv_link_info_changed, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed), + + TP_ARGS(local, sdata, link_id, changed), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u64, changed) + __field(int, link_id) __field(bool, cts) __field(bool, shortpre) __field(bool, shortslot) @@ -424,15 +473,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u32, channel_width) __field(u32, channel_cfreq1) __field(u32, channel_cfreq1_offset) - __dynamic_array(u32, arp_addr_list, - sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? - IEEE80211_BSS_ARP_ADDR_LIST_LEN : - sdata->vif.cfg.arp_addr_cnt) - __field(int, arp_addr_cnt) __field(bool, qos) - __field(bool, idle) __field(bool, ps) - __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) __field(int, txpower) __field(u8, p2p_oppps_ctwindow) @@ -442,49 +484,37 @@ TRACE_EVENT(drv_bss_info_changed, LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; - __entry->aid = sdata->vif.cfg.aid; - __entry->assoc = sdata->vif.cfg.assoc; - __entry->ibss_joined = sdata->vif.cfg.ibss_joined; - __entry->ibss_creator = sdata->vif.cfg.ibss_creator; - __entry->shortpre = info->use_short_preamble; - __entry->cts = info->use_cts_prot; - __entry->shortslot = info->use_short_slot; - __entry->enable_beacon = info->enable_beacon; - __entry->dtimper = info->dtim_period; - __entry->bcnint = info->beacon_int; - __entry->assoc_cap = info->assoc_capability; - __entry->sync_tsf = info->sync_tsf; - __entry->sync_device_ts = info->sync_device_ts; - __entry->sync_dtim_count = info->sync_dtim_count; - __entry->basic_rates = info->basic_rates; - memcpy(__entry->mcast_rate, info->mcast_rate, + __entry->link_id = link_id; + __entry->shortpre = sdata->vif.bss_conf.use_short_preamble; + __entry->cts = sdata->vif.bss_conf.use_cts_prot; + __entry->shortslot = sdata->vif.bss_conf.use_short_slot; + __entry->enable_beacon = sdata->vif.bss_conf.enable_beacon; + __entry->dtimper = sdata->vif.bss_conf.dtim_period; + __entry->bcnint = sdata->vif.bss_conf.beacon_int; + __entry->assoc_cap = sdata->vif.bss_conf.assoc_capability; + __entry->sync_tsf = sdata->vif.bss_conf.sync_tsf; + __entry->sync_device_ts = sdata->vif.bss_conf.sync_device_ts; + __entry->sync_dtim_count = sdata->vif.bss_conf.sync_dtim_count; + __entry->basic_rates = sdata->vif.bss_conf.basic_rates; + memcpy(__entry->mcast_rate, sdata->vif.bss_conf.mcast_rate, sizeof(__entry->mcast_rate)); - __entry->ht_operation_mode = info->ht_operation_mode; - __entry->cqm_rssi_thold = info->cqm_rssi_thold; - __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; - __entry->channel_width = info->chandef.width; - __entry->channel_cfreq1 = info->chandef.center_freq1; - __entry->channel_cfreq1_offset = info->chandef.freq1_offset; - __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; - memcpy(__get_dynamic_array(arp_addr_list), - sdata->vif.cfg.arp_addr_list, - sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? - IEEE80211_BSS_ARP_ADDR_LIST_LEN : - sdata->vif.cfg.arp_addr_cnt)); - __entry->qos = info->qos; - __entry->idle = sdata->vif.cfg.idle; - __entry->ps = info->ps; - memcpy(__get_dynamic_array(ssid), - sdata->vif.cfg.ssid, - sdata->vif.cfg.ssid_len); - __entry->hidden_ssid = info->hidden_ssid; - __entry->txpower = info->txpower; - __entry->p2p_oppps_ctwindow = info->p2p_noa_attr.oppps_ctwindow; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " changed:%#x", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + __entry->ht_operation_mode = sdata->vif.bss_conf.ht_operation_mode; + __entry->cqm_rssi_thold = sdata->vif.bss_conf.cqm_rssi_thold; + __entry->cqm_rssi_hyst = sdata->vif.bss_conf.cqm_rssi_hyst; + __entry->channel_width = sdata->vif.bss_conf.chandef.width; + __entry->channel_cfreq1 = sdata->vif.bss_conf.chandef.center_freq1; + __entry->channel_cfreq1_offset = sdata->vif.bss_conf.chandef.freq1_offset; + __entry->qos = sdata->vif.bss_conf.qos; + __entry->ps = sdata->vif.bss_conf.ps; + __entry->hidden_ssid = sdata->vif.bss_conf.hidden_ssid; + __entry->txpower = sdata->vif.bss_conf.txpower; + __entry->p2p_oppps_ctwindow = sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " link_id:%d, changed:%#llx", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, + __entry->changed ) ); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9cbc09e6d84e..2a279dc3e457 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1699,8 +1699,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, sdata->vif.type != NL80211_IFTYPE_NAN) { sdata->vif.bss_conf.qos = enable_qos; if (bss_notify) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_QOS); } } diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index ac97584b3a0b..7daca8352deb 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -665,7 +665,7 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.vht_group_notif.position, WLAN_USER_POSITION_LEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MU_GROUPS); } void ieee80211_update_mu_groups(struct ieee80211_vif *vif, -- cgit v1.2.3 From 8e14130d3faf7b6b0fc57b530bb601cd9d6a1dab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 13:09:28 +0200 Subject: wifi: mac80211: add per-link configuration pointer Add pointers so we can start using link_id throughout the code, even if for now only link ID 0 is valid, pointing to the "built-in" bss_conf, which is used by drivers that are not aware of MLD. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 23 +++++++++++++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 17b6eb426356..9af283b1c3b5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1739,6 +1739,8 @@ struct ieee80211_vif_cfg { * @cfg: vif configuration, see &struct ieee80211_vif_cfg * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to + * @link_conf: in case of MLD, the per-link BSS configuration, + * indexed by link ID * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1773,6 +1775,7 @@ struct ieee80211_vif { enum nl80211_iftype type; struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; + struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; u8 addr[ETH_ALEN] __aligned(2); bool p2p; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 20153957cdee..397b111f006d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1031,6 +1031,7 @@ struct ieee80211_sub_if_data { } u; struct ieee80211_link_data deflink; + struct ieee80211_link_data *link[IEEE80211_MLD_MAX_NUM_LINKS]; #ifdef CONFIG_MAC80211_DEBUGFS struct { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 978dfa48e098..04ee525394e9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1012,6 +1012,23 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } +static void ieee80211_sdata_init(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + sdata->local = local; + + /* + * Initialize the default link, so we can use link_id 0 for non-MLD, + * and that continues to work for non-MLD-aware drivers that use just + * vif.bss_conf instead of vif.link_conf. + * + * Note that we never change this, so if link ID 0 isn't used in an + * MLD connection, we get a separate allocation for it. + */ + sdata->vif.link_conf[0] = &sdata->vif.bss_conf; + sdata->link[0] = &sdata->deflink; +} + int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; @@ -1031,12 +1048,13 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) return -ENOMEM; /* set up data */ - sdata->local = local; sdata->vif.type = NL80211_IFTYPE_MONITOR; snprintf(sdata->name, IFNAMSIZ, "%s-monitor", wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; + ieee80211_sdata_init(local, sdata); + ieee80211_set_default_queues(sdata); ret = drv_add_interface(local, sdata); @@ -2074,7 +2092,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; - sdata->local = local; + + ieee80211_sdata_init(local, sdata); ieee80211_init_frag_cache(&sdata->frags); -- cgit v1.2.3 From b4f85443c17c7edb49c82fc1d28d26860c8c850d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 18:35:23 +0200 Subject: wifi: mac80211: make channel context code MLO-aware Make the channel context code MLO aware, along with some functions that it uses, so that the chan.c file is now MLD-clean and no longer uses deflink/bss_conf/etc. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 + drivers/net/wireless/ath/ath11k/mac.c | 2 + drivers/net/wireless/ath/ath9k/main.c | 2 + drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 + drivers/net/wireless/mac80211_hwsim.c | 2 + drivers/net/wireless/silabs/wfx/sta.c | 2 + drivers/net/wireless/silabs/wfx/sta.h | 2 + drivers/net/wireless/ti/wlcore/main.c | 2 + include/net/mac80211.h | 4 + net/mac80211/cfg.c | 52 +- net/mac80211/chan.c | 642 +++++++++++++--------- net/mac80211/debug.h | 14 + net/mac80211/driver-ops.h | 8 +- net/mac80211/eht.c | 4 +- net/mac80211/he.c | 6 +- net/mac80211/ibss.c | 8 +- net/mac80211/ieee80211_i.h | 51 +- net/mac80211/iface.c | 15 +- net/mac80211/mesh_plink.c | 4 +- net/mac80211/mlme.c | 28 +- net/mac80211/ocb.c | 6 +- net/mac80211/rate.c | 8 +- net/mac80211/rate.h | 7 +- net/mac80211/rx.c | 8 +- net/mac80211/tdls.c | 4 +- net/mac80211/trace.h | 17 +- net/mac80211/util.c | 39 +- net/mac80211/vht.c | 36 +- 28 files changed, 586 insertions(+), 391 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c1f8123d81fe..4808ed6a6e20 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8919,6 +8919,7 @@ unlock: static int ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; @@ -8998,6 +8999,7 @@ err: static void ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3e07b1454fe4..96a33b49a52f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7072,6 +7072,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; @@ -7161,6 +7162,7 @@ out: static void ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 729f8ee9644d..c3d5d9795424 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2596,6 +2596,7 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw, static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; @@ -2627,6 +2628,7 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 586208506275..5d3cedc146be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4235,6 +4235,7 @@ out: } static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4308,6 +4309,7 @@ out: static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index de10a40d5306..f9392bec85d9 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2722,6 +2722,7 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); @@ -2732,6 +2733,7 @@ static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index f4103a653e3b..97a631ff1bfa 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -680,6 +680,7 @@ void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf * } int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; @@ -692,6 +693,7 @@ int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index d9c6bd632b20..3109d257fe94 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -48,8 +48,10 @@ int wfx_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf void wfx_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf); void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, u32 changed); int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf); void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf); /* Hardware API Callbacks */ diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d365bdce2a10..b476f244a20e 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4701,6 +4701,7 @@ out: static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; @@ -4751,6 +4752,7 @@ out: static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9af283b1c3b5..4dc51c52dd28 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -261,11 +261,13 @@ enum ieee80211_chanctx_switch_mode { * done. * * @vif: the vif that should be switched from old_ctx to new_ctx + * @link_id: the link ID that's switching * @old_ctx: the old context to which the vif was assigned * @new_ctx: the new context to which the vif must be assigned */ struct ieee80211_vif_chanctx_switch { struct ieee80211_vif *vif; + unsigned int link_id; struct ieee80211_chanctx_conf *old_ctx; struct ieee80211_chanctx_conf *new_ctx; }; @@ -4262,9 +4264,11 @@ struct ieee80211_ops { u32 changed); int (*assign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx); void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx); int (*switch_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 69f540b0cbc6..884d2cfcec1e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -840,9 +840,10 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata) { - ieee80211_vif_release_channel(sdata); - ret = ieee80211_vif_use_channel(sdata, chandef, - IEEE80211_CHANCTX_EXCLUSIVE); + ieee80211_link_release_channel(sdata->link[0]); + ret = ieee80211_link_use_channel(sdata->link[0], + chandef, + IEEE80211_CHANCTX_EXCLUSIVE); } } else if (local->open_count == local->monitors) { local->_oper_chandef = *chandef; @@ -1183,10 +1184,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, } mutex_lock(&local->mtx); - err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[params->beacon.link_id], + ¶ms->chandef, + IEEE80211_CHANCTX_SHARED); if (!err) - ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + ieee80211_link_copy_chanctx_to_vlans(sdata->link[params->beacon.link_id], + false); mutex_unlock(&local->mtx); if (err) { sdata->vif.bss_conf.beacon_int = prev_beacon_int; @@ -1296,7 +1299,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, error: mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[params->beacon.link_id]); mutex_unlock(&local->mtx); return err; @@ -1433,8 +1436,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf); mutex_lock(&local->mtx); - ieee80211_vif_copy_chanctx_to_vlans(sdata, true); - ieee80211_vif_release_channel(sdata); + ieee80211_link_copy_chanctx_to_vlans(sdata->link[link_id], true); + ieee80211_link_release_channel(sdata->link[link_id]); mutex_unlock(&local->mtx); return 0; @@ -2401,8 +2404,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_vif_use_channel(sdata, &setup->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) return err; @@ -2416,7 +2419,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) ieee80211_stop_mesh(sdata); mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); kfree(sdata->u.mesh.ie); mutex_unlock(&sdata->local->mtx); @@ -3145,8 +3148,8 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; - err = ieee80211_vif_use_channel(sdata, chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], chandef, + IEEE80211_CHANCTX_SHARED); if (err) goto out_unlock; @@ -3174,7 +3177,7 @@ static void ieee80211_end_cac(struct wiphy *wiphy, cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work); if (sdata->wdev.cac_started) { - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); sdata->wdev.cac_started = false; } } @@ -3378,7 +3381,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (sdata->deflink.reserved_ready) return 0; - return ieee80211_vif_use_reserved_context(sdata); + return ieee80211_link_use_reserved_context(sdata->link[0]); } if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, @@ -3643,16 +3646,16 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, - chanctx->mode, - params->radar_required); + err = ieee80211_link_reserve_chanctx(sdata->link[0], ¶ms->chandef, + chanctx->mode, + params->radar_required); if (err) goto out; /* if reservation is invalid then this will fail */ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); if (err) { - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(sdata->link[0]); goto out; } @@ -3662,7 +3665,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, err = ieee80211_set_csa_beacon(sdata, params, &changed); if (err) { - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(sdata->link[0]); goto out; } @@ -3921,9 +3924,9 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, int ret = -ENODATA; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); if (chanctx_conf) { - *chandef = sdata->vif.bss_conf.chandef; + *chandef = sdata->vif.link_conf[link_id]->chandef; ret = 0; } else if (local->open_count > 0 && local->open_count == local->monitors && @@ -3980,7 +3983,8 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, int ret; u32 changed = 0; - ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); + ret = ieee80211_link_change_bandwidth(sdata->link[link_id], chandef, + &changed); if (ret == 0) ieee80211_link_info_change_notify(sdata, link_id, changed); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5d8b49f20198..4f25660d0eeb 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -15,12 +15,12 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; int num = 0; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) num++; return num; @@ -29,12 +29,12 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; int num = 0; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) num++; return num; @@ -67,12 +67,14 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) } static struct ieee80211_chanctx * -ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) +ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_chanctx_conf *conf; - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return NULL; @@ -80,21 +82,27 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) return container_of(conf, struct ieee80211_chanctx, conf); } +static struct ieee80211_chanctx * +ieee80211_link_get_chanctx(struct ieee80211_link_data *link) +{ + return ieee80211_vif_get_chanctx(link->sdata, link->link_id); +} + static const struct cfg80211_chan_def * ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct cfg80211_chan_def *compat) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { if (!compat) - compat = &sdata->deflink.reserved_chandef; + compat = &link->reserved_chandef; - compat = cfg80211_chandef_compatible(&sdata->deflink.reserved_chandef, + compat = cfg80211_chandef_compatible(&link->reserved_chandef, compat); if (!compat) break; @@ -108,20 +116,23 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct cfg80211_chan_def *compat) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->assigned_vifs, + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { - if (sdata->deflink.reserved_chanctx != NULL) + struct ieee80211_bss_conf *link_conf = + link->sdata->vif.link_conf[link->link_id]; + + if (link->reserved_chanctx) continue; if (!compat) - compat = &sdata->vif.bss_conf.chandef; + compat = &link_conf->chandef; compat = cfg80211_chandef_compatible( - &sdata->vif.bss_conf.chandef, compat); + &link_conf->chandef, compat); if (!compat) break; } @@ -157,7 +168,7 @@ ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, if (ieee80211_chanctx_combined_chandef(local, ctx, def)) return true; - if (!list_empty(&ctx->reserved_vifs) && + if (!list_empty(&ctx->reserved_links) && ieee80211_chanctx_reserved_chandef(local, ctx, def)) return true; @@ -193,13 +204,19 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, return NULL; } -static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta) +static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, + unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth width = ieee80211_sta_cap_rx_bw(sta); + enum ieee80211_sta_rx_bandwidth width = + ieee80211_sta_cap_rx_bw(sta, link_id); + + /* no effect if this STA has no presence on this link */ + if (!sta->sta.link[link_id]) + return NL80211_CHAN_WIDTH_20_NOHT; switch (width) { case IEEE80211_STA_RX_BW_20: - if (sta->sta.deflink.ht_cap.ht_supported) + if (sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20; else return NL80211_CHAN_WIDTH_20_NOHT; @@ -227,7 +244,8 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta) } static enum nl80211_chan_width -ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) +ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; struct sta_info *sta; @@ -238,7 +256,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) continue; - max_bw = max(max_bw, ieee80211_get_sta_bw(sta)); + max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id)); } rcu_read_unlock(); @@ -246,27 +264,28 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) } static enum nl80211_chan_width -ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, - struct ieee80211_chanctx_conf *conf) +ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx_conf *conf) { - struct ieee80211_sub_if_data *sdata; enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + struct ieee80211_vif *vif = &sdata->vif; + int link_id; - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - struct ieee80211_vif *vif = &sdata->vif; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - if (!ieee80211_sdata_running(sdata)) + if (!link_conf) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) continue; switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: - width = ieee80211_get_max_required_bw(sdata); + width = ieee80211_get_max_required_bw(sdata, link_id); break; case NL80211_IFTYPE_STATION: /* @@ -274,8 +293,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, * point, so take the width from the chandef, but * account also for TDLS peers */ - width = max(vif->bss_conf.chandef.width, - ieee80211_get_max_required_bw(sdata)); + width = max(link_conf->chandef.width, + ieee80211_get_max_required_bw(sdata, link_id)); break; case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_NAN: @@ -283,7 +302,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: - width = vif->bss_conf.chandef.width; + width = link_conf->chandef.width; break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_UNSPECIFIED: @@ -293,12 +312,36 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, case NL80211_IFTYPE_P2P_GO: WARN_ON_ONCE(1); } + + max_bw = max(max_bw, width); + } + + return max_bw; +} + +static enum nl80211_chan_width +ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *conf) +{ + struct ieee80211_sub_if_data *sdata; + enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + enum nl80211_chan_width width; + + if (!ieee80211_sdata_running(sdata)) + continue; + + width = ieee80211_get_chanctx_vif_max_required_bw(sdata, conf); + max_bw = max(max_bw, width); } /* use the configured bandwidth in case of monitor interface */ sdata = rcu_dereference(local->monitor_sdata); - if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf) + if (sdata && + rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == conf) max_bw = max(max_bw, conf->def.width); rcu_read_unlock(); @@ -350,7 +393,7 @@ static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, } /* calling this function is assuming that station vif is updated to - * lates changes by calling ieee80211_vif_update_chandef + * lates changes by calling ieee80211_link_update_chandef */ static void ieee80211_chan_bw_change(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, @@ -363,29 +406,38 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { + struct ieee80211_sub_if_data *sdata = sta->sdata; enum ieee80211_sta_rx_bandwidth new_sta_bw; + unsigned int link_id; if (!ieee80211_sdata_running(sta->sdata)) continue; - if (rcu_access_pointer(sta->sdata->vif.bss_conf.chanctx_conf) != - &ctx->conf) - continue; + for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; + + if (!link_conf) + continue; - new_sta_bw = ieee80211_sta_cur_vht_bw(sta); + if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf) + continue; - /* nothing change */ - if (new_sta_bw == sta->sta.deflink.bandwidth) - continue; + new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id); - /* vif changed to narrow BW and narrow BW for station wasn't - * requested or vise versa */ - if ((new_sta_bw < sta->sta.deflink.bandwidth) == !narrowed) - continue; + /* nothing change */ + if (new_sta_bw == sta->sta.link[link_id]->bandwidth) + continue; + + /* vif changed to narrow BW and narrow BW for station wasn't + * requested or vise versa */ + if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed) + continue; - sta->sta.deflink.bandwidth = new_sta_bw; - rate_control_rate_update(local, sband, sta, - IEEE80211_RC_BW_CHANGED); + sta->sta.link[link_id]->bandwidth = new_sta_bw; + rate_control_rate_update(local, sband, sta, link_id, + IEEE80211_RC_BW_CHANGED); + } } rcu_read_unlock(); } @@ -508,9 +560,14 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->deflink.radar_required) { - rcu_read_unlock(); - return true; + unsigned int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + if (sdata->link[link_id] && + sdata->link[link_id]->radar_required) { + rcu_read_unlock(); + return true; + } } } rcu_read_unlock(); @@ -531,15 +588,27 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + unsigned int link_id; + if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) - continue; - if (!sdata->deflink.radar_required) - continue; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - required = true; - break; + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) + continue; + if (!sdata->link[link_id]->radar_required) + continue; + required = true; + break; + } + + if (required) + break; } rcu_read_unlock(); @@ -559,8 +628,8 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, if (!ctx) return NULL; - INIT_LIST_HEAD(&ctx->assigned_vifs); - INIT_LIST_HEAD(&ctx->reserved_vifs); + INIT_LIST_HEAD(&ctx->assigned_links); + INIT_LIST_HEAD(&ctx->reserved_links); ctx->conf.def = *chandef; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; @@ -686,21 +755,32 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + int link_id; if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) - continue; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; - if (!compat) - compat = &sdata->vif.bss_conf.chandef; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - compat = cfg80211_chandef_compatible( - &sdata->vif.bss_conf.chandef, compat); - if (WARN_ON_ONCE(!compat)) - break; + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) + continue; + + if (!compat) + compat = &link_conf->chandef; + + compat = cfg80211_chandef_compatible(&link_conf->chandef, + compat); + if (WARN_ON_ONCE(!compat)) + break; + } } /* TDLS peers can sometimes affect the chandef width */ @@ -748,9 +828,11 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); } -static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *new_ctx) +static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, + struct ieee80211_chanctx *new_ctx) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *curr_ctx = NULL; @@ -759,29 +841,29 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) return -ENOTSUPP; - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_unassign_vif_chanctx(local, sdata, curr_ctx); + drv_unassign_vif_chanctx(local, sdata, link_id, curr_ctx); conf = NULL; - list_del(&sdata->assigned_chanctx_list); + list_del(&link->assigned_chanctx_list); } if (new_ctx) { - ret = drv_assign_vif_chanctx(local, sdata, new_ctx); + ret = drv_assign_vif_chanctx(local, sdata, link_id, new_ctx); if (ret) goto out; conf = &new_ctx->conf; - list_add(&sdata->assigned_chanctx_list, - &new_ctx->assigned_vifs); + list_add(&link->assigned_chanctx_list, + &new_ctx->assigned_links); } out: - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.link_conf[link_id]->chanctx_conf, conf); sdata->vif.cfg.idle = !conf; @@ -820,60 +902,64 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { u8 needed_static, needed_dynamic; + unsigned int link_id; if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != - &chanctx->conf) - continue; - switch (sdata->vif.type) { - case NL80211_IFTYPE_P2P_DEVICE: - case NL80211_IFTYPE_NAN: - continue; case NL80211_IFTYPE_STATION: if (!sdata->u.mgd.associated) continue; break; - case NL80211_IFTYPE_AP_VLAN: - continue; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: break; default: - WARN_ON_ONCE(1); + continue; } - switch (sdata->deflink.smps_mode) { - default: - WARN_ONCE(1, "Invalid SMPS mode %d\n", - sdata->deflink.smps_mode); - fallthrough; - case IEEE80211_SMPS_OFF: - needed_static = sdata->deflink.needed_rx_chains; - needed_dynamic = sdata->deflink.needed_rx_chains; - break; - case IEEE80211_SMPS_DYNAMIC: - needed_static = 1; - needed_dynamic = sdata->deflink.needed_rx_chains; - break; - case IEEE80211_SMPS_STATIC: - needed_static = 1; - needed_dynamic = 1; - break; - } + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_link_data *link = sdata->link[link_id]; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; + + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != &chanctx->conf) + continue; + + switch (link->smps_mode) { + default: + WARN_ONCE(1, "Invalid SMPS mode %d\n", + link->smps_mode); + fallthrough; + case IEEE80211_SMPS_OFF: + needed_static = link->needed_rx_chains; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_DYNAMIC: + needed_static = 1; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_STATIC: + needed_static = 1; + needed_dynamic = 1; + break; + } - rx_chains_static = max(rx_chains_static, needed_static); - rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + rx_chains_static = max(rx_chains_static, needed_static); + rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + } } /* Disable SMPS for the monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) + rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; rcu_read_unlock(); @@ -898,9 +984,12 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, } static void -__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear) +__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_sub_if_data *vlan; struct ieee80211_chanctx_conf *conf; @@ -916,7 +1005,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, * channel context pointer for a while, possibly pointing * to a channel context that has already been freed. */ - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); WARN_ON(!conf); @@ -924,32 +1013,34 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, conf = NULL; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(vlan->vif.link_conf[link_id]->chanctx_conf, + conf); } -void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear) +void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear) { - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = link->sdata->local; mutex_lock(&local->chanctx_mtx); - __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear); + __ieee80211_link_copy_chanctx_to_vlans(link, clear); mutex_unlock(&local->chanctx_mtx); } -int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) +int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) { - struct ieee80211_chanctx *ctx = sdata->deflink.reserved_chanctx; + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_chanctx *ctx = link->reserved_chanctx; lockdep_assert_held(&sdata->local->chanctx_mtx); if (WARN_ON(!ctx)) return -EINVAL; - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) { if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { @@ -974,17 +1065,18 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) return 0; } -int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode, - bool radar_required) +int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; lockdep_assert_held(&local->chanctx_mtx); - curr_ctx = ieee80211_vif_get_chanctx(sdata); + curr_ctx = ieee80211_link_get_chanctx(link); if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) return -ENOTSUPP; @@ -998,11 +1090,11 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, if (!curr_ctx || (curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_vifs)) { + !list_empty(&curr_ctx->reserved_links)) { /* - * Another vif already requested this context + * Another link already requested this context * for a reservation. Find another one hoping - * all vifs assigned to it will also switch + * all links assigned to it will also switch * soon enough. * * TODO: This needs a little more work as some @@ -1011,13 +1103,13 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, * provided some channel context juggling was * performed. * - * Consider ctx1..3, vif1..6, each ctx has 2 - * vifs. vif1 and vif2 from ctx1 request new + * Consider ctx1..3, link1..6, each ctx has 2 + * links. link1 and link2 from ctx1 request new * different chandefs starting 2 in-place * reserations with ctx4 and ctx5 replacing - * ctx1 and ctx2 respectively. Next vif5 and - * vif6 from ctx3 reserve ctx4. If vif3 and - * vif4 remain on ctx2 as they are then this + * ctx1 and ctx2 respectively. Next link5 and + * link6 from ctx3 reserve ctx4. If link3 and + * link4 remain on ctx2 as they are then this * fails unless `replace_ctx` from ctx5 is * replaced with ctx3. */ @@ -1027,7 +1119,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, IEEE80211_CHANCTX_REPLACE_NONE) continue; - if (!list_empty(&ctx->reserved_vifs)) + if (!list_empty(&ctx->reserved_links)) continue; curr_ctx = ctx; @@ -1042,7 +1134,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, if (!curr_ctx || (curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_vifs)) + !list_empty(&curr_ctx->reserved_links)) return -EBUSY; new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); @@ -1061,25 +1153,27 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, } } - list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs); - sdata->deflink.reserved_chanctx = new_ctx; - sdata->deflink.reserved_chandef = *chandef; - sdata->deflink.reserved_radar_required = radar_required; - sdata->deflink.reserved_ready = false; + list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links); + link->reserved_chanctx = new_ctx; + link->reserved_chandef = *chandef; + link->reserved_radar_required = radar_required; + link->reserved_ready = false; return 0; } static void -ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) +ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.csa_finalize_work); + &link->csa_finalize_work); break; case NL80211_IFTYPE_STATION: ieee80211_queue_work(&sdata->local->hw, @@ -1100,23 +1194,28 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) } static void -ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef) +ieee80211_link_update_chandef(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_sub_if_data *vlan; - sdata->vif.bss_conf.chandef = *chandef; + sdata->vif.link_conf[link_id]->chandef = *chandef; if (sdata->vif.type != NL80211_IFTYPE_AP) return; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - vlan->vif.bss_conf.chandef = *chandef; + vlan->vif.link_conf[link_id]->chandef = *chandef; } static int -ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) +ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; @@ -1127,10 +1226,10 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->mtx); lockdep_assert_held(&local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); - if (WARN_ON(!sdata->deflink.reserved_ready)) + if (WARN_ON(!link->reserved_ready)) return -EBUSY; if (WARN_ON(!new_ctx)) @@ -1144,23 +1243,24 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) return -EINVAL; chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &sdata->deflink.reserved_chandef); + &link->reserved_chandef); if (WARN_ON(!chandef)) return -EINVAL; - if (sdata->vif.bss_conf.chandef.width != sdata->deflink.reserved_chandef.width) + if (link_conf->chandef.width != link->reserved_chandef.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_vif_update_chandef(sdata, &sdata->deflink.reserved_chandef); + ieee80211_link_update_chandef(link, &link->reserved_chandef); ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef); vif_chsw[0].vif = &sdata->vif; vif_chsw[0].old_ctx = &old_ctx->conf; vif_chsw[0].new_ctx = &new_ctx->conf; + vif_chsw[0].link_id = link->link_id; - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; err = drv_switch_vif_chanctx(local, vif_chsw, 1, CHANCTX_SWMODE_REASSIGN_VIF); @@ -1171,11 +1271,11 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) goto out; } - list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, &new_ctx->conf); + list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links); + rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) - __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + __ieee80211_link_copy_chanctx_to_vlans(link, false); ieee80211_check_fast_xmit_iface(sdata); @@ -1187,25 +1287,27 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) ieee80211_recalc_radar_chanctx(local, new_ctx); if (changed) - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, link_id, changed); out: - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); return err; } static int -ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) +ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct cfg80211_chan_def *chandef; int err; - old_ctx = ieee80211_vif_get_chanctx(sdata); - new_ctx = sdata->deflink.reserved_chanctx; + old_ctx = ieee80211_vif_get_chanctx(sdata, link_id); + new_ctx = link->reserved_chanctx; - if (WARN_ON(!sdata->deflink.reserved_ready)) + if (WARN_ON(!link->reserved_ready)) return -EINVAL; if (WARN_ON(old_ctx)) @@ -1219,16 +1321,16 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) return -EINVAL; chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &sdata->deflink.reserved_chandef); + &link->reserved_chandef); if (WARN_ON(!chandef)) return -EINVAL; ieee80211_change_chanctx(local, new_ctx, new_ctx, chandef); - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; - err = ieee80211_assign_vif_chanctx(sdata, new_ctx); + err = ieee80211_assign_link_chanctx(link, new_ctx); if (err) { if (ieee80211_chanctx_refcount(local, new_ctx) == 0) ieee80211_free_chanctx(local, new_ctx); @@ -1237,19 +1339,20 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) } out: - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); return err; } static bool -ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata) +ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_chanctx *old_ctx, *new_ctx; lockdep_assert_held(&sdata->local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); if (!old_ctx) return false; @@ -1289,7 +1392,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, int n_vifs) { struct ieee80211_vif_chanctx_switch *vif_chsw; - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; struct ieee80211_chanctx *ctx, *old_ctx; int i, err; @@ -1310,16 +1413,16 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, goto out; } - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (!ieee80211_vif_has_in_place_reservation( - sdata)) + if (!ieee80211_link_has_in_place_reservation(link)) continue; - old_ctx = ieee80211_vif_get_chanctx(sdata); - vif_chsw[i].vif = &sdata->vif; + old_ctx = ieee80211_link_get_chanctx(link); + vif_chsw[i].vif = &link->sdata->vif; vif_chsw[i].old_ctx = &old_ctx->conf; vif_chsw[i].new_ctx = &ctx->conf; + vif_chsw[i].link_id = link->link_id; i++; } @@ -1345,7 +1448,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local) if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + if (!list_empty(&ctx->replace_ctx->assigned_links)) continue; ieee80211_del_chanctx(local, ctx->replace_ctx); @@ -1362,7 +1465,7 @@ err: if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + if (!list_empty(&ctx->replace_ctx->assigned_links)) continue; ieee80211_del_chanctx(local, ctx); @@ -1374,7 +1477,6 @@ err: static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata, *sdata_tmp; struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; struct ieee80211_chanctx *new_ctx = NULL; int err, n_assigned, n_reserved, n_ready; @@ -1400,6 +1502,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) */ list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; @@ -1417,12 +1521,12 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) n_reserved = 0; n_ready = 0; - list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs, + list_for_each_entry(link, &ctx->replace_ctx->assigned_links, assigned_chanctx_list) { n_assigned++; - if (sdata->deflink.reserved_chanctx) { + if (link->reserved_chanctx) { n_reserved++; - if (sdata->deflink.reserved_ready) + if (link->reserved_ready) n_ready++; } } @@ -1439,13 +1543,13 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) } ctx->conf.radar_enabled = false; - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (ieee80211_vif_has_in_place_reservation(sdata) && - !sdata->deflink.reserved_ready) + if (ieee80211_link_has_in_place_reservation(link) && + !link->reserved_ready) return -EAGAIN; - old_ctx = ieee80211_vif_get_chanctx(sdata); + old_ctx = ieee80211_link_get_chanctx(link); if (old_ctx) { if (old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) @@ -1456,7 +1560,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) n_vifs_ctxless++; } - if (sdata->deflink.reserved_radar_required) + if (link->reserved_radar_required) ctx->conf.radar_enabled = true; } } @@ -1499,6 +1603,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) * context(s). */ list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link, *link_tmp; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; @@ -1507,32 +1613,34 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) goto err; } - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link->link_id]; u32 changed = 0; - if (!ieee80211_vif_has_in_place_reservation(sdata)) + if (!ieee80211_link_has_in_place_reservation(link)) continue; - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, + rcu_assign_pointer(link_conf->chanctx_conf, &ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) - __ieee80211_vif_copy_chanctx_to_vlans(sdata, - false); + __ieee80211_link_copy_chanctx_to_vlans(link, + false); ieee80211_check_fast_xmit_iface(sdata); - sdata->deflink.radar_required = sdata->deflink.reserved_radar_required; + link->radar_required = link->reserved_radar_required; - if (sdata->vif.bss_conf.chandef.width != - sdata->deflink.reserved_chandef.width) + if (link_conf->chandef.width != link->reserved_chandef.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_vif_update_chandef(sdata, - &sdata->deflink.reserved_chandef); + ieee80211_link_update_chandef(link, &link->reserved_chandef); if (changed) - ieee80211_link_info_change_notify(sdata, 0, + ieee80211_link_info_change_notify(sdata, + link->link_id, changed); ieee80211_recalc_txpower(sdata, false); @@ -1543,17 +1651,17 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_recalc_radar_chanctx(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx); - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - if (ieee80211_vif_get_chanctx(sdata) != ctx) + if (ieee80211_link_get_chanctx(link) != ctx) continue; - list_del(&sdata->reserved_chanctx_list); - list_move(&sdata->assigned_chanctx_list, - &ctx->assigned_vifs); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + list_move(&link->assigned_chanctx_list, + &ctx->assigned_links); + link->reserved_chanctx = NULL; - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); } /* @@ -1563,31 +1671,29 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) * reservation for originally requested interface has already * succeeded at this point. */ - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - if (WARN_ON(ieee80211_vif_has_in_place_reservation( - sdata))) + if (WARN_ON(ieee80211_link_has_in_place_reservation(link))) continue; - if (WARN_ON(sdata->deflink.reserved_chanctx != ctx)) + if (WARN_ON(link->reserved_chanctx != ctx)) continue; - if (!sdata->deflink.reserved_ready) + if (!link->reserved_ready) continue; - if (ieee80211_vif_get_chanctx(sdata)) - err = ieee80211_vif_use_reserved_reassign( - sdata); + if (ieee80211_link_get_chanctx(link)) + err = ieee80211_link_use_reserved_reassign(link); else - err = ieee80211_vif_use_reserved_assign(sdata); + err = ieee80211_link_use_reserved_assign(link); if (err) { - sdata_info(sdata, - "failed to finalize (re-)assign reservation (err=%d)\n", - err); - ieee80211_vif_unreserve_chanctx(sdata); + link_info(link, + "failed to finalize (re-)assign reservation (err=%d)\n", + err); + ieee80211_link_unreserve_chanctx(link); cfg80211_stop_iface(local->hw.wiphy, - &sdata->wdev, + &link->sdata->wdev, GFP_KERNEL); } } @@ -1613,21 +1719,26 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) err: list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link, *link_tmp; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - ieee80211_vif_unreserve_chanctx(sdata); - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_unreserve_chanctx(link); + ieee80211_link_chanctx_reservation_complete(link); } } return err; } -static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1635,38 +1746,38 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return; ctx = container_of(conf, struct ieee80211_chanctx, conf); - if (sdata->deflink.reserved_chanctx) { - if (sdata->deflink.reserved_chanctx->replace_state == - IEEE80211_CHANCTX_REPLACES_OTHER && - ieee80211_chanctx_num_reserved(local, - sdata->deflink.reserved_chanctx) > 1) + if (link->reserved_chanctx) { + if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && + ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1) use_reserved_switch = true; - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(link); } - ieee80211_assign_vif_chanctx(sdata, NULL); + ieee80211_assign_link_chanctx(link, NULL); if (ieee80211_chanctx_refcount(local, ctx) == 0) ieee80211_free_chanctx(local, ctx); - sdata->deflink.radar_required = false; + link->radar_required = false; /* Unreserving may ready an in-place reservation. */ if (use_reserved_switch) ieee80211_vif_use_reserved_switch(local); } -int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode) +int ieee80211_link_use_channel(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *ctx; u8 radar_detect_width = 0; @@ -1686,14 +1797,14 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, if (ret > 0) radar_detect_width = BIT(chandef->width); - sdata->deflink.radar_required = ret; + sdata->link[link_id]->radar_required = ret; ret = ieee80211_check_combinations(sdata, chandef, mode, radar_detect_width); if (ret < 0) goto out; - __ieee80211_vif_release_channel(sdata); + __ieee80211_link_release_channel(link); ctx = ieee80211_find_chanctx(local, chandef, mode); if (!ctx) @@ -1703,9 +1814,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, goto out; } - ieee80211_vif_update_chandef(sdata, chandef); + ieee80211_link_update_chandef(link, chandef); - ret = ieee80211_assign_vif_chanctx(sdata, ctx); + ret = ieee80211_assign_link_chanctx(link, ctx); if (ret) { /* if assign fails refcount stays the same */ if (ieee80211_chanctx_refcount(local, ctx) == 0) @@ -1717,14 +1828,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_radar_chanctx(local, ctx); out: if (ret) - sdata->deflink.radar_required = false; + link->radar_required = false; mutex_unlock(&local->chanctx_mtx); return ret; } -int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) +int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *new_ctx; struct ieee80211_chanctx *old_ctx; @@ -1733,8 +1845,8 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->mtx); lockdep_assert_held(&local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); if (WARN_ON(!new_ctx)) return -EINVAL; @@ -1743,16 +1855,16 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) IEEE80211_CHANCTX_WILL_BE_REPLACED)) return -EINVAL; - if (WARN_ON(sdata->deflink.reserved_ready)) + if (WARN_ON(link->reserved_ready)) return -EINVAL; - sdata->deflink.reserved_ready = true; + link->reserved_ready = true; if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) { if (old_ctx) - return ieee80211_vif_use_reserved_reassign(sdata); + return ieee80211_link_use_reserved_reassign(link); - return ieee80211_vif_use_reserved_assign(sdata); + return ieee80211_link_use_reserved_assign(link); } /* @@ -1784,10 +1896,13 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) return 0; } -int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - u32 *changed) +int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + u32 *changed) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1799,18 +1914,18 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, return -EINVAL; mutex_lock(&local->chanctx_mtx); - if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) { + if (cfg80211_chandef_identical(chandef, &link_conf->chandef)) { ret = 0; goto out; } if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { + link_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { ret = -EINVAL; goto out; } - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { ret = -EINVAL; @@ -1845,7 +1960,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, break; } - ieee80211_vif_update_chandef(sdata, chandef); + ieee80211_link_update_chandef(link, chandef); ieee80211_recalc_chanctx_chantype(local, ctx); @@ -1856,19 +1971,24 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, return ret; } -void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +void ieee80211_link_release_channel(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); lockdep_assert_held(&sdata->local->mtx); mutex_lock(&sdata->local->chanctx_mtx); - __ieee80211_vif_release_channel(sdata); + __ieee80211_link_release_channel(link); mutex_unlock(&sdata->local->chanctx_mtx); } -void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) +void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *ap; struct ieee80211_chanctx_conf *conf; @@ -1880,9 +2000,9 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(ap->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(ap->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(link_conf->chanctx_conf, conf); mutex_unlock(&local->chanctx_mtx); } diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index d90a8f9cc3fd..3302e8da0314 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h @@ -1,4 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Portions + * Copyright (C) 2022 Intel Corporation + */ #ifndef __MAC80211_DEBUG_H #define __MAC80211_DEBUG_H #include @@ -130,6 +134,16 @@ do { \ #define sdata_dbg(sdata, fmt, ...) \ _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__) +#define link_info(link, fmt, ...) \ + _sdata_info((link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) +#define link_err(link, fmt, ...) \ + _sdata_err((link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) +#define link_dbg(link, fmt, ...) \ + _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) + #define ht_dbg(sdata, fmt, ...) \ _sdata_dbg(MAC80211_HT_DEBUG, \ sdata, fmt, ##__VA_ARGS__) diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 15ab8d00815b..9238283a8237 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -938,6 +938,7 @@ static inline void drv_change_chanctx(struct ieee80211_local *local, static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx) { int ret = 0; @@ -945,11 +946,12 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_assign_vif_chanctx(local, sdata, ctx); + trace_drv_assign_vif_chanctx(local, sdata, link_id, ctx); if (local->ops->assign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); ret = local->ops->assign_vif_chanctx(&local->hw, &sdata->vif, + link_id, &ctx->conf); } trace_drv_return_int(local, ret); @@ -959,6 +961,7 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx) { might_sleep(); @@ -966,11 +969,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_unassign_vif_chanctx(local, sdata, ctx); + trace_drv_unassign_vif_chanctx(local, sdata, link_id, ctx); if (local->ops->unassign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); local->ops->unassign_vif_chanctx(&local->hw, &sdata->vif, + link_id, &ctx->conf); } trace_drv_return_void(local); diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c index 96c9486bf2fe..2d9c6e845ce4 100644 --- a/net/mac80211/eht.c +++ b/net/mac80211/eht.c @@ -71,6 +71,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, eht_cap->has_eht = true; - sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta); - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta, 0); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); } diff --git a/net/mac80211/he.c b/net/mac80211/he.c index 1a61f7552edd..20448dda8c4d 100644 --- a/net/mac80211/he.c +++ b/net/mac80211/he.c @@ -3,7 +3,7 @@ * HE handling * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2019 - 2020 Intel Corporation + * Copyright(c) 2019 - 2022 Intel Corporation */ #include "ieee80211_i.h" @@ -153,8 +153,8 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, he_cap->has_he = true; - sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta); - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta, 0); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa) ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3b68e9f4345b..2ca75f2d3023 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -301,8 +301,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, radar_required = err; mutex_lock(&local->mtx); - if (ieee80211_vif_use_channel(sdata, &chandef, - ifibss->fixed_channel ? + if (ieee80211_link_use_channel(sdata->link[0], &chandef, + ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE)) { sdata_info(sdata, "Failed to join IBSS, no channel context\n"); @@ -371,7 +371,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, RCU_INIT_POINTER(ifibss->presp, NULL); kfree_rcu(presp, rcu_head); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", err); @@ -725,7 +725,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_IBSS); drv_leave_ibss(local, sdata); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 397b111f006d..92ed1e3c2980 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -787,8 +787,8 @@ struct ieee80211_chanctx { struct list_head list; struct rcu_head rcu_head; - struct list_head assigned_vifs; - struct list_head reserved_vifs; + struct list_head assigned_links; + struct list_head reserved_links; enum ieee80211_chanctx_replace_state replace_state; struct ieee80211_chanctx *replace_ctx; @@ -909,6 +909,12 @@ struct ieee80211_link_data_ap { }; struct ieee80211_link_data { + struct ieee80211_sub_if_data *sdata; + unsigned int link_id; + + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ + struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ + /* multicast keys only */ struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + @@ -989,9 +995,6 @@ struct ieee80211_sub_if_data { struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; struct mac80211_qos_map __rcu *qos_map; - struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ - struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ - /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; @@ -2119,8 +2122,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, struct sta_info *sta); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, + unsigned int link_id); +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, + unsigned int link_id); void ieee80211_sta_set_rx_nss(struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); @@ -2470,26 +2475,26 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); int __must_check -ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode); +ieee80211_link_use_channel(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode); int __must_check -ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode, - bool radar_required); +ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required); int __must_check -ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); -int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); +ieee80211_link_use_reserved_context(struct ieee80211_link_data *link); +int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link); int __must_check -ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - u32 *changed); -void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); -void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); -void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear); +ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + u32 *changed); +void ieee80211_link_release_channel(struct ieee80211_link_data *link); +void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link); +void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear); int ieee80211_chanctx_refcount(struct ieee80211_local *local, struct ieee80211_chanctx *ctx); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 04ee525394e9..1764068a18d1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -471,7 +471,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do chandef = sdata->vif.bss_conf.chandef; WARN_ON(local->suspended); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -1027,6 +1027,7 @@ static void ieee80211_sdata_init(struct ieee80211_local *local, */ sdata->vif.link_conf[0] = &sdata->vif.bss_conf; sdata->link[0] = &sdata->deflink; + sdata->deflink.sdata = sdata; } int ieee80211_add_virtual_monitor(struct ieee80211_local *local) @@ -1077,8 +1078,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) mutex_unlock(&local->iflist_mtx); mutex_lock(&local->mtx); - ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, - IEEE80211_CHANCTX_EXCLUSIVE); + ret = ieee80211_link_use_channel(sdata->link[0], &local->monitor_chandef, + IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); if (ret) { mutex_lock(&local->iflist_mtx); @@ -1122,7 +1123,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) synchronize_net(); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); drv_remove_interface(local, sdata); @@ -1228,7 +1229,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) case NL80211_IFTYPE_AP_VLAN: /* no need to tell driver, but set carrier and chanctx */ if (sdata->bss->active) { - ieee80211_vif_vlan_copy_chanctx(sdata); + ieee80211_link_vlan_copy_chanctx(sdata->link[0]); netif_carrier_on(dev); ieee80211_set_vif_encap_ops(sdata); } else { @@ -1681,8 +1682,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, ieee80211_csa_finalize_work); INIT_WORK(&sdata->deflink.color_change_finalize_work, ieee80211_color_change_finalize_work); - INIT_LIST_HEAD(&sdata->assigned_chanctx_list); - INIT_LIST_HEAD(&sdata->reserved_chanctx_list); + INIT_LIST_HEAD(&sdata->deflink.assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->deflink.reserved_chanctx_list); switch (type) { case NL80211_IFTYPE_P2P_GO: diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 42ba7424589e..a6cb1db50f1d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation * Author: Luis Carlos Cobo */ #include @@ -464,7 +464,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) rate_control_rate_init(sta); else - rate_control_rate_update(local, sband, sta, changed); + rate_control_rate_update(local, sband, sta, 0, changed); out: spin_unlock_bh(&sta->mesh->plink_lock); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e172bdfe9b0a..ca9e0d83e2a4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -479,7 +479,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, return -EINVAL; } - ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed); + ret = ieee80211_link_change_bandwidth(&sdata->deflink, &chandef, changed); if (ret) { sdata_info(sdata, @@ -1248,7 +1248,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (sdata->deflink.reserved_ready) goto out; - ret = ieee80211_vif_use_reserved_context(sdata); + ret = ieee80211_link_use_reserved_context(&sdata->deflink); if (ret) { sdata_info(sdata, "failed to use reserved channel context, disconnecting (err=%d)\n", @@ -1354,7 +1354,7 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(&sdata->deflink); mutex_unlock(&local->chanctx_mtx); if (sdata->deflink.csa_block_tx) @@ -1496,8 +1496,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, goto drop_connection; } - res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, - chanctx->mode, false); + res = ieee80211_link_reserve_chanctx(&sdata->deflink, &csa_ie.chandef, + chanctx->mode, false); if (res) { sdata_info(sdata, "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", @@ -1942,7 +1942,7 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) mutex_lock(&sdata->local->mtx); if (sdata->wdev.cac_started) { - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); @@ -2483,7 +2483,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags = 0; mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; @@ -2923,7 +2923,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); } @@ -2954,7 +2954,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.mu_mimo_owner = false; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); if (abandon) @@ -5497,8 +5497,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, * on incompatible channels, e.g. 80+80 and 160 sharing the * same control channel) try to use a smaller bandwidth. */ - ret = ieee80211_vif_use_channel(sdata, &chandef, - IEEE80211_CHANCTX_SHARED); + ret = ieee80211_link_use_channel(&sdata->deflink, &chandef, + IEEE80211_CHANCTX_SHARED); /* don't downgrade for 5 and 10 MHz channels, though. */ if (chandef.width == NL80211_CHAN_WIDTH_5 || @@ -5507,8 +5507,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); - ret = ieee80211_vif_use_channel(sdata, &chandef, - IEEE80211_CHANCTX_SHARED); + ret = ieee80211_link_use_channel(&sdata->deflink, &chandef, + IEEE80211_CHANCTX_SHARED); } out: mutex_unlock(&local->mtx); @@ -5868,7 +5868,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); kfree(auth_data); return err; diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index ab2658ad73ce..468c741a9aeb 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -186,8 +186,8 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_vif_use_channel(sdata, &setup->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) return err; @@ -229,7 +229,7 @@ int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&sdata->local->mtx); skb_queue_purge(&sdata->skb_queue); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index f22381127948..b268088585eb 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -90,14 +90,17 @@ void rate_control_tx_status(struct ieee80211_local *local, } void rate_control_rate_update(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta, u32 changed) + struct ieee80211_supported_band *sband, + struct sta_info *sta, unsigned int link_id, + u32 changed) { struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; struct ieee80211_chanctx_conf *chanctx_conf; + WARN_ON(link_id != 0); + if (ref && ref->ops->rate_update) { rcu_read_lock(); @@ -113,6 +116,7 @@ void rate_control_rate_update(struct ieee80211_local *local, spin_unlock_bh(&sta->rate_ctrl_lock); rcu_read_unlock(); } + drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 79b44d3db171..fbc8bdb54c43 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -3,6 +3,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc + * Copyright (C) 2022 Intel Corporation */ #ifndef IEEE80211_RATE_H @@ -31,8 +32,10 @@ void rate_control_tx_status(struct ieee80211_local *local, void rate_control_rate_init(struct sta_info *sta); void rate_control_rate_update(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta, u32 changed); + struct ieee80211_supported_band *sband, + struct sta_info *sta, + unsigned int link_id, + u32 changed); static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, struct sta_info *sta, gfp_t gfp) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 21e7424f261a..1774d0f9feaa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3369,7 +3369,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sband = rx->local->hw.wiphy->bands[status->band]; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_SMPS_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, @@ -3391,11 +3391,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) max_bw = IEEE80211_STA_RX_BW_20; else - max_bw = ieee80211_sta_cap_rx_bw(rx->sta); + max_bw = ieee80211_sta_cap_rx_bw(rx->sta, 0); /* set cur_max_bandwidth and recalc sta bw */ rx->sta->deflink.cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->sta); + new_bw = ieee80211_sta_cur_vht_bw(rx->sta, 0); if (rx->sta->sta.deflink.bandwidth == new_bw) goto handled; @@ -3406,7 +3406,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) ieee80211_sta_rx_bw_to_chan_width(rx->sta); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_BW_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 11a3b950b490..86a13ef31ef1 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1268,10 +1268,10 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, enum ieee80211_sta_rx_bandwidth bw; bw = ieee80211_chan_width_to_rx_bw(conf->def.width); - bw = min(bw, ieee80211_sta_cap_rx_bw(sta)); + bw = min(bw, ieee80211_sta_cap_rx_bw(sta, 0)); if (bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = bw; - rate_control_rate_update(local, sband, sta, + rate_control_rate_update(local, sband, sta, 0, IEEE80211_RC_BW_CHANGED); /* * if a TDLS peer BW was updated, we need to diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 9417378b4fc0..2f325eaf4576 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1625,6 +1625,7 @@ struct trace_chandef_entry { struct trace_switch_entry { struct trace_vif_entry vif; + unsigned int link_id; struct trace_chandef_entry old_chandef; struct trace_chandef_entry new_chandef; } __packed; @@ -1664,6 +1665,7 @@ TRACE_EVENT(drv_switch_vif_chanctx, SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); + SWITCH_ENTRY_ASSIGN(link_id, link_id); strncpy(local_vifs[i].vif.vif_name, sdata->name, sizeof(local_vifs[i].vif.vif_name)); @@ -1704,40 +1706,45 @@ TRACE_EVENT(drv_switch_vif_chanctx, DECLARE_EVENT_CLASS(local_sdata_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx), + TP_ARGS(local, sdata, link_id, ctx), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY CHANCTX_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; CHANCTX_ASSIGN; + __entry->link_id = link_id; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG + LOCAL_PR_FMT VIF_PR_FMT " link_id:%d" CHANCTX_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, CHANCTX_PR_ARG ) ); DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx) + TP_ARGS(local, sdata, link_id, ctx) ); DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx) + TP_ARGS(local, sdata, link_id, ctx) ); TRACE_EVENT(drv_start_ap, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2a279dc3e457..4ec96170a679 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2255,7 +2255,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) } static void ieee80211_assign_chanctx(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -2264,11 +2265,11 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, return; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_assign_vif_chanctx(local, sdata, ctx); + drv_assign_vif_chanctx(local, sdata, link_id, ctx); } mutex_unlock(&local->chanctx_mtx); } @@ -2474,7 +2475,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata && ieee80211_sdata_running(sdata)) - ieee80211_assign_chanctx(local, sdata); + ieee80211_assign_chanctx(local, sdata, 0); } /* reconfigure hardware */ @@ -2484,12 +2485,16 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { + unsigned int link; u32 changed; if (!ieee80211_sdata_running(sdata)) continue; - ieee80211_assign_chanctx(local, sdata); + for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { + if (sdata->vif.link_conf[link]) + ieee80211_assign_chanctx(local, sdata, link); + } switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: @@ -3975,7 +3980,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) if (sdata->wdev.cac_started) { chandef = sdata->vif.bss_conf.chandef; - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -4401,7 +4406,7 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; u8 radar_detect = 0; lockdep_assert_held(&local->chanctx_mtx); @@ -4409,20 +4414,26 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) return 0; - list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) - if (sdata->deflink.reserved_radar_required) - radar_detect |= BIT(sdata->deflink.reserved_chandef.width); + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) + if (link->reserved_radar_required) + radar_detect |= BIT(link->reserved_chandef.width); /* * An in-place reservation context should not have any assigned vifs * until it replaces the other context. */ WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && - !list_empty(&ctx->assigned_vifs)); + !list_empty(&ctx->assigned_links)); + + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { + struct ieee80211_sub_if_data *sdata = link->sdata; - list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) - if (sdata->deflink.radar_required) - radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); + if (!link->radar_required) + continue; + + radar_detect |= + BIT(sdata->vif.link_conf[link->link_id]->chandef.width); + } return radar_detect; } diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 7daca8352deb..27d260be9123 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -313,7 +313,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; } - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: @@ -330,19 +330,21 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, } /* FIXME: move this to some better location - parses HE/EHT now */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; - struct ieee80211_sta_he_cap *he_cap = &sta->sta.deflink.he_cap; - struct ieee80211_sta_eht_cap *eht_cap = &sta->sta.deflink.eht_cap; + struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + struct ieee80211_link_sta *link_sta = sta->sta.link[link_id]; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; u32 cap_width; if (he_cap->has_he) { u8 info; if (eht_cap->has_eht && - sta->sdata->vif.bss_conf.chandef.chan->band == - NL80211_BAND_6GHZ) { + link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { info = eht_cap->eht_cap_elem.phy_cap_info[0]; if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) @@ -351,8 +353,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) info = he_cap->he_cap_elem.phy_cap_info[0]; - if (sta->sdata->vif.bss_conf.chandef.chan->band == - NL80211_BAND_2GHZ) { + if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ) { if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) return IEEE80211_STA_RX_BW_40; else @@ -369,7 +370,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) } if (!vht_cap->vht_supported) - return sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; @@ -466,14 +467,15 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width) } /* FIXME: rename/move - this deals with everything not just VHT */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + enum nl80211_chan_width bss_width = link_conf->chandef.width; enum ieee80211_sta_rx_bandwidth bw; - enum nl80211_chan_width bss_width = sdata->vif.bss_conf.chandef.width; - bw = ieee80211_sta_cap_rx_bw(sta); - bw = min(bw, sta->deflink.cur_max_bandwidth); + bw = ieee80211_sta_cap_rx_bw(sta, link_id); + bw = min(bw, sta->link[link_id]->cur_max_bandwidth); /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of * IEEE80211-2016 specification makes higher bandwidth operation @@ -629,7 +631,7 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, break; } - new_bw = ieee80211_sta_cur_vht_bw(sta); + new_bw = ieee80211_sta_cur_vht_bw(sta, 0); if (new_bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = new_bw; sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta); @@ -692,7 +694,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, changed); + rate_control_rate_update(local, sband, sta, 0, changed); } } -- cgit v1.2.3 From ec7a04073d3b31c03a9ad00e0709ffd78b5cfd1b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 22:36:30 +0200 Subject: wifi: mac80211: use IEEE80211_MLD_MAX_NUM_LINKS Remove MAX_STA_LINKS and use IEEE80211_MLD_MAX_NUM_LINKS instead to unify between the station and other data structures. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 +--- net/mac80211/sta_info.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4dc51c52dd28..902a10ee50f2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2061,8 +2061,6 @@ struct ieee80211_sta_txpwr { enum nl80211_tx_power_setting type; }; -#define MAX_STA_LINKS 15 - /** * struct ieee80211_link_sta - station Link specific info * All link specific info for a STA link for a non MLD STA(single) @@ -2190,7 +2188,7 @@ struct ieee80211_sta { bool multi_link_sta; struct ieee80211_link_sta deflink; - struct ieee80211_link_sta *link[MAX_STA_LINKS]; + struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 134a7dad0ac4..2ff3d5fd0cbf 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -710,7 +710,7 @@ struct sta_info { bool multi_link_sta; struct link_sta_info deflink; - struct link_sta_info *link[MAX_STA_LINKS]; + struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* keep last! */ struct ieee80211_sta sta; -- cgit v1.2.3 From afe0d181905ed03c2379fcb81d423704f59f8788 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 23:22:19 +0200 Subject: wifi: mac80211: add link_id to vht.c code for MLO Update the code in vht.c and add the link_id parameter where necessary. Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- include/net/mac80211.h | 3 +- net/mac80211/cfg.c | 5 +- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 18 ++-- net/mac80211/iface.c | 6 +- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 6 +- net/mac80211/rate.c | 2 +- net/mac80211/rx.c | 2 +- net/mac80211/tdls.c | 2 +- net/mac80211/vht.c | 122 ++++++++++++---------- 12 files changed, 92 insertions(+), 80 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5d3cedc146be..2539dc5aaa3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1776,7 +1776,7 @@ static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac, * the data received from firmware as if it came from the * action frame, so no conversion is needed. */ - ieee80211_update_mu_groups(vif, + ieee80211_update_mu_groups(vif, 0, (u8 *)¬if->membership_status, (u8 *)¬if->user_position); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 902a10ee50f2..0a26cb2871d6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6548,6 +6548,7 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) * ieee80211_update_mu_groups - set the VHT MU-MIMO groud data * * @vif: the specified virtual interface + * @link_id: the link ID for MLO, otherwise 0 * @membership: 64 bits array - a bit is set if station is member of the group * @position: 2 bits per group id indicating the position in the group * @@ -6556,7 +6557,7 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) * matching GroupId management frame. * Calls to this function need to be serialized with RX path. */ -void ieee80211_update_mu_groups(struct ieee80211_vif *vif, +void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, const u8 *membership, const u8 *position); void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 884d2cfcec1e..53aac8f277e1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1763,7 +1763,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, /* VHT can override some HT caps such as the A-MSDU max length */ if (params->vht_capa) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - params->vht_capa, sta); + params->vht_capa, sta, 0); if (params->he_capa) ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, @@ -1784,7 +1784,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ - __ieee80211_vht_handle_opmode(sdata, sta, params->opmode_notif, + __ieee80211_vht_handle_opmode(sdata, sta, 0, + params->opmode_notif, sband->band); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2ca75f2d3023..87815a3624f3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1068,7 +1068,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, &chandef); memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - &cap_ie, sta); + &cap_ie, sta, 0); if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) rates_updated |= true; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 92ed1e3c2980..5be96b0bbd96 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2121,29 +2121,31 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta); + struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, unsigned int link_id); -void ieee80211_sta_set_rx_nss(struct sta_info *sta); +void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta); +enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, + unsigned int link_id); void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_mgmt *mgmt); u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band); + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band); + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band); void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_vht_cap *vht_cap); void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, u16 vht_mask[NL80211_VHT_NSS_MAX]); enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta); +ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id); /* HE */ void diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fa684d76a169..c5be60ee12d8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1496,14 +1496,14 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) - ieee80211_vht_handle_opmode(sdata, sta, opmode, - band); + ieee80211_vht_handle_opmode(sdata, sta, 0, + opmode, band); mutex_unlock(&local->sta_mtx); break; } case WLAN_VHT_ACTION_GROUPID_MGMT: - ieee80211_process_mu_groups(sdata, mgmt); + ieee80211_process_mu_groups(sdata, 0, mgmt); break; default: WARN_ON(1); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a6cb1db50f1d..fb7e8a9600ca 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -442,7 +442,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, changed |= IEEE80211_RC_BW_CHANGED; ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta); + elems->vht_cap_elem, sta, 0); ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ca9e0d83e2a4..643ef0ae786e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3570,7 +3570,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta); + elems->vht_cap_elem, + sta, 0); if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && elems->he_cap) { @@ -4377,7 +4378,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (sta && elems->opmode_notif) - ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, + ieee80211_vht_handle_opmode(sdata, sta, 0, + *elems->opmode_notif, rx_status->band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b268088585eb..402e898b75c3 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; - ieee80211_sta_set_rx_nss(sta); + ieee80211_sta_set_rx_nss(sta, 0); if (!ref) return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1774d0f9feaa..e6b16ebbdb48 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3403,7 +3403,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) rx->sta->sta.deflink.bandwidth = new_bw; sband = rx->local->hw.wiphy->bands[status->band]; sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->sta); + ieee80211_sta_rx_bw_to_chan_width(rx->sta, 0); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; rate_control_rate_update(local, sband, rx->sta, 0, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 86a13ef31ef1..4fc120c64022 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -308,7 +308,7 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, /* IEEE802.11ac-2013 Table E-4 */ u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; struct cfg80211_chan_def uc = sta->tdls_chandef; - enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta); + enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta, 0); int i; /* only support upgrading non-narrow channels up to 80Mhz */ diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 27d260be9123..acfe1459535f 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -116,16 +116,16 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta) + struct sta_info *sta, unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; struct ieee80211_sta_vht_cap own_cap; u32 cap_info, i; bool have_80mhz; memset(vht_cap, 0, sizeof(*vht_cap)); - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return; if (!vht_cap_ie || !sband->vht_cap.vht_supported) @@ -295,10 +295,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; default: - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; if (!(vht_cap->vht_mcs.tx_highest & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) @@ -310,10 +310,11 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * above) between 160 and 80+80 yet. */ if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = + IEEE80211_STA_RX_BW_160; } - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); + sta->sta.link[link_id]->bandwidth = ieee80211_sta_cur_vht_bw(sta, link_id); switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: @@ -391,16 +392,17 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, return IEEE80211_STA_RX_BW_80; } -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta) +enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; u32 cap_width; if (!vht_cap->vht_supported) { - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; - return sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return sta->sta.link[link_id]->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20; } @@ -415,15 +417,17 @@ enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta) } enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta) +ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth cur_bw = sta->sta.deflink.bandwidth; - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + enum ieee80211_sta_rx_bandwidth cur_bw = + sta->sta.link[link_id]->bandwidth; + struct ieee80211_sta_vht_cap *vht_cap = + &sta->sta.link[link_id]->vht_cap; u32 cap_width; switch (cur_bw) { case IEEE80211_STA_RX_BW_20: - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; else return NL80211_CHAN_WIDTH_20; @@ -497,18 +501,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, return bw; } -void ieee80211_sta_set_rx_nss(struct sta_info *sta) +void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) { u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss; bool support_160; /* if we received a notification already don't overwrite it */ - if (sta->sta.deflink.rx_nss) + if (sta->sta.link[link_id]->rx_nss) return; - if (sta->sta.deflink.eht_cap.has_eht) { + if (sta->sta.link[link_id]->eht_cap.has_eht) { int i; - const u8 *rx_nss_mcs = (void *)&sta->sta.deflink.eht_cap.eht_mcs_nss_supp; + const u8 *rx_nss_mcs = (void *)&sta->sta.link[link_id]->eht_cap.eht_mcs_nss_supp; /* get the max nss for EHT over all possible bandwidths and mcs */ for (i = 0; i < sizeof(struct ieee80211_eht_mcs_nss_supp); i++) @@ -517,10 +521,10 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) IEEE80211_EHT_MCS_NSS_RX)); } - if (sta->sta.deflink.he_cap.has_he) { + if (sta->sta.link[link_id]->he_cap.has_he) { int i; u8 rx_mcs_80 = 0, rx_mcs_160 = 0; - const struct ieee80211_sta_he_cap *he_cap = &sta->sta.deflink.he_cap; + const struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; u16 mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); @@ -551,23 +555,23 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) he_rx_nss = rx_mcs_80; } - if (sta->sta.deflink.ht_cap.ht_supported) { - if (sta->sta.deflink.ht_cap.mcs.rx_mask[0]) + if (sta->sta.link[link_id]->ht_cap.ht_supported) { + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[0]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[1]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[1]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[2]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[2]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[3]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[3]) ht_rx_nss++; /* FIXME: consider rx_highest? */ } - if (sta->sta.deflink.vht_cap.vht_supported) { + if (sta->sta.link[link_id]->vht_cap.vht_supported) { int i; u16 rx_mcs_map; - rx_mcs_map = le16_to_cpu(sta->sta.deflink.vht_cap.vht_mcs.rx_mcs_map); + rx_mcs_map = le16_to_cpu(sta->sta.link[link_id]->vht_cap.vht_mcs.rx_mcs_map); for (i = 7; i >= 0; i--) { u8 mcs = (rx_mcs_map >> (2 * i)) & 3; @@ -583,12 +587,12 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); rx_nss = max(eht_rx_nss, rx_nss); - sta->sta.deflink.rx_nss = max_t(u8, 1, rx_nss); + sta->sta.link[link_id]->rx_nss = max_t(u8, 1, rx_nss); } u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band) + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band) { enum ieee80211_sta_rx_bandwidth new_bw; struct sta_opmode_info sta_opmode = {}; @@ -603,8 +607,8 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; nss += 1; - if (sta->sta.deflink.rx_nss != nss) { - sta->sta.deflink.rx_nss = nss; + if (sta->sta.link[link_id]->rx_nss != nss) { + sta->sta.link[link_id]->rx_nss = nss; sta_opmode.rx_nss = nss; changed |= IEEE80211_RC_NSS_CHANGED; sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; @@ -613,28 +617,28 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_20; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_40; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80) - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; else - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: /* legacy only, no longer used by newer spec */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; } - new_bw = ieee80211_sta_cur_vht_bw(sta, 0); - if (new_bw != sta->sta.deflink.bandwidth) { - sta->sta.deflink.bandwidth = new_bw; - sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta); + new_bw = ieee80211_sta_cur_vht_bw(sta, link_id); + if (new_bw != sta->sta.link[link_id]->bandwidth) { + sta->sta.link[link_id]->bandwidth = new_bw; + sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta, link_id); changed |= IEEE80211_RC_BW_CHANGED; sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED; } @@ -647,54 +651,56 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, } void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_mgmt *mgmt) { - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; - if (!sdata->vif.bss_conf.mu_mimo_owner) + if (!link_conf->mu_mimo_owner) return; if (!memcmp(mgmt->u.action.u.vht_group_notif.position, - bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) && + link_conf->mu_group.position, WLAN_USER_POSITION_LEN) && !memcmp(mgmt->u.action.u.vht_group_notif.membership, - bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN)) + link_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN)) return; - memcpy(bss_conf->mu_group.membership, + memcpy(link_conf->mu_group.membership, mgmt->u.action.u.vht_group_notif.membership, WLAN_MEMBERSHIP_LEN); - memcpy(bss_conf->mu_group.position, + memcpy(link_conf->mu_group.position, mgmt->u.action.u.vht_group_notif.position, WLAN_USER_POSITION_LEN); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, link_id, BSS_CHANGED_MU_GROUPS); } -void ieee80211_update_mu_groups(struct ieee80211_vif *vif, +void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, const u8 *membership, const u8 *position) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id]; - if (WARN_ON_ONCE(!vif->bss_conf.mu_mimo_owner)) + if (WARN_ON_ONCE(!link_conf->mu_mimo_owner)) return; - memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); - memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); + memcpy(link_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); + memcpy(link_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); } EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band) + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; - u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band); + u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, link_id, + opmode, band); if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, 0, changed); + rate_control_rate_update(local, sband, sta, link_id, changed); } } -- cgit v1.2.3 From e9aac179ad4526afa3190856b71aa41decb6dc6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 23:45:04 +0200 Subject: wifi: mac80211: make some SMPS code MLD-aware Start making some SMPS related code MLD-aware. This isn't really done yet, but again cuts down our 'deflink' reliance. Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/dvm/lib.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- include/net/mac80211.h | 3 ++- net/mac80211/cfg.c | 19 +++++++++++------ net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ht.c | 29 ++++++++++++++------------ net/mac80211/ieee80211_i.h | 4 +++- net/mac80211/iface.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/util.c | 5 +++-- 11 files changed, 45 insertions(+), 31 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 40d790b36d85..1dc974e2c511 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014, 2022 Intel Corporation. All rights reserved. *****************************************************************************/ #include #include @@ -441,7 +441,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) priv->current_ht_config.smps = smps_request; for_each_context(priv, ctx) { if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) - ieee80211_request_smps(ctx->vif, smps_request); + ieee80211_request_smps(ctx->vif, 0, smps_request); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 3ee5ea3484be..14b2de65bd84 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -304,7 +304,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, smps_mode = IEEE80211_SMPS_DYNAMIC; } - ieee80211_request_smps(vif, smps_mode); + ieee80211_request_smps(vif, 0, smps_mode); } static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f78b9f28d5f6..985ee36efc0f 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1600,9 +1600,9 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, return; if (rtwdev->hal.txrx_1ss) - ieee80211_request_smps(vif, IEEE80211_SMPS_STATIC); + ieee80211_request_smps(vif, 0, IEEE80211_SMPS_STATIC); else - ieee80211_request_smps(vif, IEEE80211_SMPS_OFF); + ieee80211_request_smps(vif, 0, IEEE80211_SMPS_OFF); } void rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool txrx_1ss) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0a26cb2871d6..302340f6fa08 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6210,13 +6210,14 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, /** * ieee80211_request_smps - request SM PS transition * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: link ID for MLO, or 0 * @smps_mode: new SM PS mode * * This allows the driver to request an SM PS transition in managed * mode. This is useful when the driver has more information than * the stack about possible interference, for example by bluetooth. */ -void ieee80211_request_smps(struct ieee80211_vif *vif, +void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode); /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d7f2eb7421c3..2c9554174bcf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2913,6 +2913,7 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy, #endif int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, enum ieee80211_smps_mode smps_mode) { const u8 *ap; @@ -2926,8 +2927,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) return -EINVAL; - old_req = sdata->deflink.u.mgd.req_smps; - sdata->deflink.u.mgd.req_smps = smps_mode; + old_req = sdata->link[link_id]->u.mgd.req_smps; + sdata->link[link_id]->u.mgd.req_smps = smps_mode; if (old_req == smps_mode && smps_mode != IEEE80211_SMPS_AUTOMATIC) @@ -2939,10 +2940,10 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, * the new value until we associate. */ if (!sdata->u.mgd.associated || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) + sdata->vif.link_conf[link_id]->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; - ap = sdata->deflink.u.mgd.bssid; + ap = sdata->link[link_id]->u.mgd.bssid; rcu_read_lock(); list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { @@ -2966,7 +2967,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, err = ieee80211_send_smps_action(sdata, smps_mode, ap, ap); if (err) - sdata->deflink.u.mgd.req_smps = old_req; + sdata->link[link_id]->u.mgd.req_smps = old_req; else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found) ieee80211_teardown_tdls_peers(sdata); @@ -2978,6 +2979,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + unsigned int link_id; if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; @@ -2994,7 +2996,12 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, /* no change, but if automatic follow powersave */ sdata_lock(sdata); - __ieee80211_request_smps_mgd(sdata, sdata->deflink.u.mgd.req_smps); + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + if (!sdata->link[link_id]) + continue; + __ieee80211_request_smps_mgd(sdata, link_id, + sdata->link[link_id]->u.mgd.req_smps); + } sdata_unlock(sdata); if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index bd398b631763..dfb194e15018 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -256,7 +256,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; sdata_lock(sdata); - err = __ieee80211_request_smps_mgd(sdata, smps_mode); + err = __ieee80211_request_smps_mgd(sdata, 0, smps_mode); sdata_unlock(sdata); return err; diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 22677df83ed8..111828b559a0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -542,30 +542,33 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, void ieee80211_request_smps_mgd_work(struct work_struct *work) { - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - deflink.u.mgd.request_smps_work); - - sdata_lock(sdata); - __ieee80211_request_smps_mgd(sdata, - sdata->deflink.u.mgd.driver_smps_mode); - sdata_unlock(sdata); + struct ieee80211_link_data *link = + container_of(work, struct ieee80211_link_data, + u.mgd.request_smps_work); + + sdata_lock(link->sdata); + __ieee80211_request_smps_mgd(link->sdata, link->link_id, + link->u.mgd.driver_smps_mode); + sdata_unlock(link->sdata); } -void ieee80211_request_smps(struct ieee80211_vif *vif, +void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_link_data *link = sdata->link[link_id]; if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION)) return; - if (sdata->deflink.u.mgd.driver_smps_mode == smps_mode) + if (WARN_ON(!link)) return; - sdata->deflink.u.mgd.driver_smps_mode = smps_mode; - ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.u.mgd.request_smps_work); + if (link->u.mgd.driver_smps_mode == smps_mode) + return; + + link->u.mgd.driver_smps_mode = smps_mode; + ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work); } /* this might change ... don't want non-open drivers using it */ EXPORT_SYMBOL_GPL(ieee80211_request_smps); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e75496a99299..0948d074c4b9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2422,8 +2422,10 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band band, u32 *basic_rates); int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, enum ieee80211_smps_mode smps_mode); -void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, + unsigned int link_id); void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c5be60ee12d8..ea75d5d5cb6a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1657,7 +1657,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, recalc_smps); - ieee80211_recalc_smps(sdata); + ieee80211_recalc_smps(sdata, 0); } /* diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 30423b2d4eee..cdbf7a5dc2ba 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2337,7 +2337,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local); mutex_unlock(&local->iflist_mtx); - ieee80211_recalc_smps(sdata); + ieee80211_recalc_smps(sdata, 0); ieee80211_recalc_ps_vif(sdata); netif_carrier_on(sdata->dev); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4ec96170a679..ecda655e7481 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2803,7 +2803,8 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif) } EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); -void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *chanctx_conf; @@ -2811,7 +2812,7 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + chanctx_conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); /* -- cgit v1.2.3 From d648c23024bd01333acd2fd5e34bcde0ffb66b16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 19:48:33 +0200 Subject: wifi: nl80211: support MLO in auth/assoc For authentication, we need the BSS, the link_id and the AP MLD address to create the link and station, (for now) the driver assigns a link address and sends the frame, the MLD address needs to be the address of the interface. For association, pass the list of BSSes that were selected for the MLO connection, along with extra per-STA profile elements, the AP MLD address and the link ID on which the association request should be sent. Note that for now we don't have a proper way to pass the link address(es) and so the driver/mac80211 will select one, but depending on how that selection works it means that assoc w/o auth data still being around (mac80211 implementation detail) the association won't necessarily work - so this will need to be extended in the future to sort out the link addressing. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 31 +++++++++++++++ include/uapi/linux/nl80211.h | 3 ++ net/wireless/mlme.c | 30 +++++++++++++-- net/wireless/nl80211.c | 91 ++++++++++++++++++++++++++++++++++++++++++-- net/wireless/sme.c | 2 + 5 files changed, 151 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 772e099fc932..a4f9e6094118 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2718,6 +2718,12 @@ static inline const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 id) * Authentication algorithm number, i.e., starting at the Authentication * transaction sequence number field. * @auth_data_len: Length of auth_data buffer in octets + * @link_id: if >= 0, indicates authentication should be done as an MLD, + * the interface address is included as the MLD address and the + * necessary link (with the given link_id) will be created (and + * given an MLD address) by the driver + * @ap_mld_addr: AP MLD address in case of authentication request with + * an AP MLD, valid iff @link_id >= 0 */ struct cfg80211_auth_request { struct cfg80211_bss *bss; @@ -2728,6 +2734,21 @@ struct cfg80211_auth_request { u8 key_len, key_idx; const u8 *auth_data; size_t auth_data_len; + s8 link_id; + const u8 *ap_mld_addr; +}; + +/** + * struct cfg80211_assoc_link - per-link information for MLO association + * @bss: the BSS pointer, see also &struct cfg80211_assoc_request::bss; + * if this is %NULL for a link, that link is not requested + * @elems: extra elements for the per-STA profile for this link + * @elems_len: length of the elements + */ +struct cfg80211_assoc_link { + struct cfg80211_bss *bss; + const u8 *elems; + size_t elems_len; }; /** @@ -2761,6 +2782,8 @@ enum cfg80211_assoc_req_flags { * given a reference that it must give back to cfg80211_send_rx_assoc() * or to cfg80211_assoc_timeout(). To ensure proper refcounting, new * association requests while already associating must be rejected. + * This also applies to the @links.bss parameter, which is used instead + * of this one (it is %NULL) for MLO associations. * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association @@ -2785,6 +2808,11 @@ enum cfg80211_assoc_req_flags { * with 16 octets of STA Nonce followed by 16 octets of AP Nonce. * @s1g_capa: S1G capability override * @s1g_capa_mask: S1G capability override mask + * @links: per-link information for MLO connections + * @link_id: >= 0 for MLO connections, where links are given, and indicates + * the link on which the association request should be sent + * @ap_mld_addr: AP MLD address in case of MLO association request, + * valid iff @link_id >= 0 */ struct cfg80211_assoc_request { struct cfg80211_bss *bss; @@ -2800,6 +2828,9 @@ struct cfg80211_assoc_request { size_t fils_kek_len; const u8 *fils_nonces; struct ieee80211_s1g_cap s1g_capa, s1g_capa_mask; + struct cfg80211_assoc_link links[IEEE80211_MLD_MAX_NUM_LINKS]; + const u8 *ap_mld_addr; + s8 link_id; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a9a2c9fef295..60ad9a9f153d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2687,6 +2687,8 @@ enum nl80211_commands { * various commands that need a link ID to operate. * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some * per-link information and a link ID. + * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as + * authenticate/associate. * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined @@ -3204,6 +3206,7 @@ enum nl80211_attrs { NL80211_ATTR_MLO_LINKS, NL80211_ATTR_MLO_LINK_ID, + NL80211_ATTR_MLD_ADDR, /* add attributes here, update the policy in nl80211.c */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 532113937469..d92eed0e52cd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -241,6 +241,10 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!req->bss) return -ENOENT; + if (req->link_id >= 0 && + !(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + if (req->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { if (!req->key || !req->key_len || req->key_idx < 0 || req->key_idx > 3) @@ -294,10 +298,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct cfg80211_assoc_request *req) { struct wireless_dev *wdev = dev->ieee80211_ptr; - int err; + int err, i, j; ASSERT_WDEV_LOCK(wdev); + for (i = 1; i < ARRAY_SIZE(req->links); i++) { + if (!req->links[i].bss) + continue; + for (j = 0; j < i; j++) { + if (req->links[i].bss == req->links[j].bss) + return -EINVAL; + } + } + if (wdev->connected && (!req->prev_bssid || !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid))) @@ -310,8 +323,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, err = rdev_assoc(rdev, dev, req); if (!err) { - cfg80211_ref_bss(&rdev->wiphy, req->bss); - cfg80211_hold_bss(bss_from_pub(req->bss)); + int link_id; + + if (req->bss) { + cfg80211_ref_bss(&rdev->wiphy, req->bss); + cfg80211_hold_bss(bss_from_pub(req->bss)); + } + + for (link_id = 0; link_id < ARRAY_SIZE(req->links); link_id++) { + if (!req->links[link_id].bss) + continue; + cfg80211_ref_bss(&rdev->wiphy, req->links[link_id].bss); + cfg80211_hold_bss(bss_from_pub(req->links[link_id].bss)); + } } return err; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5a4d3ddcdf80..9bc66a21ac3a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -796,6 +796,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_NESTED_ARRAY(nl80211_policy), [NL80211_ATTR_MLO_LINK_ID] = NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), + [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), }; /* policy for the key attributes */ @@ -10282,6 +10283,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) req.key = key.p.key; req.key_len = key.p.key_len; req.key_idx = key.idx; + req.link_id = nl80211_link_id_or_invalid(info->attrs); + if (req.link_id >= 0) { + if (!info->attrs[NL80211_ATTR_MLD_ADDR]) + return -EINVAL; + req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + } req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, IEEE80211_BSS_TYPE_ESS, @@ -10475,7 +10482,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct cfg80211_assoc_request req = {}; + struct nlattr **attrs = NULL; const u8 *bssid, *ssid; + unsigned int link_id; int err, ssid_len; if (dev->ieee80211_ptr->conn_owner_nlportid && @@ -10585,9 +10594,81 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) sizeof(req.s1g_capa)); } - req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs, &bssid); - if (IS_ERR(req.bss)) - return PTR_ERR(req.bss); + req.link_id = nl80211_link_id_or_invalid(info->attrs); + + if (info->attrs[NL80211_ATTR_MLO_LINKS]) { + unsigned int attrsize = NUM_NL80211_ATTR * sizeof(*attrs); + struct nlattr *link; + int rem = 0; + + if (req.link_id < 0) + return -EINVAL; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MAC] || + info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_MLD_ADDR]) + return -EINVAL; + + req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + + attrs = kzalloc(attrsize, GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + nla_for_each_nested(link, + info->attrs[NL80211_ATTR_MLO_LINKS], + rem) { + memset(attrs, 0, attrsize); + + nla_parse_nested(attrs, NL80211_ATTR_MAX, + link, NULL, NULL); + + if (!attrs[NL80211_ATTR_MLO_LINK_ID]) { + err = -EINVAL; + goto free; + } + + link_id = nla_get_u8(attrs[NL80211_ATTR_MLO_LINK_ID]); + /* cannot use the same link ID again */ + if (req.links[link_id].bss) { + err = -EINVAL; + goto free; + } + req.links[link_id].bss = + nl80211_assoc_bss(rdev, ssid, ssid_len, attrs, + &bssid); + if (IS_ERR(req.links[link_id].bss)) { + err = PTR_ERR(req.links[link_id].bss); + goto free; + } + + if (attrs[NL80211_ATTR_IE]) { + req.links[link_id].elems = + nla_data(attrs[NL80211_ATTR_IE]); + req.links[link_id].elems_len = + nla_len(attrs[NL80211_ATTR_IE]); + } + } + + if (!req.links[req.link_id].bss) { + err = -EINVAL; + goto free; + } + + kfree(attrs); + attrs = NULL; + } else { + if (req.link_id >= 0) + return -EINVAL; + + req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs, + &bssid); + if (IS_ERR(req.bss)) + return PTR_ERR(req.bss); + } err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); if (!err) { @@ -10605,7 +10686,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) wdev_unlock(dev->ieee80211_ptr); } +free: + for (link_id = 0; link_id < ARRAY_SIZE(req.links); link_id++) + cfg80211_put_bss(&rdev->wiphy, req.links[link_id].bss); cfg80211_put_bss(&rdev->wiphy, req.bss); + kfree(attrs); return err; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index c8a99b90723b..b3c6ce4f85ee 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -177,6 +177,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev, params->ssid, params->ssid_len, IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); + auth_req.link_id = -1; err = cfg80211_mlme_auth(rdev, wdev->netdev, &auth_req); cfg80211_put_bss(&rdev->wiphy, auth_req.bss); return err; @@ -198,6 +199,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev, req.ht_capa_mask = params->ht_capa_mask; req.vht_capa = params->vht_capa; req.vht_capa_mask = params->vht_capa_mask; + req.link_id = -1; req.bss = cfg80211_get_bss(&rdev->wiphy, params->channel, params->bssid, -- cgit v1.2.3 From d8787ec6b4ef1857b827699eca6f5978d0aecd74 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 23:20:08 +0200 Subject: wifi: mac80211: add vif link addition/removal Add the necessary infrastructure, including a new driver method, to add/remove links to/from an interface. Also add the missing link address to bss_conf (which we use as link_conf too), and fill it, in station mode for now just randomly, in AP mode we get the address from cfg80211 since the link must be created with an address first. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++ net/mac80211/driver-ops.h | 21 +++++++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/iface.c | 134 ++++++++++++++++++++++++++++++++++++++++++++- net/mac80211/trace.h | 27 +++++++++ 5 files changed, 197 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 302340f6fa08..f221afdfa475 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -515,6 +515,7 @@ struct ieee80211_fils_discovery { * This structure keeps information about a BSS (and an association * to that BSS) that can change during the lifetime of the BSS. * + * @addr: (link) address used locally * @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE * @uora_exists: is the UORA element advertised by AP * @ack_enabled: indicates support to receive a multi-TID that solicits either @@ -638,6 +639,7 @@ struct ieee80211_fils_discovery { */ struct ieee80211_bss_conf { const u8 *bssid; + u8 addr[ETH_ALEN] __aligned(2); u8 htc_trig_based_pkt_ext; bool uora_exists; u8 uora_ocw_range; @@ -1743,6 +1745,7 @@ struct ieee80211_vif_cfg { * or the BSS we're associated to * @link_conf: in case of MLD, the per-link BSS configuration, * indexed by link ID + * @valid_links: bitmap of valid links, or 0 for non-MLO. * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1778,6 +1781,7 @@ struct ieee80211_vif { struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; + u16 valid_links; u8 addr[ETH_ALEN] __aligned(2); bool p2p; @@ -4028,6 +4032,13 @@ struct ieee80211_prep_tx_info { * disable background CAC/radar detection. * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to * resolve a path for hardware flow offloading + * @change_vif_links: Change the valid links on an interface, note that while + * removing the old link information is still valid (link_conf pointer), + * but may immediately disappear after the function returns. The old or + * new links bitmaps may be 0 if going from/to a non-MLO situation. + * The @old[] array contains pointers to the old bss_conf structures + * that were already removed, in case they're needed. + * This callback can sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4371,6 +4382,10 @@ struct ieee80211_ops { struct ieee80211_sta *sta, struct net_device_path_ctx *ctx, struct net_device_path *path); + int (*change_vif_links)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9238283a8237..c8133c84d7d5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1533,4 +1533,25 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local, return ret; } +static inline int drv_change_vif_links(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_change_vif_links(local, sdata, old_links, new_links); + if (local->ops->change_vif_links) + ret = local->ops->change_vif_links(&local->hw, &sdata->vif, + old_links, new_links, old); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8286e607152c..22f17231dede 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2006,6 +2006,9 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); int ieee80211_add_virtual_monitor(struct ieee80211_local *local); void ieee80211_del_virtual_monitor(struct ieee80211_local *local); +int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, + u16 new_links); + bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, bool update_bss); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ea75d5d5cb6a..f118e7710fb1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -220,8 +220,10 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) ret = eth_mac_addr(dev, sa); - if (ret == 0) + if (ret == 0) { memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); + } return ret; } @@ -449,7 +451,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do cancel_work_sync(&local->dynamic_ps_enable_work); cancel_work_sync(&sdata->recalc_smps); + sdata_lock(sdata); + WARN(sdata->vif.valid_links, + "destroying interface with valid links 0x%04x\n", + sdata->vif.valid_links); + mutex_lock(&local->mtx); sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) @@ -1013,10 +1020,15 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) } static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + int link_id, struct ieee80211_link_data *link, struct ieee80211_bss_conf *link_conf) { + bool deflink = link_id < 0; + + if (link_id < 0) + link_id = 0; + sdata->vif.link_conf[link_id] = link_conf; sdata->link[link_id] = link; @@ -1031,6 +1043,23 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, INIT_LIST_HEAD(&link->reserved_chanctx_list); INIT_DELAYED_WORK(&link->dfs_cac_timer_work, ieee80211_dfs_cac_timer_work); + + if (!deflink) { + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + ether_addr_copy(link_conf->addr, + sdata->wdev.links[link_id].addr); + WARN_ON(!(sdata->wdev.valid_links & BIT(link_id))); + break; + case NL80211_IFTYPE_STATION: + eth_random_addr(link_conf->addr); + ether_addr_copy(sdata->wdev.links[link_id].addr, + link_conf->addr); + break; + default: + WARN_ON(1); + } + } } static void ieee80211_sdata_init(struct ieee80211_local *local, @@ -1046,7 +1075,7 @@ static void ieee80211_sdata_init(struct ieee80211_local *local, * Note that we never change this, so if link ID 0 isn't used in an * MLD connection, we get a separate allocation for it. */ - ieee80211_link_init(sdata, 0, &sdata->deflink, &sdata->vif.bss_conf); + ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf); } int ieee80211_add_virtual_monitor(struct ieee80211_local *local) @@ -1768,6 +1797,10 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, if (!local->ops->change_interface) return -EBUSY; + /* for now, don't support changing while links exist */ + if (sdata->vif.valid_links) + return -EBUSY; + switch (sdata->vif.type) { case NL80211_IFTYPE_AP: if (!list_empty(&sdata->u.ap.vlans)) @@ -2030,6 +2063,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, strlcpy(sdata->name, name, IFNAMSIZ); ieee80211_assign_perm_addr(local, wdev->address, type); memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); } else { int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size, sizeof(void *)); @@ -2094,6 +2128,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata = netdev_priv(ndev); ndev->ieee80211_ptr = &sdata->wdev; memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); memcpy(sdata->name, ndev->name, IFNAMSIZ); if (txq_size) { @@ -2318,3 +2353,96 @@ void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata) else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) atomic_dec(&sdata->u.vlan.num_mcast_sta); } + +int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, + u16 new_links) +{ + u16 old_links = sdata->vif.valid_links; + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + unsigned int link_id; + int ret; + struct { + struct ieee80211_link_data data; + struct ieee80211_bss_conf conf; + } *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link; + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS]; + bool use_deflink = old_links == 0; /* set for error case */ + + sdata_assert_lock(sdata); + + if (old_links == new_links) + return 0; + + /* allocate new link structures first */ + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) { + ret = -ENOMEM; + goto free; + } + links[link_id] = link; + } + + /* keep track of the old pointers for the driver */ + BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf)); + memcpy(old, sdata->vif.link_conf, sizeof(old)); + /* and for us in error cases */ + BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link)); + memcpy(old_data, sdata->link, sizeof(old_data)); + + /* link them into data structures */ + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + WARN_ON(!use_deflink && + sdata->link[link_id] == &sdata->deflink); + + link = links[link_id]; + ieee80211_link_init(sdata, link_id, &link->data, &link->conf); + } + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + sdata->link[link_id] = NULL; + sdata->vif.link_conf[link_id] = NULL; + } + + sdata->vif.valid_links = new_links; + + /* tell the driver */ + ret = drv_change_vif_links(sdata->local, sdata, + old_links, new_links, + old); + if (ret) { + /* restore config */ + memcpy(sdata->link, old_data, sizeof(old_data)); + memcpy(sdata->vif.link_conf, old, sizeof(old)); + sdata->vif.valid_links = old_links; + /* and free the newly allocated links */ + goto free; + } + + /* use deflink/bss_conf again if and only if there are no more links */ + use_deflink = new_links == 0; + + /* now use this to free the old links */ + memset(links, 0, sizeof(links)); + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + if (sdata->link[link_id] == &sdata->deflink) + continue; + /* + * we must have allocated the data through this path so + * we know we can free both at the same time + */ + links[link_id] = container_of(sdata->link[link_id], + typeof(*links[link_id]), + data); + } + +free: + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + kfree(links[link_id]); + if (use_deflink) + ieee80211_link_init(sdata, -1, &sdata->deflink, + &sdata->vif.bss_conf); + return ret; +} diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 295db57a76a2..256ebab13cda 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2455,6 +2455,33 @@ DEFINE_EVENT(sta_event, drv_net_fill_forward_path, TP_ARGS(local, sdata, sta) ); +TRACE_EVENT(drv_change_vif_links, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u16 old_links, u16 new_links), + + TP_ARGS(local, sdata, old_links, new_links), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u16, old_links) + __field(u16, new_links) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->old_links = old_links; + __entry->new_links = new_links; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " old_links:0x%04x, new_links:0x%04x\n", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->old_links, __entry->new_links + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v1.2.3 From eef25a6679adb3cc73b611cf6c78386f54df0e0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jun 2022 15:59:31 +0200 Subject: wifi: mac80211: remove band from TX info in MLO If the interface is an MLD, then we don't know which band the frame will be transmitted on, and we don't know how to look up the band. Set the band information to zero in that case, the driver cannot rely on it anyway. No longer inline ieee80211_tx_skb_tid() since it's even bigger now. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++- net/mac80211/ieee80211_i.h | 19 ++-------- net/mac80211/tx.c | 89 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 39 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f221afdfa475..8222419c9ead 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1029,7 +1029,9 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) * (3) TX status information - driver tells mac80211 what happened * * @flags: transmit info flags, defined above - * @band: the band to transmit on (use for checking for races) + * @band: the band to transmit on (use e.g. for checking for races), + * not valid if the interface is an MLD since we won't know which + * link the frame will be transmitted on * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC * @ack_frame_id: internal frame ID for TX status, used internally * @tx_time_est: TX time estimate in units of 4us, used internally diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 22f17231dede..0f69859e4e39 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2251,23 +2251,8 @@ ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } -static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid) -{ - struct ieee80211_chanctx_conf *chanctx_conf; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (WARN_ON(!chanctx_conf)) { - rcu_read_unlock(); - kfree_skb(skb); - return; - } - - __ieee80211_tx_skb_tid_band(sdata, skb, tid, - chanctx_conf->def.chan->band); - rcu_read_unlock(); -} +void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid); static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0589d2d66fe6..e8a5e27a3dd1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2566,8 +2566,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, bool tdls_peer; bool multicast; u16 info_id = 0; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_sub_if_data *ap_sdata; + struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; @@ -2584,7 +2583,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, ethertype = (skb->data[12] << 8) | skb->data[13]; fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (!sdata->vif.valid_links) + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: @@ -2599,10 +2600,16 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = sta->sta.wme; } - /* override chanctx_conf from AP (we don't have one) */ - ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, - u.ap); - chanctx_conf = rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); + if (!sdata->vif.valid_links) { + struct ieee80211_sub_if_data *ap_sdata; + + /* override chanctx_conf from AP (we don't have one) */ + ap_sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); + chanctx_conf = + rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); + } if (sdata->wdev.use_4addr) break; fallthrough; @@ -2738,10 +2745,15 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } if (!chanctx_conf) { - ret = -ENOTCONN; - goto free; + if (!sdata->vif.valid_links) { + ret = -ENOTCONN; + goto free; + } + /* MLD transmissions must not rely on the band */ + band = 0; + } else { + band = chanctx_conf->def.chan->band; } - band = chanctx_conf->def.chan->band; multicast = is_multicast_ether_addr(hdr.addr1); @@ -2953,14 +2965,20 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG)) goto out; - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (!chanctx_conf) { + if (!sdata->vif.valid_links) { + rcu_read_lock(); + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + goto out; + } + build.band = chanctx_conf->def.chan->band; rcu_read_unlock(); - goto out; + } else { + /* MLD transmissions must not rely on the band */ + build.band = 0; } - build.band = chanctx_conf->def.chan->band; - rcu_read_unlock(); fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); @@ -4577,12 +4595,16 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, sdata = vif_to_sdata(info->control.vif); if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (unlikely(!chanctx_conf)) { - dev_kfree_skb(skb); - return true; + /* update band only for non-MLD */ + if (!sdata->vif.valid_links) { + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (unlikely(!chanctx_conf)) { + dev_kfree_skb(skb); + return true; + } + info->band = chanctx_conf->def.chan->band; } - info->band = chanctx_conf->def.chan->band; result = ieee80211_tx(sdata, NULL, skb, true); } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { @@ -5665,6 +5687,31 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, local_bh_enable(); } +void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + enum nl80211_band band; + + rcu_read_lock(); + if (!sdata->vif.valid_links) { + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + kfree_skb(skb); + return; + } + band = chanctx_conf->def.chan->band; + } else { + /* MLD transmissions must not rely on the band */ + band = 0; + } + + __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + rcu_read_unlock(); +} + int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len, const u8 *dest, __be16 proto, bool unencrypted, -- cgit v1.2.3 From 69d41b5a9c9d8d24c0faeb376fc2f52fc810d855 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Jun 2022 22:05:07 +0200 Subject: wifi: mac80211: add MLO link ID to TX frame metadata Take a few bits out of the control.flags to add the link ID to TX frame metadata, so drivers don't need to look it up by the address themselves. Implement that lookup where it's needed, for internal frame TX, and set it to "unspecified" for data transmissions. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 +++++++ net/mac80211/tx.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8222419c9ead..1bea225c0d4d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -867,6 +867,10 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_DONT_REORDER: This frame should not be reordered * relative to other frames that have this flag set, independent * of their QoS TID or other priority field values. + * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this + * frame should be transmitted on the specific link. This really is + * only relevant for frames that do not have data present, and is + * also not used for 802.3 format frames. * * These flags are used in tx_info->control.flags. */ @@ -880,8 +884,11 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6), IEEE80211_TX_CTRL_NO_SEQNO = BIT(7), IEEE80211_TX_CTRL_DONT_REORDER = BIT(8), + IEEE80211_TX_CTRL_MLO_LINK = 0xf0000000, }; +#define IEEE80211_LINK_UNSPECIFIED 0xf + /** * enum mac80211_tx_status_flags - flags to describe transmit status * diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e8a5e27a3dd1..17313954c628 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2889,7 +2889,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, info->flags = info_flags; info->ack_frame_id = info_id; info->band = band; - info->control.flags = ctrl_flags; + info->control.flags = ctrl_flags | + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + IEEE80211_TX_CTRL_MLO_LINK); return skb; free: @@ -3558,7 +3560,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | IEEE80211_TX_CTL_DONTFRAG | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); - info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; + info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT | + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + IEEE80211_TX_CTRL_MLO_LINK); #ifdef CONFIG_MAC80211_DEBUGFS if (local->force_tx_status) @@ -5668,7 +5672,9 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int tid, enum nl80211_band band) { + const struct ieee80211_hdr *hdr = (void *)skb->data; int ac = ieee80211_ac_from_tid(tid); + unsigned int link; skb_reset_mac_header(skb); skb_set_queue_mapping(skb, ac); @@ -5676,6 +5682,30 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, skb->dev = sdata->dev; + BUILD_BUG_ON(IEEE80211_LINK_UNSPECIFIED < IEEE80211_MLD_MAX_NUM_LINKS); + BUILD_BUG_ON(!FIELD_FIT(IEEE80211_TX_CTRL_MLO_LINK, + IEEE80211_LINK_UNSPECIFIED)); + + if (!sdata->vif.valid_links) { + link = 0; + } else if (memcmp(sdata->vif.addr, hdr->addr2, ETH_ALEN) == 0) { + /* address from the MLD */ + link = IEEE80211_LINK_UNSPECIFIED; + } else { + /* otherwise must be addressed from a link */ + for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { + if (memcmp(sdata->vif.link_conf[link]->addr, + hdr->addr2, ETH_ALEN) == 0) + break; + } + + if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf))) + link = ffs(sdata->vif.valid_links) - 1; + } + + IEEE80211_SKB_CB(skb)->control.flags |= + u32_encode_bits(link, IEEE80211_TX_CTRL_MLO_LINK); + /* * The other path calling ieee80211_xmit is from the tasklet, * and while we can handle concurrent transmissions locking -- cgit v1.2.3 From cb71f1d136a635decf43c3b502ee34fb05640fcd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 23:20:08 +0200 Subject: wifi: mac80211: add sta link addition/removal Add the necessary infrastructure, including a new driver method, to add/remove links to/from a station. To do this, refactor the link alloc/free a bit, splitting that so we can do it without linking them, to handle failures better. Note that a station entry must be created representing an MLD or a non-MLD STA, it cannot change between the two. When representing an MLD, the 'deflink' is used for the first link, which might be removed later, in which case the memory isn't reused. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 13 +++- net/mac80211/cfg.c | 2 +- net/mac80211/driver-ops.h | 21 +++++++ net/mac80211/ibss.c | 4 +- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/ocb.c | 2 +- net/mac80211/sta_info.c | 156 +++++++++++++++++++++++++++++++++++++++------- net/mac80211/sta_info.h | 8 ++- net/mac80211/trace.h | 31 +++++++++ 10 files changed, 206 insertions(+), 35 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1bea225c0d4d..1bc9d1d9769a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2150,7 +2150,6 @@ struct ieee80211_link_sta { * @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that * the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames - * @multi_link_sta: Identifies if this sta is a MLD STA * @deflink: This holds the default link STA information, for non MLO STA all link * specific STA information is accessed through @deflink or through * link[0] which points to address of @deflink. For MLO Link STA @@ -2162,6 +2161,7 @@ struct ieee80211_link_sta { * @deflink address and remaining would be allocated and the address * would be assigned to link[link_id] where link_id is the id assigned * by the AP. + * @valid_links: bitmap of valid links, or 0 for non-MLO */ struct ieee80211_sta { u8 addr[ETH_ALEN]; @@ -2199,7 +2199,7 @@ struct ieee80211_sta { struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; - bool multi_link_sta; + u16 valid_links; struct ieee80211_link_sta deflink; struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -4048,6 +4048,11 @@ struct ieee80211_prep_tx_info { * The @old[] array contains pointers to the old bss_conf structures * that were already removed, in case they're needed. * This callback can sleep. + * @change_sta_links: Change the valid links of a station, similar to + * @change_vif_links. This callback can sleep. + * Note that a sta can also be inserted or removed with valid links, + * i.e. passed to @sta_add/@sta_state with sta->valid_links not zero. + * In fact, cannot change from having valid_links and not having them. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4395,6 +4400,10 @@ struct ieee80211_ops { struct ieee80211_vif *vif, u16 old_links, u16 new_links, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]); + int (*change_sta_links)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e30659b1242b..abc3fa5a8d7e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1839,7 +1839,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; - sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + sta = sta_info_alloc(sdata, mac, -1, GFP_KERNEL); if (!sta) return -ENOMEM; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c8133c84d7d5..52be89f8f0bc 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1554,4 +1554,25 @@ static inline int drv_change_vif_links(struct ieee80211_local *local, return ret; } +static inline int drv_change_sta_links(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); + if (local->ops->change_sta_links) + ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, + old_links, new_links); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 09c11c067cbf..65a3808dc92a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -629,7 +629,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_KERNEL); + sta = sta_info_alloc(sdata, addr, -1, GFP_KERNEL); if (!sta) { rcu_read_lock(); return NULL; @@ -1229,7 +1229,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e24bd48bc915..fe54ac431202 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -510,7 +510,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) if (aid < 0) return NULL; - sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); + sta = sta_info_alloc(sdata, hw_addr, -1, GFP_KERNEL); if (!sta) return NULL; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b6ee8da07663..c2c997086553 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5579,7 +5579,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (!have_sta) { - new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); + new_sta = sta_info_alloc(sdata, cbss->bssid, -1, GFP_KERNEL); if (!new_sta) return -ENOMEM; } diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 468c741a9aeb..0fd29d9c496c 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -69,7 +69,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f20ce7bbcb39..b1426a2459e8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -64,6 +64,11 @@ * freed before they are done using it. */ +struct sta_link_alloc { + struct link_sta_info info; + struct ieee80211_link_sta sta; +}; + static const struct rhashtable_params sta_rht_params = { .nelem_hint = 3, /* start small */ .automatic_shrinking = true, @@ -245,17 +250,27 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, return NULL; } -static void sta_info_free_links(struct sta_info *sta) +static void sta_info_free_link(struct link_sta_info *link_sta) { - unsigned int link_id; + free_percpu(link_sta->pcpu_rx_stats); +} - for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) { - if (!sta->link[link_id]) - continue; - free_percpu(sta->link[link_id]->pcpu_rx_stats); +static void sta_remove_link(struct sta_info *sta, unsigned int link_id) +{ + struct sta_link_alloc *alloc = NULL; - if (sta->link[link_id] != &sta->deflink) - kfree(sta->link[link_id]); + if (WARN_ON(!sta->link[link_id])) + return; + + if (sta->link[link_id] != &sta->deflink) + alloc = container_of(sta->link[link_id], typeof(*alloc), info); + + sta->sta.valid_links &= ~BIT(link_id); + sta->link[link_id] = NULL; + sta->sta.link[link_id] = NULL; + if (alloc) { + sta_info_free_link(&alloc->info); + kfree(alloc); } } @@ -272,6 +287,15 @@ static void sta_info_free_links(struct sta_info *sta) */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { + int i; + + for (i = 0; i < ARRAY_SIZE(sta->link); i++) { + if (!(sta->sta.valid_links & BIT(i))) + continue; + + sta_remove_link(sta, i); + } + /* * If we had used sta_info_pre_move_state() then we might not * have gone through the state transitions down again, so do @@ -302,7 +326,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) kfree(sta->mesh); #endif - sta_info_free_links(sta); + sta_info_free_link(&sta->deflink); kfree(sta); } @@ -348,19 +372,13 @@ static int sta_prepare_rate_control(struct ieee80211_local *local, return 0; } -static int sta_info_init_link(struct sta_info *sta, - unsigned int link_id, - struct link_sta_info *link_info, - struct ieee80211_link_sta *link_sta, - gfp_t gfp) +static int sta_info_alloc_link(struct ieee80211_local *local, + struct link_sta_info *link_info, + gfp_t gfp) { - struct ieee80211_local *local = sta->local; struct ieee80211_hw *hw = &local->hw; int i; - link_info->sta = sta; - link_info->link_id = link_id; - if (ieee80211_hw_check(hw, USES_RSS)) { link_info->pcpu_rx_stats = alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); @@ -368,9 +386,6 @@ static int sta_info_init_link(struct sta_info *sta, return -ENOMEM; } - sta->link[link_id] = link_info; - sta->sta.link[link_id] = link_sta; - link_info->rx_stats.last_rx = jiffies; u64_stats_init(&link_info->rx_stats.syncp); @@ -382,8 +397,19 @@ static int sta_info_init_link(struct sta_info *sta, return 0; } +static void sta_info_add_link(struct sta_info *sta, + unsigned int link_id, + struct link_sta_info *link_info, + struct ieee80211_link_sta *link_sta) +{ + link_info->sta = sta; + link_info->link_id = link_id; + sta->link[link_id] = link_info; + sta->sta.link[link_id] = link_sta; +} + struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, gfp_t gfp) + const u8 *addr, int link_id, gfp_t gfp) { struct ieee80211_local *local = sdata->local; struct ieee80211_hw *hw = &local->hw; @@ -397,9 +423,17 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; - if (sta_info_init_link(sta, 0, &sta->deflink, &sta->sta.deflink, gfp)) + if (sta_info_alloc_link(local, &sta->deflink, gfp)) return NULL; + if (link_id >= 0) { + sta_info_add_link(sta, link_id, &sta->deflink, + &sta->sta.deflink); + sta->sta.valid_links = BIT(link_id); + } else { + sta_info_add_link(sta, 0, &sta->deflink, &sta->sta.deflink); + } + spin_lock_init(&sta->lock); spin_lock_init(&sta->ps_lock); INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); @@ -565,7 +599,7 @@ free_txq: if (sta->sta.txq[0]) kfree(to_txq_info(sta->sta.txq[0])); free: - sta_info_free_links(sta); + sta_info_free_link(&sta->deflink); #ifdef CONFIG_MAC80211_MESH kfree(sta->mesh); #endif @@ -2613,3 +2647,77 @@ void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, sta_update_codel_params(sta, thr); } + +int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct sta_link_alloc *alloc; + int ret; + + lockdep_assert_held(&sdata->local->sta_mtx); + + /* must represent an MLD from the start */ + if (WARN_ON(!sta->sta.valid_links)) + return -EINVAL; + + if (WARN_ON(sta->sta.valid_links & BIT(link_id) || + sta->link[link_id])) + return -EBUSY; + + alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + ret = sta_info_alloc_link(sdata->local, &alloc->info, GFP_KERNEL); + if (ret) { + kfree(alloc); + return ret; + } + + sta_info_add_link(sta, link_id, &alloc->info, &alloc->sta); + + return 0; +} + +int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + u16 old_links = sta->sta.valid_links; + u16 new_links = old_links | BIT(link_id); + int ret; + + lockdep_assert_held(&sdata->local->sta_mtx); + + if (WARN_ON(old_links == new_links || !sta->link[link_id])) + return -EINVAL; + + sta->sta.valid_links = new_links; + + if (!test_sta_flag(sta, WLAN_STA_INSERTED)) + return 0; + + ret = drv_change_sta_links(sdata->local, sdata, &sta->sta, + old_links, new_links); + if (ret) { + sta->sta.valid_links = old_links; + sta_remove_link(sta, link_id); + } + + return ret; +} + +void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + + lockdep_assert_held(&sdata->local->sta_mtx); + + sta->sta.valid_links &= ~BIT(link_id); + + if (test_sta_flag(sta, WLAN_STA_INSERTED)) + drv_change_sta_links(sdata->local, sdata, &sta->sta, + sta->sta.valid_links, + sta->sta.valid_links & ~BIT(link_id)); + + sta_remove_link(sta, link_id); +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2ff3d5fd0cbf..8ec65bb7d13e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -623,7 +623,6 @@ struct link_sta_info { * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to * the BSS one. * @frags: fragment cache - * @multi_link_sta: Identifies if this sta is a MLD STA or regular STA * @deflink: This is the default link STA information, for non MLO STA all link * specific STA information is accessed through @deflink or through * link[0] which points to address of @deflink. For MLO Link STA @@ -708,7 +707,6 @@ struct sta_info { struct ieee80211_fragment_cache frags; - bool multi_link_sta; struct link_sta_info deflink; struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -833,7 +831,7 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, * until sta_info_insert(). */ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, gfp_t gfp); + const u8 *addr, int link_id, gfp_t gfp); void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); @@ -892,6 +890,10 @@ u32 sta_get_expected_throughput(struct sta_info *sta); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); +int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id); +int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id); +void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id); + void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 256ebab13cda..9804634e7d99 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2482,6 +2482,37 @@ TRACE_EVENT(drv_change_vif_links, ) ); +TRACE_EVENT(drv_change_sta_links, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links), + + TP_ARGS(local, sdata, sta, old_links, new_links), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u16, old_links) + __field(u16, new_links) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->old_links = old_links; + __entry->new_links = new_links; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " old_links:0x%04x, new_links:0x%04x\n", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, + __entry->old_links, __entry->new_links + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v1.2.3 From f2a0290b2df2b0e65ab78b71c4a15e732afd4458 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jun 2022 11:07:55 +0200 Subject: wifi: cfg80211: add optional link add/remove callbacks Add some optional callbacks for link add/remove so that drivers can react here. Initially, I thought it would be sufficient to just create the link in start_ap etc., but it turns out that's not so simple, since there are quite a few callbacks that can be called: if they're erroneously without start_ap, things might crash. Thus it might be easier for drivers to allocate all the necessary data structures immediately, to not have to worry about it in each callback, since cfg80211 checks that the link ID is valid (has been added.) Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 12 ++++++++++++ net/wireless/nl80211.c | 14 +++++++++++++- net/wireless/rdev-ops.h | 26 ++++++++++++++++++++++++++ net/wireless/trace.h | 20 +++++++++++++++++++- 4 files changed, 70 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a4f9e6094118..5706f96b819a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3858,6 +3858,11 @@ struct mgmt_frame_regs { * keep the struct wireless_dev's iftype updated. * This additionally holds the RTNL to be able to do netdev changes. * + * @add_intf_link: Add a new MLO link to the given interface. Note that + * the wdev->link[] data structure has been updated, so the new link + * address is available. + * @del_intf_link: Remove an MLO link from the given interface. + * * @add_key: add a key with the given parameters. @mac_addr will be %NULL * when adding a group key. * @@ -4212,6 +4217,13 @@ struct cfg80211_ops { enum nl80211_iftype type, struct vif_params *params); + int (*add_intf_link)(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id); + void (*del_intf_link)(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id); + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9bc66a21ac3a..0a69a5a6b74d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15556,9 +15556,11 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) { + struct cfg80211_registered_device *rdev = info->user_ptr[0]; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; + int ret; if (!(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) return -EINVAL; @@ -15578,13 +15580,20 @@ static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) wdev->valid_links |= BIT(link_id); ether_addr_copy(wdev->links[link_id].addr, nla_data(info->attrs[NL80211_ATTR_MAC])); + + ret = rdev_add_intf_link(rdev, wdev, link_id); + if (ret) { + wdev->valid_links &= ~BIT(link_id); + eth_zero_addr(wdev->links[link_id].addr); + } wdev_unlock(wdev); - return 0; + return ret; } static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) { + struct cfg80211_registered_device *rdev = info->user_ptr[0]; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -15604,6 +15613,9 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); wdev->valid_links &= ~BIT(link_id); + + rdev_del_intf_link(rdev, wdev, link_id); + eth_zero_addr(wdev->links[link_id].addr); wdev_unlock(wdev); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d2300eff03ae..a329ba036989 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1422,4 +1422,30 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_add_intf_link(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + unsigned int link_id) +{ + int ret = 0; + + trace_rdev_add_intf_link(&rdev->wiphy, wdev, link_id); + if (rdev->ops->add_intf_link) + ret = rdev->ops->add_intf_link(&rdev->wiphy, wdev, link_id); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + +static inline void +rdev_del_intf_link(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + unsigned int link_id) +{ + trace_rdev_del_intf_link(&rdev->wiphy, wdev, link_id); + if (rdev->ops->add_intf_link) + rdev->ops->add_intf_link(&rdev->wiphy, wdev, link_id); + trace_rdev_return_void(&rdev->wiphy); +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 92742430958e..65f8b814ecd0 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2064,7 +2064,7 @@ TRACE_EVENT(rdev_set_noack_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); -TRACE_EVENT(rdev_get_channel, +DECLARE_EVENT_CLASS(wiphy_wdev_link_evt, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, unsigned int link_id), TP_ARGS(wiphy, wdev, link_id), @@ -2082,6 +2082,12 @@ TRACE_EVENT(rdev_get_channel, WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id) ); +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_get_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + TRACE_EVENT(rdev_return_chandef, TP_PROTO(struct wiphy *wiphy, int ret, struct cfg80211_chan_def *chandef), @@ -2823,6 +2829,18 @@ TRACE_EVENT(rdev_set_radar_background, WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_add_intf_link, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_del_intf_link, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ -- cgit v1.2.3 From ae7ba17b49b6707e62f31643dda25592c29482f8 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 2 Jun 2022 15:08:16 +0300 Subject: wifi: mac80211: pass the link id in start/stop ap In start_ap and stop_ap mac80211 callbacks pass the link_id to the drivers. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 40 +++++++++++++++++++---- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 6 ++-- drivers/net/wireless/silabs/wfx/sta.c | 6 ++-- drivers/net/wireless/silabs/wfx/sta.h | 6 ++-- include/net/mac80211.h | 6 ++-- net/mac80211/cfg.c | 4 +-- net/mac80211/driver-ops.h | 15 +++++---- net/mac80211/trace.h | 36 ++++++++++++++++---- net/mac80211/util.c | 2 +- 10 files changed, 93 insertions(+), 31 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 2539dc5aaa3f..eaffc3163bd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2396,7 +2396,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2522,8 +2523,22 @@ out_unlock: return ret; } +static int iwl_mvm_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id) +{ + return iwl_mvm_start_ap_ibss(hw, vif, link_id); +} + +static int iwl_mvm_start_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return iwl_mvm_start_ap_ibss(hw, vif, 0); +} + static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2586,6 +2601,19 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id) +{ + iwl_mvm_stop_ap_ibss(hw, vif, link_id); +} + +static void iwl_mvm_stop_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + iwl_mvm_stop_ap_ibss(hw, vif, 0); +} + static void iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -5408,10 +5436,10 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx, - .start_ap = iwl_mvm_start_ap_ibss, - .stop_ap = iwl_mvm_stop_ap_ibss, - .join_ibss = iwl_mvm_start_ap_ibss, - .leave_ibss = iwl_mvm_stop_ap_ibss, + .start_ap = iwl_mvm_start_ap, + .stop_ap = iwl_mvm_stop_ap, + .join_ibss = iwl_mvm_start_ibss, + .leave_ibss = iwl_mvm_stop_ibss, .tx_last_beacon = iwl_mvm_tx_last_beacon, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 9e0b5692fbab..ba60ca7ecdbf 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -429,7 +429,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } -static int rtw_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +static int rtw_ops_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, unsigned int link_id) { struct rtw_dev *rtwdev = hw->priv; struct rtw_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 5afb8fe5708e..0e3c95cf4c99 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -381,7 +381,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } -static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +static int rtw89_ops_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, unsigned int link_id) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; @@ -401,7 +402,8 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif } static -void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 97a631ff1bfa..3ae93573f787 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -378,7 +378,8 @@ static void wfx_set_mfp_ap(struct wfx_vif *wvif) } } -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; struct wfx_dev *wdev = wvif->wdev; @@ -396,7 +397,8 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return ret; } -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index 3109d257fe94..93ea992de1d7 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -29,8 +29,10 @@ void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1bc9d1d9769a..48c688fdf23d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4084,8 +4084,10 @@ struct ieee80211_ops { struct ieee80211_vif *vif, unsigned int link_id, u64 changed); - int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); - void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); + void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); u64 (*prepare_multicast)(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f1ee73d96dfb..009f1723c990 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1287,7 +1287,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP; } - err = drv_start_ap(sdata->local, sdata); + err = drv_start_ap(sdata->local, sdata, link_id); if (err) { old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1442,7 +1442,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, GFP_KERNEL); } - drv_stop_ap(sdata->local, sdata); + drv_stop_ap(sdata->local, sdata, link_id); /* free all potentially still buffered bcast frames */ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 52be89f8f0bc..db38c8cc9d8f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -985,7 +985,8 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, int n_vifs, enum ieee80211_chanctx_switch_mode mode); static inline int drv_start_ap(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { int ret = 0; @@ -994,22 +995,24 @@ static inline int drv_start_ap(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); + trace_drv_start_ap(local, sdata, sdata->vif.link_conf[link_id], + link_id); if (local->ops->start_ap) - ret = local->ops->start_ap(&local->hw, &sdata->vif); + ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id); trace_drv_return_int(local, ret); return ret; } static inline void drv_stop_ap(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { if (!check_sdata_in_driver(sdata)) return; - trace_drv_stop_ap(local, sdata); + trace_drv_stop_ap(local, sdata, link_id); if (local->ops->stop_ap) - local->ops->stop_ap(&local->hw, &sdata->vif); + local->ops->stop_ap(&local->hw, &sdata->vif, link_id); trace_drv_return_void(local); } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 9804634e7d99..f96e7cdca4c2 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1752,13 +1752,15 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TRACE_EVENT(drv_start_ap, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info), + struct ieee80211_bss_conf *info, + unsigned int link_id), - TP_ARGS(local, sdata, info), + TP_ARGS(local, sdata, info, link_id), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY + __field(u32, link_id) __field(u8, dtimper) __field(u16, bcnint) __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) @@ -1768,6 +1770,7 @@ TRACE_EVENT(drv_start_ap, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; + __entry->link_id = link_id; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; memcpy(__get_dynamic_array(ssid), @@ -1777,15 +1780,34 @@ TRACE_EVENT(drv_start_ap, ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG + LOCAL_PR_FMT VIF_PR_FMT " link id %u", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id ) ); -DEFINE_EVENT(local_sdata_evt, drv_stop_ap, +TRACE_EVENT(drv_stop_ap, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata), - TP_ARGS(local, sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id), + + TP_ARGS(local, sdata, link_id), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u32, link_id) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->link_id = link_id; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " link id %u", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id + ) ); TRACE_EVENT(drv_reconfig_complete, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ecda655e7481..bccc3a309ed0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2568,7 +2568,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) changed |= BSS_CHANGED_AP_PROBE_RESP; if (rcu_access_pointer(sdata->deflink.u.ap.beacon)) - drv_start_ap(local, sdata); + drv_start_ap(local, sdata, 0); } fallthrough; case NL80211_IFTYPE_MESH_POINT: -- cgit v1.2.3 From 6e8912a503759bb8f1f01c5b761d0d45815fa6de Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 6 Jun 2022 14:25:54 +0300 Subject: wifi: mac80211: return a beacon for a specific link Pass the link id through to the get_beacon and return the beacon for a specific link id. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/ath/carl9170/tx.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 2 +- drivers/net/wireless/broadcom/b43/main.c | 2 +- drivers/net/wireless/broadcom/b43legacy/main.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 4 +- drivers/net/wireless/intel/iwlegacy/common.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 +- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intersil/p54/main.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/marvell/libertas_tf/main.c | 4 +- drivers/net/wireless/marvell/mwl8k.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7603/beacon.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 +- .../net/wireless/mediatek/mt76/mt76x02_beacon.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/purelifi/plfxlc/mac.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/pci.c | 2 +- drivers/net/wireless/realtek/rtw88/fw.c | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 3 +- drivers/net/wireless/rsi/rsi_91x_hal.c | 2 +- drivers/net/wireless/silabs/wfx/sta.c | 6 +- drivers/net/wireless/st/cw1200/sta.c | 4 +- drivers/net/wireless/ti/wl1251/main.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 4 +- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 9 +-- drivers/staging/vt6655/rxtx.c | 2 +- drivers/staging/vt6656/rxtx.c | 2 +- include/net/mac80211.h | 14 ++-- net/mac80211/tx.c | 75 +++++++++++++--------- 43 files changed, 109 insertions(+), 88 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4808ed6a6e20..3d111d6447f0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1630,7 +1630,7 @@ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) arvif->vdev_type != WMI_VDEV_TYPE_IBSS) return 0; - bcn = ieee80211_beacon_get_template(hw, vif, &offs); + bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { ath10k_warn(ar, "failed to get beacon template from mac80211\n"); return -EPERM; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index af19cab24c76..074d8ba5072a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3888,7 +3888,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } - bcn = ieee80211_beacon_get(ar->hw, arvif->vif); + bcn = ieee80211_beacon_get(ar->hw, arvif->vif, 0); if (!bcn) { ath10k_warn(ar, "could not get mac80211 beacon\n"); continue; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 96a33b49a52f..17dbc7d9cf29 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1362,7 +1362,7 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; - bcn = ieee80211_beacon_get_template(hw, vif, &offs); + bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { ath11k_warn(ab, "failed to get beacon template from mac80211\n"); return -EPERM; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 66d123f48085..85c982e0a1cd 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1946,7 +1946,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (!skb) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index d41988f8ea3f..ee72faac2f1d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -135,7 +135,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, bf->bf_mpdu = NULL; } - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb == NULL) return NULL; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 468bc934d848..533471e69400 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -215,7 +215,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, } /* Get a new beacon */ - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) { spin_unlock_bh(&priv->beacon_lock); return; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 514f568d9d07..6bb9aa2bfe65 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1628,7 +1628,7 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit) goto out_unlock; skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), - NULL, NULL); + NULL, NULL, 0); if (!skb) { err = -ENOMEM; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 04fb26cb8322..ace8641909bd 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1010,7 +1010,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, NULL, vif->addr, false); skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, - &tim_len); + &tim_len, 0); if (!skb) { wcn36xx_err("failed to alloc beacon skb\n"); goto out; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index e3121a9d0579..6b4188066f0b 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -1832,7 +1832,7 @@ static void b43_update_templates(struct b43_wl *wl) * the TIM field, but that would probably require resizing and * moving of data within the beacon template. * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(wl->hw, wl->vif); + beacon = ieee80211_beacon_get(wl->hw, wl->vif, 0); if (unlikely(!beacon)) return; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 96d5a034c09b..532013184389 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -1241,7 +1241,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) * field, but that would probably require resizing and moving of data * within the beacon template. Simply request a new beacon and let * mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(wl->hw, wl->vif); + beacon = ieee80211_beacon_get(wl->hw, wl->vif, 0); if (unlikely(!beacon)) return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index fd3c131c622c..61d7404aded4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -678,7 +678,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, u16 tim_offset = 0; spin_lock_bh(&wl->lock); - beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); + beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0); brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, info->dtim_period); spin_unlock_bh(&wl->lock); @@ -950,7 +950,7 @@ static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw, spin_lock_bh(&wl->lock); if (wl->wlc->vif) beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif, - &tim_offset, NULL); + &tim_offset, NULL, 0); if (beacon) brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, wl->wlc->vif->bss_conf.dtim_period); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index affad34f70f0..6f007e63f0c2 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5276,7 +5276,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct il_priv *il = hw->priv; unsigned long flags; __le64 timestamp; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index caf452922dbd..a873be109f43 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2003 - 2014, 2018 - 2021 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2018 - 2022 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well @@ -284,7 +284,7 @@ static void iwl_bg_beacon_update(struct work_struct *work) } /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif); + beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif, 0); if (!beacon) { IWL_ERR(priv, "update beacon failed -- keeping old\n"); goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 45e382fe45a2..f80cce37e2c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -183,7 +183,7 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, lockdep_assert_held(&priv->mutex); dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif); + priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif, 0); if (!priv->beacon_skb) return -ENOMEM; return iwlagn_send_beacon_cmd(priv); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 49898fd99594..c0bd697b080a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1233,7 +1233,7 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len) mvm->hw->extra_beacon_tailroom = len; - beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0); if (!beacon) goto out_err; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 65df8cbb57d9..ed586e6d7d64 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1002,7 +1002,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC); - beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0); if (!beacon) return -ENOMEM; diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index cc6769a4fec7..115be1f3f33d 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -139,7 +139,7 @@ static int p54_beacon_update(struct p54_common *priv, struct sk_buff *beacon; int ret; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; ret = p54_beacon_format_ie_tim(beacon); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index be83904c642b..44174a4c2117 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1908,7 +1908,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, vif->type != NL80211_IFTYPE_OCB) return; - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb == NULL) return; info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 21c3e0bdc444..74c4942b9a5a 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -427,7 +427,7 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, switch (priv->vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - beacon = ieee80211_beacon_get(hw, vif); + beacon = ieee80211_beacon_get(hw, vif, 0); if (beacon) { lbtf_beacon_set(priv, beacon); kfree_skb(beacon); @@ -691,7 +691,7 @@ void lbtf_bcn_sent(struct lbtf_private *priv) } } - skb = ieee80211_beacon_get(priv->hw, priv->vif); + skb = ieee80211_beacon_get(priv->hw, priv->vif, 0); if (skb) { lbtf_beacon_set(priv, skb); diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 7eef3a74d124..293bec9bb8dd 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5147,7 +5147,7 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { struct sk_buff *skb; - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb != NULL) { mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); kfree_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c index b5e8308e0cc7..c67fc29bb7c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c @@ -20,7 +20,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!(mdev->beacon_mask & BIT(mvif->idx))) return; - skb = ieee80211_beacon_get(mt76_hw(dev), vif); + skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f58376733c67..3f8f06d9628c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -706,7 +706,7 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(hw, vif, &offs); + skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!skb) return -EINVAL; @@ -1076,7 +1076,7 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index 5d034cec191b..b72510949877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -139,7 +139,7 @@ mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!(dev->mt76.beacon_mask & BIT(mvif->idx))) return; - skb = ieee80211_beacon_get(mt76_hw(dev), vif); + skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 1b3d6634a72e..8c91257ba1c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2086,7 +2086,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!en) goto out; - skb = ieee80211_beacon_get_template(hw, vif, &offs); + skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 64fc400bd981..3b5b475b0875 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1258,7 +1258,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 1fc1682683e1..d3cdffbded69 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -133,7 +133,7 @@ int plfxlc_restore_settings(struct plfxlc_mac *mac) return 0; if (mac->vif) { - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) { /*beacon is hardcoded in firmware */ kfree_skb(beacon); @@ -601,7 +601,7 @@ static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw, /* for ADHOC */ associated = true; if (changes & BSS_CHANGED_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif, 0); if (beacon) { /*beacon is hardcoded in firmware */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index aa6b2f3d2eff..4d06038afd83 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -758,7 +758,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ rt2x00queue_free_skb(intf->beacon); - intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); + intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif, 0); if (!intf->beacon->skb) return -ENOMEM; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index 10e8fdc31879..f66cc9083972 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1300,7 +1300,7 @@ static void rtl8180_beacon_work(struct work_struct *work) goto resched; /* grab a fresh beacon */ - skb = ieee80211_beacon_get(dev, vif); + skb = ieee80211_beacon_get(dev, vif, 0); if (!skb) goto resched; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 8ab65c888baf..edc84f9dc984 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1075,7 +1075,7 @@ static void rtl8187_beacon_work(struct work_struct *work) goto resched; /* grab a fresh beacon */ - skb = ieee80211_beacon_get(dev, vif); + skb = ieee80211_beacon_get(dev, vif, 0); if (!skb) goto resched; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 2f7fd8888d3a..8537cc6d7a89 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1009,7 +1009,7 @@ static void send_beacon_frame(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif, 0); struct rtl_tcb_desc tcb_desc; if (skb) { diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 8e4c15654746..ca79f652fef3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1100,7 +1100,7 @@ static void _rtl_pci_prepare_bcn_tasklet(struct tasklet_struct *t) } /*NB: the beacon data buffer must be 32-bit aligned. */ - pskb = ieee80211_beacon_get(hw, mac->vif); + pskb = ieee80211_beacon_get(hw, mac->vif, 0); if (!pskb) return; hdr = rtl_get_hdr(pskb); diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index c3ae631c2264..4fdab0329695 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -1070,7 +1070,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, switch (rsvd_pkt->type) { case RSVD_BEACON: - skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); + skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0); rsvd_pkt->tim_offset = tim_offset; break; case RSVD_PS_POLL: diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2d9c3157d878..179ec9276e32 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1043,7 +1043,8 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, u16 tim_offset; int bcn_total_len; - skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, NULL); + skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, + NULL, 0); if (!skb_beacon) { rtw89_err(rtwdev, "failed to get beacon skb\n"); return -ENOMEM; diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index d3634ad986ac..40f9a31f9ca7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -443,7 +443,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) return -EINVAL; mac_bcn = ieee80211_beacon_get_tim(adapter->hw, vif, - &tim_offset, NULL); + &tim_offset, NULL, 0); if (!mac_bcn) { rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); return -EINVAL; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 3ae93573f787..0378144795ca 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -339,7 +339,7 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif) struct ieee80211_vif *vif = wvif_to_vif(wvif); struct sk_buff *skb; - skb = ieee80211_beacon_get(wvif->wdev->hw, vif); + skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0); if (!skb) return -ENOMEM; wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, API_RATE_INDEX_B_1MBPS); @@ -356,7 +356,7 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif) static void wfx_set_mfp_ap(struct wfx_vif *wvif) { struct ieee80211_vif *vif = wvif_to_vif(wvif); - struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0); const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset, skb->len - ieoffset); @@ -588,7 +588,7 @@ static int wfx_update_tim(struct wfx_vif *wvif) u8 *tim_ptr; skb = ieee80211_beacon_get_tim(wvif->wdev->hw, vif, &tim_offset, - &tim_length); + &tim_length, 0); if (!skb) return -ENOENT; tim_ptr = skb->data + tim_offset; diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 5fa6878ee109..a3f6942df0c1 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1671,7 +1671,7 @@ static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) pr_debug("[AP] mcast: %s.\n", aid0_bit_set ? "ena" : "dis"); skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_length); + &tim_offset, &tim_length, 0); if (!skb) { if (!__cw1200_flush(priv, true)) wsm_unlock_tx(priv); @@ -2203,7 +2203,7 @@ static int cw1200_upload_beacon(struct cw1200_common *priv) frame.rate = WSM_TRANSMIT_RATE_6; frame.skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_len); + &tim_offset, &tim_len, 0); if (!frame.skb) return -ENOMEM; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 340ab4985fe2..d76558964420 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1186,7 +1186,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); + beacon = ieee80211_beacon_get(hw, vif, 0); if (!beacon) goto out_sleep; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index b476f244a20e..a1923ef52d55 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4039,7 +4039,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, u32 min_rate; int ret; int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif, 0); u16 tmpl_id; if (!beacon) { @@ -5493,7 +5493,7 @@ static const void *wlcore_get_beacon_ie(struct wl1271 *wl, { int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); struct sk_buff *beacon = - ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif)); + ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif), 0); if (!beacon) return NULL; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index b42fedba519d..80b905d49954 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -398,7 +398,7 @@ int zd_restore_settings(struct zd_mac *mac) mac->type == NL80211_IFTYPE_ADHOC || mac->type == NL80211_IFTYPE_AP) { if (mac->vif != NULL) { - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) zd_mac_config_beacon(mac->hw, beacon, false); } @@ -1167,7 +1167,7 @@ static void zd_beacon_done(struct zd_mac *mac) /* * Fetch next beacon so that tim_count is updated. */ - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) zd_mac_config_beacon(mac->hw, beacon, true); @@ -1290,7 +1290,8 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, mac->type == NL80211_IFTYPE_AP) { associated = true; if (changes & BSS_CHANGED_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif, + 0); if (beacon) { zd_chip_disable_hwint(&mac->chip); @@ -1447,7 +1448,7 @@ static void beacon_watchdog_handler(struct work_struct *work) zd_chip_disable_hwint(&mac->chip); - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) { zd_mac_free_cur_beacon(mac); diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 71cbfa607d96..85cd01c463e8 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1435,7 +1435,7 @@ int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 4d29f8ebb393..cd99091c6c28 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -699,7 +699,7 @@ int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 48c688fdf23d..06545ef1d41c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5069,6 +5069,7 @@ struct ieee80211_mutable_offsets { * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @offs: &struct ieee80211_mutable_offsets pointer to struct that will * receive the offsets that may be updated by the driver. + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * If the driver implements beaconing modes, it must use this function to * obtain the beacon template. @@ -5085,7 +5086,8 @@ struct ieee80211_mutable_offsets { struct sk_buff * ieee80211_beacon_get_template(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_mutable_offsets *offs); + struct ieee80211_mutable_offsets *offs, + unsigned int link_id); /** * ieee80211_beacon_get_tim - beacon generation function @@ -5096,6 +5098,7 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, * @tim_length: pointer to variable that will receive the TIM IE length, * (including the ID and length bytes!). * Set to 0 if invalid (in non-AP modes). + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * If the driver implements beaconing modes, it must use this function to * obtain the beacon frame. @@ -5111,21 +5114,24 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, */ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 *tim_offset, u16 *tim_length); + u16 *tim_offset, u16 *tim_length, + unsigned int link_id); /** * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * See ieee80211_beacon_get_tim(). * * Return: See ieee80211_beacon_get_tim(). */ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { - return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL, link_id); } /** diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 17313954c628..c3e14ef20c05 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4689,11 +4689,12 @@ void ieee80211_tx_pending(struct tasklet_struct *t) static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, struct ps_data *ps, struct sk_buff *skb, - bool is_template) + bool is_template, unsigned int link_id) { u8 *pos, *tim; int aid0 = 0; int i, have_bits = 0, n1, n2; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ @@ -4704,7 +4705,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_AID+1); if (!is_template) { if (ps->dtim_count == 0) - ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; + ps->dtim_count = link_conf->dtim_period - 1; else ps->dtim_count--; } @@ -4713,7 +4714,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = ps->dtim_count; - *pos++ = sdata->vif.bss_conf.dtim_period; + *pos++ = link_conf->dtim_period; if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf)) aid0 = 1; @@ -4754,7 +4755,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, struct ps_data *ps, struct sk_buff *skb, - bool is_template) + bool is_template, unsigned int link_id) { struct ieee80211_local *local = sdata->local; @@ -4766,10 +4767,12 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template); + __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, + link_id); } else { spin_lock_bh(&local->tim_lock); - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template); + __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, + link_id); spin_unlock_bh(&local->tim_lock); } @@ -4777,7 +4780,8 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, - struct beacon_data *beacon) + struct beacon_data *beacon, + unsigned int link_id) { u8 *beacon_data, count, max_count = 1; struct probe_resp *resp; @@ -4803,11 +4807,11 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, } rcu_read_lock(); - resp = rcu_dereference(sdata->deflink.u.ap.probe_resp); + resp = rcu_dereference(sdata->link[link_id]->u.ap.probe_resp); bcn_offsets = beacon->cntdwn_counter_offsets; count = beacon->cntdwn_current_counter; - if (sdata->vif.bss_conf.csa_active) + if (sdata->vif.link_conf[link_id]->csa_active) max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; for (i = 0; i < max_count; ++i) { @@ -4948,14 +4952,15 @@ EXPORT_SYMBOL(ieee80211_beacon_cntdwn_is_complete); static int ieee80211_beacon_protect(struct sk_buff *skb, struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { ieee80211_tx_result res; struct ieee80211_tx_data tx; struct sk_buff *check_skb; memset(&tx, 0, sizeof(tx)); - tx.key = rcu_dereference(sdata->deflink.default_beacon_key); + tx.key = rcu_dereference(sdata->link[link_id]->default_beacon_key); if (!tx.key) return 0; tx.local = local; @@ -4979,7 +4984,8 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw, struct beacon_data *beacon, struct sk_buff *skb, struct ieee80211_chanctx_conf *chanctx_conf, - u16 csa_off_base) + u16 csa_off_base, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -5010,7 +5016,7 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw, memset(&txrc, 0, sizeof(txrc)); txrc.hw = hw; txrc.sband = local->hw.wiphy->bands[band]; - txrc.bss_conf = &sdata->vif.bss_conf; + txrc.bss_conf = sdata->vif.link_conf[link_id]; txrc.skb = skb; txrc.reported_rate.idx = -1; if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) @@ -5045,7 +5051,8 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, struct ieee80211_mutable_offsets *offs, bool is_template, struct beacon_data *beacon, - struct ieee80211_chanctx_conf *chanctx_conf) + struct ieee80211_chanctx_conf *chanctx_conf, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -5058,7 +5065,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (!is_template) ieee80211_beacon_update_cntdwn(vif); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } /* headroom, head length, @@ -5074,7 +5081,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); + ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template, link_id); if (offs) { offs->tim_offset = beacon->head_len; @@ -5093,11 +5100,11 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (beacon->tail) skb_put_data(skb, beacon->tail, beacon->tail_len); - if (ieee80211_beacon_protect(skb, local, sdata) < 0) + if (ieee80211_beacon_protect(skb, local, sdata, link_id) < 0) return NULL; ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, - csa_off_base); + csa_off_base, link_id); return skb; } @@ -5105,7 +5112,8 @@ static struct sk_buff * __ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_mutable_offsets *offs, - bool is_template) + bool is_template, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct beacon_data *beacon = NULL; @@ -5116,7 +5124,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_lock(); sdata = vif_to_sdata(vif); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + chanctx_conf = + rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; @@ -5125,12 +5134,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, memset(offs, 0, sizeof(*offs)); if (sdata->vif.type == NL80211_IFTYPE_AP) { - beacon = rcu_dereference(sdata->deflink.u.ap.beacon); + beacon = rcu_dereference(sdata->link[link_id]->u.ap.beacon); if (!beacon) goto out; skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, - beacon, chanctx_conf); + beacon, chanctx_conf, link_id); } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; @@ -5143,7 +5152,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!is_template) __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + @@ -5158,7 +5167,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, IEEE80211_STYPE_BEACON); ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0); + chanctx_conf, 0, link_id); } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -5175,7 +5184,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, */ __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } if (ifmsh->sync_ops) @@ -5190,7 +5199,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); + ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template, + link_id); if (offs) { offs->tim_offset = beacon->head_len; @@ -5199,7 +5209,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, skb_put_data(skb, beacon->tail, beacon->tail_len); ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0); + chanctx_conf, 0, link_id); } else { WARN_ON(1); goto out; @@ -5214,18 +5224,21 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, struct sk_buff * ieee80211_beacon_get_template(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_mutable_offsets *offs) + struct ieee80211_mutable_offsets *offs, + unsigned int link_id) { - return __ieee80211_beacon_get(hw, vif, offs, true); + return __ieee80211_beacon_get(hw, vif, offs, true, link_id); } EXPORT_SYMBOL(ieee80211_beacon_get_template); struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 *tim_offset, u16 *tim_length) + u16 *tim_offset, u16 *tim_length, + unsigned int link_id) { struct ieee80211_mutable_offsets offs = {}; - struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false); + struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false, + link_id); struct sk_buff *copy; int shift; -- cgit v1.2.3 From c71420db653aba30a234d1e4cf86dde376e604fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jun 2022 09:20:45 +0200 Subject: wifi: mac80211: RCU-ify link STA pointers We need to be able to access these in a race-free way under traffic while adding/removing them, so RCU-ify the pointers. This requires passing a link_sta to a lot of functions so we don't have to do the RCU handling everywhere. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- net/mac80211/cfg.c | 12 ++-- net/mac80211/chan.c | 25 +++++--- net/mac80211/eht.c | 13 ++--- net/mac80211/he.c | 17 +++--- net/mac80211/ht.c | 14 ++--- net/mac80211/ibss.c | 5 +- net/mac80211/ieee80211_i.h | 30 +++++----- net/mac80211/iface.c | 3 +- net/mac80211/mesh_plink.c | 8 ++- net/mac80211/mlme.c | 12 ++-- net/mac80211/rate.c | 2 +- net/mac80211/rx.c | 6 +- net/mac80211/sta_info.c | 28 +++++---- net/mac80211/sta_info.h | 5 +- net/mac80211/tdls.c | 5 +- net/mac80211/vht.c | 139 ++++++++++++++++++++++++--------------------- 17 files changed, 180 insertions(+), 146 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 06545ef1d41c..27f24ac0426d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2201,7 +2201,7 @@ struct ieee80211_sta { u16 valid_links; struct ieee80211_link_sta deflink; - struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 009f1723c990..b387f5f4fef0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1771,19 +1771,21 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (params->ht_capa) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - params->ht_capa, sta, 0); + params->ht_capa, + &sta->deflink); /* VHT can override some HT caps such as the A-MSDU max length */ if (params->vht_capa) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - params->vht_capa, sta, 0); + params->vht_capa, + &sta->deflink); if (params->he_capa) ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, (void *)params->he_capa, params->he_capa_len, (void *)params->he_6ghz_capa, - sta, 0); + &sta->deflink); if (params->eht_capa) ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, @@ -1791,13 +1793,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->he_capa_len, params->eht_capa, params->eht_capa_len, - sta, 0); + &sta->deflink); if (params->opmode_notif_used) { /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ - __ieee80211_vht_handle_opmode(sdata, sta, 0, + __ieee80211_vht_handle_opmode(sdata, &sta->deflink, params->opmode_notif, sband->band); } diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4f25660d0eeb..6853b563fb6c 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -207,16 +207,20 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth width = - ieee80211_sta_cap_rx_bw(sta, link_id); + enum ieee80211_sta_rx_bandwidth width; + struct link_sta_info *link_sta; + + link_sta = rcu_dereference(sta->link[link_id]); /* no effect if this STA has no presence on this link */ - if (!sta->sta.link[link_id]) + if (!link_sta) return NL80211_CHAN_WIDTH_20_NOHT; + width = ieee80211_sta_cap_rx_bw(link_sta); + switch (width) { case IEEE80211_STA_RX_BW_20: - if (sta->sta.link[link_id]->ht_cap.ht_supported) + if (link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20; else return NL80211_CHAN_WIDTH_20_NOHT; @@ -416,6 +420,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct link_sta_info *link_sta; if (!link_conf) continue; @@ -423,18 +428,22 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf) continue; - new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta = rcu_dereference(sta->link[link_id]); + if (!link_sta) + continue; + + new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta); /* nothing change */ - if (new_sta_bw == sta->sta.link[link_id]->bandwidth) + if (new_sta_bw == link_sta->pub->bandwidth) continue; /* vif changed to narrow BW and narrow BW for station wasn't * requested or vise versa */ - if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed) + if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed) continue; - sta->sta.link[link_id]->bandwidth = new_sta_bw; + link_sta->pub->bandwidth = new_sta_bw; rate_control_rate_update(local, sband, sta, link_id, IEEE80211_RC_BW_CHANGED); } diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c index de762a803c38..31e20a342f21 100644 --- a/net/mac80211/eht.c +++ b/net/mac80211/eht.c @@ -12,11 +12,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, - u8 eht_cap_len, struct sta_info *sta, - unsigned int link_id) + u8 eht_cap_len, + struct link_sta_info *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = - &sta->sta.link[link_id]->eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; u8 eht_ppe_size = 0; u8 mcs_nss_size; @@ -73,8 +72,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, eht_cap->has_eht = true; - sta->link[link_id]->cur_max_bandwidth = - ieee80211_sta_cap_rx_bw(sta, link_id); - sta->sta.link[link_id]->bandwidth = - ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); } diff --git a/net/mac80211/he.c b/net/mac80211/he.c index e48e9a021622..d9228fd3f77a 100644 --- a/net/mac80211/he.c +++ b/net/mac80211/he.c @@ -10,8 +10,9 @@ static void ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { + struct sta_info *sta = link_sta->sta; enum ieee80211_smps_mode smps_mode; if (sta->sdata->vif.type == NL80211_IFTYPE_AP || @@ -49,7 +50,7 @@ ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_ break; } - sta->sta.link[link_id]->he_6ghz_capa = *he_6ghz_capa; + link_sta->pub->he_6ghz_capa = *he_6ghz_capa; } static void ieee80211_he_mcs_disable(__le16 *he_mcs) @@ -108,9 +109,9 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { - struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; struct ieee80211_sta_he_cap own_he_cap; struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; u8 he_ppe_size; @@ -153,13 +154,11 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, he_cap->has_he = true; - sta->link[link_id]->cur_max_bandwidth = - ieee80211_sta_cap_rx_bw(sta, link_id); - sta->sta.link[link_id]->bandwidth = - ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa) - ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta, link_id); + ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta); ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80, &he_cap->he_mcs_nss_supp.rx_mcs_80, diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 111828b559a0..2eb3a409b70f 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -138,8 +138,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_ht_cap *ht_cap_ie, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { + struct sta_info *sta = link_sta->sta; struct ieee80211_sta_ht_cap ht_cap, own_cap; u8 ampdu_info, tx_mcs_set_cap; int i, max_tx_streams; @@ -243,12 +244,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839; apply: - changed = memcmp(&sta->sta.link[link_id]->ht_cap, - &ht_cap, sizeof(ht_cap)); + changed = memcmp(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap)); - memcpy(&sta->sta.link[link_id]->ht_cap, &ht_cap, sizeof(ht_cap)); + memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap)); - switch (sdata->vif.link_conf[link_id]->chandef.width) { + switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) { default: WARN_ON_ONCE(1); fallthrough; @@ -265,9 +265,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, break; } - sta->sta.link[link_id]->bandwidth = bw; + link_sta->pub->bandwidth = bw; - sta->link[link_id]->cur_max_bandwidth = + link_sta->cur_max_bandwidth = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 65a3808dc92a..65b6255c6747 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1051,7 +1051,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, &htcap_ie, - sta, 0); + &sta->deflink); if (elems->vht_operation && elems->vht_cap_elem && sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 && @@ -1068,7 +1068,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, &chandef); memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - &cap_ie, sta, 0); + &cap_ie, + &sta->deflink); if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) rates_updated |= true; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index aa5e4c2734b7..46f4e89825a0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2061,7 +2061,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_ht_cap *ht_cap_ie, - struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, u16 initiator, u16 reason_code); @@ -2117,31 +2117,31 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta, unsigned int link_id); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, - unsigned int link_id); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, - unsigned int link_id); -void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta); +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta); +void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, - unsigned int link_id); +enum nl80211_chan_width +ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta); void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, unsigned int link_id, struct ieee80211_mgmt *mgmt); u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *sta, u8 opmode, enum nl80211_band band); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *sta, u8 opmode, enum nl80211_band band); void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_vht_cap *vht_cap); void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, u16 vht_mask[NL80211_VHT_NSS_MAX]); enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id); +ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *sta); /* HE */ void @@ -2149,7 +2149,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); void ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif, const struct ieee80211_he_spr *he_spr_ie_elem); @@ -2560,6 +2560,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, - u8 eht_cap_len, struct sta_info *sta, - unsigned int link_id); + u8 eht_cap_len, + struct link_sta_info *link_sta); #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f118e7710fb1..0cf5a395d925 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1525,7 +1525,8 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) - ieee80211_vht_handle_opmode(sdata, sta, 0, + ieee80211_vht_handle_opmode(sdata, + &sta->deflink, opmode, band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fe54ac431202..55bed9ce98fe 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -438,16 +438,18 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, sta->sta.deflink.supp_rates[sband->band] = rates; if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - elems->ht_cap_elem, sta, 0)) + elems->ht_cap_elem, + &sta->deflink)) changed |= IEEE80211_RC_BW_CHANGED; ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta, 0); + elems->vht_cap_elem, + &sta->deflink); ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, - sta, 0); + &sta->deflink); if (bw != sta->sta.deflink.bandwidth) changed |= IEEE80211_RC_BW_CHANGED; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c2c997086553..01a72d1fcfcc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3566,12 +3566,13 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, /* Set up internal HT/VHT capabilities */ if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - elems->ht_cap_elem, sta, 0); + elems->ht_cap_elem, + &sta->deflink); if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, elems->vht_cap_elem, - sta, 0); + &sta->deflink); if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && elems->he_cap) { @@ -3579,7 +3580,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, - sta, 0); + &sta->deflink); bss_conf->he_support = sta->sta.deflink.he_cap.has_he; if (elems->rsnx && elems->rsnx_len && @@ -3599,7 +3600,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, elems->he_cap_len, elems->eht_cap, elems->eht_cap_len, - sta, 0); + &sta->deflink); bss_conf->eht_support = sta->sta.deflink.eht_cap.has_eht; } else { @@ -4378,7 +4379,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (sta && elems->opmode_notif) - ieee80211_vht_handle_opmode(sdata, sta, 0, + ieee80211_vht_handle_opmode(sdata, + &sta->deflink, *elems->opmode_notif, rx_status->band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c58d9689f51f..7947e9a162a9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; - ieee80211_sta_set_rx_nss(sta, 0); + ieee80211_sta_set_rx_nss(&sta->deflink); if (!ref) return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0b5c34d00c14..d017ad14d7db 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3391,11 +3391,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) max_bw = IEEE80211_STA_RX_BW_20; else - max_bw = ieee80211_sta_cap_rx_bw(rx->sta, 0); + max_bw = ieee80211_sta_cap_rx_bw(&rx->sta->deflink); /* set cur_max_bandwidth and recalc sta bw */ rx->sta->deflink.cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->sta, 0); + new_bw = ieee80211_sta_cur_vht_bw(&rx->sta->deflink); if (rx->sta->sta.deflink.bandwidth == new_bw) goto handled; @@ -3403,7 +3403,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) rx->sta->sta.deflink.bandwidth = new_bw; sband = rx->local->hw.wiphy->bands[status->band]; sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->sta, 0); + ieee80211_sta_rx_bw_to_chan_width(&rx->sta->deflink); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; rate_control_rate_update(local, sband, rx->sta, 0, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index b1426a2459e8..1f4189e08675 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -67,6 +67,7 @@ struct sta_link_alloc { struct link_sta_info info; struct ieee80211_link_sta sta; + struct rcu_head rcu_head; }; static const struct rhashtable_params sta_rht_params = { @@ -258,19 +259,23 @@ static void sta_info_free_link(struct link_sta_info *link_sta) static void sta_remove_link(struct sta_info *sta, unsigned int link_id) { struct sta_link_alloc *alloc = NULL; + struct link_sta_info *link_sta; - if (WARN_ON(!sta->link[link_id])) + link_sta = rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&sta->local->sta_mtx)); + + if (WARN_ON(!link_sta)) return; - if (sta->link[link_id] != &sta->deflink) - alloc = container_of(sta->link[link_id], typeof(*alloc), info); + if (link_sta != &sta->deflink) + alloc = container_of(link_sta, typeof(*alloc), info); sta->sta.valid_links &= ~BIT(link_id); - sta->link[link_id] = NULL; - sta->sta.link[link_id] = NULL; + RCU_INIT_POINTER(sta->link[link_id], NULL); + RCU_INIT_POINTER(sta->sta.link[link_id], NULL); if (alloc) { sta_info_free_link(&alloc->info); - kfree(alloc); + kfree_rcu(alloc, rcu_head); } } @@ -404,8 +409,9 @@ static void sta_info_add_link(struct sta_info *sta, { link_info->sta = sta; link_info->link_id = link_id; - sta->link[link_id] = link_info; - sta->sta.link[link_id] = link_sta; + link_info->pub = link_sta; + rcu_assign_pointer(sta->link[link_id], link_info); + rcu_assign_pointer(sta->sta.link[link_id], link_sta); } struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, @@ -2682,13 +2688,15 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct link_sta_info *link_sta; u16 old_links = sta->sta.valid_links; u16 new_links = old_links | BIT(link_id); int ret; - lockdep_assert_held(&sdata->local->sta_mtx); + link_sta = rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&sdata->local->sta_mtx)); - if (WARN_ON(old_links == new_links || !sta->link[link_id])) + if (WARN_ON(old_links == new_links || !link_sta)) return -EINVAL; sta->sta.valid_links = new_links; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 8ec65bb7d13e..27c96c04b13f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -516,6 +516,7 @@ struct ieee80211_fragment_cache { * @status_stats.last_ack_signal: last ACK signal * @status_stats.ack_signal_filled: last ACK signal validity * @status_stats.avg_ack_signal: average ACK signal + * @pub: public (driver visible) link STA data * TODO Move other link params from sta_info as required for MLD operation */ struct link_sta_info { @@ -561,6 +562,8 @@ struct link_sta_info { } tx_stats; enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; + + struct ieee80211_link_sta *pub; }; /** @@ -708,7 +711,7 @@ struct sta_info { struct ieee80211_fragment_cache frags; struct link_sta_info deflink; - struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct link_sta_info __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* keep last! */ struct ieee80211_sta sta; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4fc120c64022..c531fa17f426 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -308,7 +308,8 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, /* IEEE802.11ac-2013 Table E-4 */ u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; struct cfg80211_chan_def uc = sta->tdls_chandef; - enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta, 0); + enum nl80211_chan_width max_width = + ieee80211_sta_cap_chan_bw(&sta->deflink); int i; /* only support upgrading non-narrow channels up to 80Mhz */ @@ -1268,7 +1269,7 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, enum ieee80211_sta_rx_bandwidth bw; bw = ieee80211_chan_width_to_rx_bw(conf->def.width); - bw = min(bw, ieee80211_sta_cap_rx_bw(sta, 0)); + bw = min(bw, ieee80211_sta_cap_rx_bw(&sta->deflink)); if (bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = bw; rate_control_rate_update(local, sband, sta, 0, diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index acfe1459535f..fa14627b499a 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -116,16 +116,16 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; struct ieee80211_sta_vht_cap own_cap; u32 cap_info, i; bool have_80mhz; memset(vht_cap, 0, sizeof(*vht_cap)); - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return; if (!vht_cap_ie || !sband->vht_cap.vht_supported) @@ -162,7 +162,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * our own capabilities and then use those below. */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) + !test_sta_flag(link_sta->sta, WLAN_STA_TDLS_PEER)) ieee80211_apply_vhtcap_overrides(sdata, &own_cap); /* take some capabilities as-is */ @@ -286,8 +286,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, */ if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) { vht_cap->vht_supported = false; - sdata_info(sdata, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n", - sta->addr); + sdata_info(sdata, + "Ignoring VHT IE from %pM (link:%pM) due to invalid rx_mcs_map\n", + link_sta->sta->addr, link_sta->addr); return; } @@ -295,10 +296,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; default: - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; if (!(vht_cap->vht_mcs.tx_highest & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) @@ -310,35 +311,40 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * above) between 160 and 80+80 yet. */ if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) - sta->link[link_id]->cur_max_bandwidth = + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; } - sta->sta.link[link_id]->bandwidth = ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); + /* + * FIXME - should the amsdu len be per link? store per link + * and maintain a minimum? + */ switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454; break; case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991; break; case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895: default: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895; break; } } /* FIXME: move this to some better location - parses HE/EHT now */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, - unsigned int link_id) +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta) { - struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; - struct ieee80211_link_sta *link_sta = sta->sta.link[link_id]; - struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; - struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; - struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; + unsigned int link_id = link_sta->link_id; + struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; u32 cap_width; if (he_cap->has_he) { @@ -371,7 +377,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, } if (!vht_cap->vht_supported) - return link_sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; @@ -392,17 +398,17 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, return IEEE80211_STA_RX_BW_80; } -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, - unsigned int link_id) +enum nl80211_chan_width +ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; u32 cap_width; if (!vht_cap->vht_supported) { - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; - return sta->sta.link[link_id]->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20; } @@ -417,17 +423,17 @@ enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, } enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id) +ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *link_sta) { enum ieee80211_sta_rx_bandwidth cur_bw = - sta->sta.link[link_id]->bandwidth; + link_sta->pub->bandwidth; struct ieee80211_sta_vht_cap *vht_cap = - &sta->sta.link[link_id]->vht_cap; + &link_sta->pub->vht_cap; u32 cap_width; switch (cur_bw) { case IEEE80211_STA_RX_BW_20: - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; else return NL80211_CHAN_WIDTH_20; @@ -471,15 +477,17 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width) } /* FIXME: rename/move - this deals with everything not just VHT */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, - unsigned int link_id) +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta) { - struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + struct sta_info *sta = link_sta->sta; + struct ieee80211_bss_conf *link_conf = + sta->sdata->vif.link_conf[link_sta->link_id]; enum nl80211_chan_width bss_width = link_conf->chandef.width; enum ieee80211_sta_rx_bandwidth bw; - bw = ieee80211_sta_cap_rx_bw(sta, link_id); - bw = min(bw, sta->link[link_id]->cur_max_bandwidth); + bw = ieee80211_sta_cap_rx_bw(link_sta); + bw = min(bw, link_sta->cur_max_bandwidth); /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of * IEEE80211-2016 specification makes higher bandwidth operation @@ -501,18 +509,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, return bw; } -void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) +void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta) { u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss; bool support_160; /* if we received a notification already don't overwrite it */ - if (sta->sta.link[link_id]->rx_nss) + if (link_sta->pub->rx_nss) return; - if (sta->sta.link[link_id]->eht_cap.has_eht) { + if (link_sta->pub->eht_cap.has_eht) { int i; - const u8 *rx_nss_mcs = (void *)&sta->sta.link[link_id]->eht_cap.eht_mcs_nss_supp; + const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp; /* get the max nss for EHT over all possible bandwidths and mcs */ for (i = 0; i < sizeof(struct ieee80211_eht_mcs_nss_supp); i++) @@ -521,10 +529,10 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) IEEE80211_EHT_MCS_NSS_RX)); } - if (sta->sta.link[link_id]->he_cap.has_he) { + if (link_sta->pub->he_cap.has_he) { int i; u8 rx_mcs_80 = 0, rx_mcs_160 = 0; - const struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; + const struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; u16 mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); @@ -555,23 +563,23 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) he_rx_nss = rx_mcs_80; } - if (sta->sta.link[link_id]->ht_cap.ht_supported) { - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[0]) + if (link_sta->pub->ht_cap.ht_supported) { + if (link_sta->pub->ht_cap.mcs.rx_mask[0]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[1]) + if (link_sta->pub->ht_cap.mcs.rx_mask[1]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[2]) + if (link_sta->pub->ht_cap.mcs.rx_mask[2]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[3]) + if (link_sta->pub->ht_cap.mcs.rx_mask[3]) ht_rx_nss++; /* FIXME: consider rx_highest? */ } - if (sta->sta.link[link_id]->vht_cap.vht_supported) { + if (link_sta->pub->vht_cap.vht_supported) { int i; u16 rx_mcs_map; - rx_mcs_map = le16_to_cpu(sta->sta.link[link_id]->vht_cap.vht_mcs.rx_mcs_map); + rx_mcs_map = le16_to_cpu(link_sta->pub->vht_cap.vht_mcs.rx_mcs_map); for (i = 7; i >= 0; i--) { u8 mcs = (rx_mcs_map >> (2 * i)) & 3; @@ -587,11 +595,11 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); rx_nss = max(eht_rx_nss, rx_nss); - sta->sta.link[link_id]->rx_nss = max_t(u8, 1, rx_nss); + link_sta->pub->rx_nss = max_t(u8, 1, rx_nss); } u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *link_sta, u8 opmode, enum nl80211_band band) { enum ieee80211_sta_rx_bandwidth new_bw; @@ -607,8 +615,8 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; nss += 1; - if (sta->sta.link[link_id]->rx_nss != nss) { - sta->sta.link[link_id]->rx_nss = nss; + if (link_sta->pub->rx_nss != nss) { + link_sta->pub->rx_nss = nss; sta_opmode.rx_nss = nss; changed |= IEEE80211_RC_NSS_CHANGED; sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; @@ -617,34 +625,34 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80) - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; else - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: /* legacy only, no longer used by newer spec */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; } - new_bw = ieee80211_sta_cur_vht_bw(sta, link_id); - if (new_bw != sta->sta.link[link_id]->bandwidth) { - sta->sta.link[link_id]->bandwidth = new_bw; - sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta, link_id); + new_bw = ieee80211_sta_cur_vht_bw(link_sta); + if (new_bw != link_sta->pub->bandwidth) { + link_sta->pub->bandwidth = new_bw; + sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(link_sta); changed |= IEEE80211_RC_BW_CHANGED; sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED; } if (sta_opmode.changed) - cfg80211_sta_opmode_change_notify(sdata->dev, sta->addr, + cfg80211_sta_opmode_change_notify(sdata->dev, link_sta->addr, &sta_opmode, GFP_KERNEL); return changed; @@ -689,18 +697,19 @@ void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *link_sta, u8 opmode, enum nl80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; - u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, link_id, + u32 changed = __ieee80211_vht_handle_opmode(sdata, link_sta, opmode, band); if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, link_id, changed); + rate_control_rate_update(local, sband, link_sta->sta, + link_sta->link_id, changed); } } -- cgit v1.2.3 From efbabc11650040c64884ff3019b88c7bcc0ceb1d Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Wed, 8 Jun 2022 14:46:37 +0530 Subject: cfg80211: Indicate MLO connection info in connect and roam callbacks The MLO links used for connection with an MLD AP are decided by the driver in case of SME offloaded to driver. Add support for the drivers to indicate the information of links used for MLO connection in connect and roam callbacks, update the connected links information in wdev from connect/roam result sent by driver. Also, send the connected links information to userspace. Add a netlink flag attribute to indicate that userspace supports handling of MLO connection. Drivers must not do MLO connection when this flag is not set. This is to maintain backwards compatibility with older supplicant versions which doesn't have support for MLO connection. Signed-off-by: Veerendranath Jakkam Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 4 +- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 6 +- drivers/net/wireless/rndis_wlan.c | 5 +- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 4 +- drivers/staging/wlan-ng/cfg80211.c | 2 +- include/net/cfg80211.h | 84 +++-- include/uapi/linux/nl80211.h | 6 + net/wireless/mlme.c | 4 +- net/wireless/nl80211.c | 120 ++++++- net/wireless/sme.c | 391 +++++++++++++++------ 11 files changed, 480 insertions(+), 148 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 33ed54738d47..e11c7e9accc0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -807,7 +807,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, cfg80211_put_bss(ar->wiphy, bss); } else if (vif->sme_state == SME_CONNECTED) { struct cfg80211_roam_info roam_info = { - .bss = bss, + .links[0].bss = bss, .req_ie = assoc_req_ie, .req_ie_len = assoc_req_len, .resp_ie = assoc_resp_ie, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 98b4c189eecc..ea7bd403e706 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1822,8 +1822,8 @@ wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len) freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ); memset(&info, 0, sizeof(info)); - info.channel = ieee80211_get_channel(wiphy, freq); - info.bss = vif->bss; + info.links[0].channel = ieee80211_get_channel(wiphy, freq); + info.links[0].bss = vif->bss; info.req_ie = assoc_req_ie; info.req_ie_len = assoc_req_ie_len; info.resp_ie = assoc_resp_ie; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 11e1f07f83e0..3ae6779fe153 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6017,8 +6017,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, done: kfree(buf); - roam_info.channel = notify_channel; - roam_info.bssid = profile->bssid; + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = profile->bssid; roam_info.req_ie = conn_info->req_ie; roam_info.req_ie_len = conn_info->req_ie_len; roam_info.resp_ie = conn_info->resp_ie; @@ -6061,7 +6061,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, } else { conn_params.status = WLAN_STATUS_AUTH_TIMEOUT; } - conn_params.bssid = profile->bssid; + conn_params.links[0].bssid = profile->bssid; conn_params.req_ie = conn_info->req_ie; conn_params.req_ie_len = conn_info->req_ie_len; conn_params.resp_ie = conn_info->resp_ie; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ff2448394a1e..05524291d60c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2813,8 +2813,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) resp_ie_len, 0, GFP_KERNEL); } else { struct cfg80211_roam_info roam_info = { - .channel = get_current_channel(usbdev, NULL), - .bssid = bssid, + .links[0].channel = + get_current_channel(usbdev, NULL), + .links[0].bssid = bssid, .req_ie = req_ie, .req_ie_len = req_ie_len, .resp_ie = resp_ie, diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 349aa3c4b668..cf35125b7891 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -450,8 +450,8 @@ check_bss: notify_channel = ieee80211_get_channel(wiphy, freq); - roam_info.channel = notify_channel; - roam_info.bssid = cur_network->network.mac_address; + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = cur_network->network.mac_address; roam_info.req_ie = pmlmepriv->assoc_req+sizeof(struct ieee80211_hdr_3addr)+2; roam_info.req_ie_len = diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 87379edce9a8..b7b56d8406d1 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -645,7 +645,7 @@ void prism2_disconnected(struct wlandevice *wlandev) void prism2_roamed(struct wlandevice *wlandev) { struct cfg80211_roam_info roam_info = { - .bssid = wlandev->bssid, + .links[0].bssid = wlandev->bssid, }; cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5706f96b819a..996782c44838 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2763,6 +2763,9 @@ struct cfg80211_assoc_link { * request (connect callback). * @ASSOC_REQ_DISABLE_HE: Disable HE * @ASSOC_REQ_DISABLE_EHT: Disable EHT + * @CONNECT_REQ_MLO_SUPPORT: Userspace indicates support for handling MLD links. + * Drivers shall disable MLO features for the current association if this + * flag is not set. */ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HT = BIT(0), @@ -2771,6 +2774,7 @@ enum cfg80211_assoc_req_flags { CONNECT_REQ_EXTERNAL_AUTH_SUPPORT = BIT(3), ASSOC_REQ_DISABLE_HE = BIT(4), ASSOC_REQ_DISABLE_EHT = BIT(5), + CONNECT_REQ_MLO_SUPPORT = BIT(6), }; /** @@ -5780,12 +5784,13 @@ static inline void WARN_INVALID_LINK_ID(struct wireless_dev *wdev, !(wdev->valid_links & BIT(link_id))); } -#define for_each_valid_link(wdev, link_id) \ - for (link_id = 0; \ - link_id < ((wdev)->valid_links ? ARRAY_SIZE((wdev)->links) : 1); \ - link_id++) \ - if (!(wdev)->valid_links || \ - ((wdev)->valid_links & BIT(link_id))) +#define for_each_valid_link(link_info, link_id) \ + for (link_id = 0; \ + link_id < ((link_info)->valid_links ? \ + ARRAY_SIZE((link_info)->links) : 1); \ + link_id++) \ + if (!(link_info)->valid_links || \ + ((link_info)->valid_links & BIT(link_id))) /** * DOC: Utility functions @@ -7296,13 +7301,6 @@ struct cfg80211_fils_resp_params { * indicate that this is a failure, but without a status code. * @timeout_reason is used to report the reason for the timeout in that * case. - * @bssid: The BSSID of the AP (may be %NULL) - * @bss: Entry of bss to which STA got connected to, can be obtained through - * cfg80211_get_bss() (may be %NULL). But it is recommended to store the - * bss from the connect_request and hold a reference to it and return - * through this param to avoid a warning if the bss is expired during the - * connection, esp. for those drivers implementing connect op. - * Only one parameter among @bssid and @bss needs to be specified. * @req_ie: Association request IEs (may be %NULL) * @req_ie_len: Association request IEs length * @resp_ie: Association response IEs (may be %NULL) @@ -7314,17 +7312,41 @@ struct cfg80211_fils_resp_params { * not known. This value is used only if @status < 0 to indicate that the * failure is due to a timeout and not due to explicit rejection by the AP. * This value is ignored in other cases (@status >= 0). + * @valid_links: For MLO connection, BIT mask of the valid link ids. Otherwise + * zero. + * @ap_mld_addr: For MLO connection, MLD address of the AP. Otherwise %NULL. + * @links : For MLO connection, contains link info for the valid links indicated + * using @valid_links. For non-MLO connection, links[0] contains the + * connected AP info. + * @links.addr: For MLO connection, MAC address of the STA link. Otherwise + * %NULL. + * @links.bssid: For MLO connection, MAC address of the AP link. For non-MLO + * connection, links[0].bssid points to the BSSID of the AP (may be %NULL). + * @links.bss: For MLO connection, entry of bss to which STA link is connected. + * For non-MLO connection, links[0].bss points to entry of bss to which STA + * is connected. It can be obtained through cfg80211_get_bss() (may be + * %NULL). It is recommended to store the bss from the connect_request and + * hold a reference to it and return through this param to avoid a warning + * if the bss is expired during the connection, esp. for those drivers + * implementing connect op. Only one parameter among @bssid and @bss needs + * to be specified. */ struct cfg80211_connect_resp_params { int status; - const u8 *bssid; - struct cfg80211_bss *bss; const u8 *req_ie; size_t req_ie_len; const u8 *resp_ie; size_t resp_ie_len; struct cfg80211_fils_resp_params fils; enum nl80211_timeout_reason timeout_reason; + + const u8 *ap_mld_addr; + u16 valid_links; + struct { + const u8 *addr; + const u8 *bssid; + struct cfg80211_bss *bss; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; }; /** @@ -7394,8 +7416,8 @@ cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, memset(¶ms, 0, sizeof(params)); params.status = status; - params.bssid = bssid; - params.bss = bss; + params.links[0].bssid = bssid; + params.links[0].bss = bss; params.req_ie = req_ie; params.req_ie_len = req_ie_len; params.resp_ie = resp_ie; @@ -7466,24 +7488,40 @@ cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid, /** * struct cfg80211_roam_info - driver initiated roaming information * - * @channel: the channel of the new AP - * @bss: entry of bss to which STA got roamed (may be %NULL if %bssid is set) - * @bssid: the BSSID of the new AP (may be %NULL if %bss is set) * @req_ie: association request IEs (maybe be %NULL) * @req_ie_len: association request IEs length * @resp_ie: association response IEs (may be %NULL) * @resp_ie_len: assoc response IEs length * @fils: FILS related roaming information. + * @valid_links: For MLO roaming, BIT mask of the new valid links is set. + * Otherwise zero. + * @ap_mld_addr: For MLO roaming, MLD address of the new AP. Otherwise %NULL. + * @links : For MLO roaming, contains new link info for the valid links set in + * @valid_links. For non-MLO roaming, links[0] contains the new AP info. + * @links.addr: For MLO roaming, MAC address of the STA link. Otherwise %NULL. + * @links.bssid: For MLO roaming, MAC address of the new AP link. For non-MLO + * roaming, links[0].bssid points to the BSSID of the new AP. May be + * %NULL if %links.bss is set. + * @links.channel: the channel of the new AP. + * @links.bss: For MLO roaming, entry of new bss to which STA link got + * roamed. For non-MLO roaming, links[0].bss points to entry of bss to + * which STA got roamed (may be %NULL if %links.bssid is set) */ struct cfg80211_roam_info { - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; - const u8 *bssid; const u8 *req_ie; size_t req_ie_len; const u8 *resp_ie; size_t resp_ie_len; struct cfg80211_fils_resp_params fils; + + const u8 *ap_mld_addr; + u16 valid_links; + struct { + const u8 *addr; + const u8 *bssid; + struct ieee80211_channel *channel; + struct cfg80211_bss *bss; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 60ad9a9f153d..89f64f46b98d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2690,6 +2690,10 @@ enum nl80211_commands { * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as * authenticate/associate. * + * @NL80211_ATTR_MLO_SUPPORT: Flag attribute to indicate user space supports MLO + * connection. Used with %NL80211_CMD_CONNECT. If this attribute is not + * included in NL80211_CMD_CONNECT drivers must not perform MLO connection. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3208,6 +3212,8 @@ enum nl80211_attrs { NL80211_ATTR_MLO_LINK_ID, NL80211_ATTR_MLD_ADDR, + NL80211_ATTR_MLO_SUPPORT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d92eed0e52cd..8a84cf77667c 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -42,8 +42,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, memset(&cr, 0, sizeof(cr)); cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); - cr.bssid = mgmt->bssid; - cr.bss = bss; + cr.links[0].bssid = mgmt->bssid; + cr.links[0].bss = bss; cr.req_ie = req_ies; cr.req_ie_len = req_ies_len; cr.resp_ie = resp_ie; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aca799b9971e..6a45801c783c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -797,6 +797,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MLO_LINK_ID] = NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), + [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -11529,6 +11530,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT; } + if (nla_get_flag(info->attrs[NL80211_ATTR_MLO_SUPPORT])) + connect.flags |= CONNECT_REQ_MLO_SUPPORT; + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, @@ -17304,10 +17308,29 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; void *hdr; + unsigned int link; + size_t link_info_size = 0; + const u8 *connected_addr = cr->valid_links ? + cr->ap_mld_addr : cr->links[0].bssid; + + if (cr->valid_links) { + for_each_valid_link(cr, link) { + /* Nested attribute header */ + link_info_size += NLA_HDRLEN; + /* Link ID */ + link_info_size += nla_total_size(sizeof(u8)); + link_info_size += cr->links[link].addr ? + nla_total_size(ETH_ALEN) : 0; + link_info_size += (cr->links[link].bssid || + cr->links[link].bss) ? + nla_total_size(ETH_ALEN) : 0; + } + } msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len + cr->fils.kek_len + cr->fils.pmk_len + - (cr->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (cr->fils.pmkid ? WLAN_PMKID_LEN : 0) + link_info_size, + gfp); if (!msg) return; @@ -17319,8 +17342,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - (cr->bssid && - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) || + (connected_addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr)) || nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : cr->status) || @@ -17346,6 +17369,38 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid))))) goto nla_put_failure; + if (cr->valid_links) { + int i = 1; + struct nlattr *nested; + + nested = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!nested) + goto nla_put_failure; + + for_each_valid_link(cr, link) { + struct nlattr *nested_mlo_links; + const u8 *bssid = cr->links[link].bss ? + cr->links[link].bss->bssid : + cr->links[link].bssid; + + nested_mlo_links = nla_nest_start(msg, i); + if (!nested_mlo_links) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link) || + (bssid && + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid)) || + (cr->links[link].addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + cr->links[link].addr))) + goto nla_put_failure; + + nla_nest_end(msg, nested_mlo_links); + i++; + } + nla_nest_end(msg, nested); + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, @@ -17362,11 +17417,32 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; void *hdr; - const u8 *bssid = info->bss ? info->bss->bssid : info->bssid; + size_t link_info_size = 0; + unsigned int link; + const u8 *connected_addr = info->ap_mld_addr ? + info->ap_mld_addr : + (info->links[0].bss ? + info->links[0].bss->bssid : + info->links[0].bssid); + + if (info->valid_links) { + for_each_valid_link(info, link) { + /* Nested attribute header */ + link_info_size += NLA_HDRLEN; + /* Link ID */ + link_info_size += nla_total_size(sizeof(u8)); + link_info_size += info->links[link].addr ? + nla_total_size(ETH_ALEN) : 0; + link_info_size += (info->links[link].bssid || + info->links[link].bss) ? + nla_total_size(ETH_ALEN) : 0; + } + } msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len + info->fils.kek_len + info->fils.pmk_len + - (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (info->fils.pmkid ? WLAN_PMKID_LEN : 0) + + link_info_size, gfp); if (!msg) return; @@ -17378,7 +17454,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) || (info->req_ie && nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len, info->req_ie)) || @@ -17397,6 +17473,38 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, info->fils.pmkid))) goto nla_put_failure; + if (info->valid_links) { + int i = 1; + struct nlattr *nested; + + nested = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!nested) + goto nla_put_failure; + + for_each_valid_link(info, link) { + struct nlattr *nested_mlo_links; + const u8 *bssid = info->links[link].bss ? + info->links[link].bss->bssid : + info->links[link].bssid; + + nested_mlo_links = nla_nest_start(msg, i); + if (!nested_mlo_links) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link) || + (bssid && + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid)) || + (info->links[link].addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + info->links[link].addr))) + goto nla_put_failure; + + nla_nest_end(msg, nested_mlo_links); + i++; + } + nla_nest_end(msg, nested); + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index b3c6ce4f85ee..00be498aab2e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -275,7 +275,7 @@ void cfg80211_conn_work(struct work_struct *work) memset(&cr, 0, sizeof(cr)); cr.status = -1; - cr.bssid = bssid; + cr.links[0].bssid = bssid; cr.timeout_reason = treason; __cfg80211_connect_result(wdev->netdev, &cr, false); } @@ -384,7 +384,7 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) memset(&cr, 0, sizeof(cr)); cr.status = status_code; - cr.bssid = mgmt->bssid; + cr.links[0].bssid = mgmt->bssid; cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; __cfg80211_connect_result(wdev->netdev, &cr, false); } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { @@ -698,6 +698,20 @@ static void disconnect_work(struct work_struct *work) DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); +static void +cfg80211_connect_result_release_bsses(struct wireless_dev *wdev, + struct cfg80211_connect_resp_params *cr) +{ + unsigned int link; + + for_each_valid_link(cr, link) { + if (!cr->links[link].bss) + continue; + cfg80211_unhold_bss(bss_from_pub(cr->links[link].bss)); + cfg80211_put_bss(wdev->wiphy, cr->links[link].bss); + } +} + /* * API calls for drivers implementing connect/disconnect and * SME event handling @@ -715,21 +729,33 @@ void __cfg80211_connect_result(struct net_device *dev, #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif + unsigned int link; + const u8 *connected_addr; + bool bss_not_found = false; ASSERT_WDEV_LOCK(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && - wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) { - cfg80211_put_bss(wdev->wiphy, cr->bss); - return; + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + goto out; + + if (cr->valid_links) { + if (WARN_ON(!cr->ap_mld_addr)) + goto out; + + for_each_valid_link(cr, link) { + if (WARN_ON(!cr->links[link].addr)) + goto out; + } } wdev->unprot_beacon_reported = 0; nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr, GFP_KERNEL); + connected_addr = cr->valid_links ? cr->ap_mld_addr : cr->links[0].bssid; #ifdef CONFIG_CFG80211_WEXT - if (wextev) { + if (wextev && !cr->valid_links) { if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = cr->req_ie_len; @@ -746,23 +772,38 @@ void __cfg80211_connect_result(struct net_device *dev, memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) { - memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN); - memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN); + if (connected_addr && cr->status == WLAN_STATUS_SUCCESS) { + memcpy(wrqu.ap_addr.sa_data, connected_addr, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, connected_addr, ETH_ALEN); wdev->wext.prev_bssid_valid = true; } wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } #endif - if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { - WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); - cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, - wdev->u.client.ssid, wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); - if (cr->bss) - cfg80211_hold_bss(bss_from_pub(cr->bss)); + if (cr->status == WLAN_STATUS_SUCCESS) { + for_each_valid_link(cr, link) { + if (WARN_ON_ONCE(!cr->links[link].bss)) + break; + } + + for_each_valid_link(cr, link) { + if (cr->links[link].bss) + continue; + + cr->links[link].bss = + cfg80211_get_bss(wdev->wiphy, NULL, + cr->links[link].bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + if (!cr->links[link].bss) { + bss_not_found = true; + break; + } + cfg80211_hold_bss(bss_from_pub(cr->links[link].bss)); + } } cfg80211_wdev_release_bsses(wdev); @@ -772,26 +813,40 @@ void __cfg80211_connect_result(struct net_device *dev, wdev->connect_keys = NULL; wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; - if (cr->bss) { - cfg80211_unhold_bss(bss_from_pub(cr->bss)); - cfg80211_put_bss(wdev->wiphy, cr->bss); - } + cfg80211_connect_result_release_bsses(wdev, cr); cfg80211_sme_free(wdev); return; } - if (WARN_ON(!cr->bss)) + if (WARN_ON(bss_not_found)) { + cfg80211_connect_result_release_bsses(wdev, cr); return; + } - wdev->links[0].client.current_bss = bss_from_pub(cr->bss); + memset(wdev->links, 0, sizeof(wdev->links)); + wdev->valid_links = cr->valid_links; + for_each_valid_link(cr, link) + wdev->links[link].client.current_bss = + bss_from_pub(cr->links[link].bss); wdev->connected = true; - ether_addr_copy(wdev->u.client.connected_addr, cr->bss->bssid); + ether_addr_copy(wdev->u.client.connected_addr, connected_addr); + if (cr->valid_links) { + for_each_valid_link(cr, link) + memcpy(wdev->links[link].addr, cr->links[link].addr, + ETH_ALEN); + } if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); rcu_read_lock(); - country_elem = ieee80211_bss_get_elem(cr->bss, WLAN_EID_COUNTRY); + for_each_valid_link(cr, link) { + country_elem = + ieee80211_bss_get_elem(cr->links[link].bss, + WLAN_EID_COUNTRY); + if (country_elem) + break; + } if (!country_elem) { rcu_read_unlock(); return; @@ -804,12 +859,60 @@ void __cfg80211_connect_result(struct net_device *dev, if (!country_data) return; - regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band, + regulatory_hint_country_ie(wdev->wiphy, + cr->links[link].bss->channel->band, country_data, country_datalen); kfree(country_data); + + return; +out: + for_each_valid_link(cr, link) + cfg80211_put_bss(wdev->wiphy, cr->links[link].bss); } -/* Consumes bss object one way or another */ +static void cfg80211_update_link_bss(struct wireless_dev *wdev, + struct cfg80211_bss **bss) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct cfg80211_internal_bss *ibss; + + if (!*bss) + return; + + ibss = bss_from_pub(*bss); + if (list_empty(&ibss->list)) { + struct cfg80211_bss *found = NULL, *tmp = *bss; + + found = cfg80211_get_bss(wdev->wiphy, NULL, + (*bss)->bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + if (found) { + /* The same BSS is already updated so use it + * instead, as it has latest info. + */ + *bss = found; + } else { + /* Update with BSS provided by driver, it will + * be freshly added and ref cnted, we can free + * the old one. + * + * signal_valid can be false, as we are not + * expecting the BSS to be found. + * + * keep the old timestamp to avoid confusion + */ + cfg80211_bss_update(rdev, ibss, false, + ibss->ts); + } + + cfg80211_put_bss(wdev->wiphy, tmp); + } +} + +/* Consumes bss object(s) one way or another */ void cfg80211_connect_done(struct net_device *dev, struct cfg80211_connect_resp_params *params, gfp_t gfp) @@ -819,55 +922,34 @@ void cfg80211_connect_done(struct net_device *dev, struct cfg80211_event *ev; unsigned long flags; u8 *next; + size_t link_info_size = 0; + unsigned int link; - if (params->bss) { - struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss); - - if (list_empty(&ibss->list)) { - struct cfg80211_bss *found = NULL, *tmp = params->bss; - - found = cfg80211_get_bss(wdev->wiphy, NULL, - params->bss->bssid, - wdev->u.client.ssid, wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); - if (found) { - /* The same BSS is already updated so use it - * instead, as it has latest info. - */ - params->bss = found; - } else { - /* Update with BSS provided by driver, it will - * be freshly added and ref cnted, we can free - * the old one. - * - * signal_valid can be false, as we are not - * expecting the BSS to be found. - * - * keep the old timestamp to avoid confusion - */ - cfg80211_bss_update(rdev, ibss, false, - ibss->ts); - } - - cfg80211_put_bss(wdev->wiphy, tmp); - } + for_each_valid_link(params, link) { + cfg80211_update_link_bss(wdev, ¶ms->links[link].bss); + link_info_size += params->links[link].bssid ? ETH_ALEN : 0; + link_info_size += params->links[link].addr ? ETH_ALEN : 0; } - ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) + + ev = kzalloc(sizeof(*ev) + (params->ap_mld_addr ? ETH_ALEN : 0) + params->req_ie_len + params->resp_ie_len + params->fils.kek_len + params->fils.pmk_len + - (params->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (params->fils.pmkid ? WLAN_PMKID_LEN : 0) + link_info_size, + gfp); + if (!ev) { - cfg80211_put_bss(wdev->wiphy, params->bss); + for_each_valid_link(params, link) + cfg80211_put_bss(wdev->wiphy, + params->links[link].bss); return; } ev->type = EVENT_CONNECT_RESULT; next = ((u8 *)ev) + sizeof(*ev); - if (params->bssid) { - ev->cr.bssid = next; - memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN); + if (params->ap_mld_addr) { + ev->cr.ap_mld_addr = next; + memcpy((void *)ev->cr.ap_mld_addr, params->ap_mld_addr, + ETH_ALEN); next += ETH_ALEN; } if (params->req_ie_len) { @@ -907,9 +989,28 @@ void cfg80211_connect_done(struct net_device *dev, ev->cr.fils.update_erp_next_seq_num = params->fils.update_erp_next_seq_num; if (params->fils.update_erp_next_seq_num) ev->cr.fils.erp_next_seq_num = params->fils.erp_next_seq_num; - if (params->bss) - cfg80211_hold_bss(bss_from_pub(params->bss)); - ev->cr.bss = params->bss; + ev->cr.valid_links = params->valid_links; + for_each_valid_link(params, link) { + if (params->links[link].bss) + cfg80211_hold_bss( + bss_from_pub(params->links[link].bss)); + ev->cr.links[link].bss = params->links[link].bss; + + if (params->links[link].addr) { + ev->cr.links[link].addr = next; + memcpy((void *)ev->cr.links[link].addr, + params->links[link].addr, + ETH_ALEN); + next += ETH_ALEN; + } + if (params->links[link].bssid) { + ev->cr.links[link].bssid = next; + memcpy((void *)ev->cr.links[link].bssid, + params->links[link].bssid, + ETH_ALEN); + next += ETH_ALEN; + } + } ev->cr.status = params->status; ev->cr.timeout_reason = params->timeout_reason; @@ -927,6 +1028,9 @@ void __cfg80211_roamed(struct wireless_dev *wdev, #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif + unsigned int link; + const u8 *connected_addr; + ASSERT_WDEV_LOCK(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && @@ -936,48 +1040,76 @@ void __cfg80211_roamed(struct wireless_dev *wdev, if (WARN_ON(!wdev->connected)) goto out; + if (info->valid_links) { + if (WARN_ON(!info->ap_mld_addr)) + goto out; + + for_each_valid_link(info, link) { + if (WARN_ON(!info->links[link].addr)) + goto out; + } + } + cfg80211_wdev_release_bsses(wdev); - if (WARN_ON(!info->bss)) - return; + for_each_valid_link(info, link) { + if (WARN_ON(!info->links[link].bss)) + goto out; + } - cfg80211_hold_bss(bss_from_pub(info->bss)); - wdev->links[0].client.current_bss = bss_from_pub(info->bss); - ether_addr_copy(wdev->u.client.connected_addr, info->bss->bssid); + memset(wdev->links, 0, sizeof(wdev->links)); + wdev->valid_links = info->valid_links; + for_each_valid_link(info, link) { + cfg80211_hold_bss(bss_from_pub(info->links[link].bss)); + wdev->links[link].client.current_bss = + bss_from_pub(info->links[link].bss); + } + connected_addr = info->valid_links ? + info->ap_mld_addr : + info->links[0].bss->bssid; + ether_addr_copy(wdev->u.client.connected_addr, connected_addr); + if (info->valid_links) { + for_each_valid_link(info, link) + memcpy(wdev->links[link].addr, info->links[link].addr, + ETH_ALEN); + } wdev->unprot_beacon_reported = 0; nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), wdev->netdev, info, GFP_KERNEL); #ifdef CONFIG_CFG80211_WEXT - if (info->req_ie) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = info->req_ie_len; - wireless_send_event(wdev->netdev, IWEVASSOCREQIE, - &wrqu, info->req_ie); - } + if (!info->valid_links) { + if (info->req_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = info->req_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCREQIE, + &wrqu, info->req_ie); + } + + if (info->resp_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = info->resp_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + &wrqu, info->resp_ie); + } - if (info->resp_ie) { memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = info->resp_ie_len; - wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, - &wrqu, info->resp_ie); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.ap_addr.sa_data, connected_addr, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, connected_addr, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; + wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN); - memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN); - wdev->wext.prev_bssid_valid = true; - wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); #endif return; out: - cfg80211_put_bss(wdev->wiphy, info->bss); + for_each_valid_link(info, link) + cfg80211_put_bss(wdev->wiphy, info->links[link].bss); } -/* Consumes info->bss object one way or another */ +/* Consumes info->links.bss object(s) one way or another */ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, gfp_t gfp) { @@ -986,25 +1118,41 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, struct cfg80211_event *ev; unsigned long flags; u8 *next; + unsigned int link; + size_t link_info_size = 0; + bool bss_not_found = false; + + for_each_valid_link(info, link) { + link_info_size += info->links[link].addr ? ETH_ALEN : 0; + link_info_size += info->links[link].bssid ? ETH_ALEN : 0; - if (!info->bss) { - info->bss = cfg80211_get_bss(wdev->wiphy, info->channel, - info->bssid, wdev->u.client.ssid, - wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); + if (info->links[link].bss) + continue; + + info->links[link].bss = + cfg80211_get_bss(wdev->wiphy, + info->links[link].channel, + info->links[link].bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + + if (!info->links[link].bss) { + bss_not_found = true; + break; + } } - if (WARN_ON(!info->bss)) - return; + if (WARN_ON(bss_not_found)) + goto out; ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len + info->fils.kek_len + info->fils.pmk_len + - (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); - if (!ev) { - cfg80211_put_bss(wdev->wiphy, info->bss); - return; - } + (info->fils.pmkid ? WLAN_PMKID_LEN : 0) + + (info->ap_mld_addr ? ETH_ALEN : 0) + link_info_size, gfp); + if (!ev) + goto out; ev->type = EVENT_ROAMED; next = ((u8 *)ev) + sizeof(*ev); @@ -1044,12 +1192,43 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, ev->rm.fils.update_erp_next_seq_num = info->fils.update_erp_next_seq_num; if (info->fils.update_erp_next_seq_num) ev->rm.fils.erp_next_seq_num = info->fils.erp_next_seq_num; - ev->rm.bss = info->bss; + if (info->ap_mld_addr) { + ev->rm.ap_mld_addr = next; + memcpy((void *)ev->rm.ap_mld_addr, info->ap_mld_addr, + ETH_ALEN); + next += ETH_ALEN; + } + ev->rm.valid_links = info->valid_links; + for_each_valid_link(info, link) { + ev->rm.links[link].bss = info->links[link].bss; + + if (info->links[link].addr) { + ev->rm.links[link].addr = next; + memcpy((void *)ev->rm.links[link].addr, + info->links[link].addr, + ETH_ALEN); + next += ETH_ALEN; + } + + if (info->links[link].bssid) { + ev->rm.links[link].bssid = next; + memcpy((void *)ev->rm.links[link].bssid, + info->links[link].bssid, + ETH_ALEN); + next += ETH_ALEN; + } + } spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); queue_work(cfg80211_wq, &rdev->event_work); + + return; +out: + for_each_valid_link(info, link) + cfg80211_put_bss(wdev->wiphy, info->links[link].bss); + } EXPORT_SYMBOL(cfg80211_roamed); -- cgit v1.2.3 From 04919bed948dc22a0032a9da867b7dcb8aece4ca Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 15 Jun 2022 09:20:11 -0700 Subject: tcp: Introduce tcp_read_skb() This patch inroduces tcp_read_skb() based on tcp_read_sock(), a preparation for the next patch which actually introduces a new sock ops. TCP is special here, because it has tcp_read_sock() which is mainly used by splice(). tcp_read_sock() supports partial read and arbitrary offset, neither of them is needed for sockmap. Signed-off-by: Cong Wang Signed-off-by: Daniel Borkmann Reviewed-by: Eric Dumazet Reviewed-by: John Fastabend Link: https://lore.kernel.org/bpf/20220615162014.89193-2-xiyou.wangcong@gmail.com --- include/net/tcp.h | 2 ++ net/ipv4/tcp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) (limited to 'include/net') diff --git a/include/net/tcp.h b/include/net/tcp.h index c21a9b516f1e..7547d90fbb57 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -672,6 +672,8 @@ void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); +int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); void tcp_initialize_rcv_mss(struct sock *sk); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f7309452bdce..124f384f8695 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1734,6 +1734,53 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, } EXPORT_SYMBOL(tcp_read_sock); +int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor) +{ + struct tcp_sock *tp = tcp_sk(sk); + u32 seq = tp->copied_seq; + struct sk_buff *skb; + int copied = 0; + u32 offset; + + if (sk->sk_state == TCP_LISTEN) + return -ENOTCONN; + + while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { + int used; + + __skb_unlink(skb, &sk->sk_receive_queue); + used = recv_actor(desc, skb, 0, skb->len); + if (used <= 0) { + if (!copied) + copied = used; + break; + } + seq += used; + copied += used; + + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { + consume_skb(skb); + ++seq; + break; + } + consume_skb(skb); + if (!desc->count) + break; + WRITE_ONCE(tp->copied_seq, seq); + } + WRITE_ONCE(tp->copied_seq, seq); + + tcp_rcv_space_adjust(sk); + + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) + tcp_cleanup_rbuf(sk, copied); + + return copied; +} +EXPORT_SYMBOL(tcp_read_skb); + int tcp_peek_len(struct socket *sock) { return tcp_inq(sock->sk); -- cgit v1.2.3 From 965b57b469a589d64d81b1688b38dcb537011bb0 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 15 Jun 2022 09:20:12 -0700 Subject: net: Introduce a new proto_ops ->read_skb() Currently both splice() and sockmap use ->read_sock() to read skb from receive queue, but for sockmap we only read one entire skb at a time, so ->read_sock() is too conservative to use. Introduce a new proto_ops ->read_skb() which supports this sematic, with this we can finally pass the ownership of skb to recv actors. For non-TCP protocols, all ->read_sock() can be simply converted to ->read_skb(). Signed-off-by: Cong Wang Signed-off-by: Daniel Borkmann Reviewed-by: John Fastabend Link: https://lore.kernel.org/bpf/20220615162014.89193-3-xiyou.wangcong@gmail.com --- include/linux/net.h | 4 ++++ include/net/tcp.h | 3 +-- include/net/udp.h | 3 +-- net/core/skmsg.c | 20 +++++--------------- net/ipv4/af_inet.c | 3 ++- net/ipv4/tcp.c | 9 +++------ net/ipv4/udp.c | 10 ++++------ net/ipv6/af_inet6.c | 3 ++- net/unix/af_unix.c | 23 +++++++++-------------- 9 files changed, 31 insertions(+), 47 deletions(-) (limited to 'include/net') diff --git a/include/linux/net.h b/include/linux/net.h index 12093f4db50c..a03485e8cbb2 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -152,6 +152,8 @@ struct module; struct sk_buff; typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t); +typedef int (*skb_read_actor_t)(struct sock *, struct sk_buff *); + struct proto_ops { int family; @@ -214,6 +216,8 @@ struct proto_ops { */ int (*read_sock)(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); + /* This is different from read_sock(), it reads an entire skb at a time. */ + int (*read_skb)(struct sock *sk, skb_read_actor_t recv_actor); int (*sendpage_locked)(struct sock *sk, struct page *page, int offset, size_t size, int flags); int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg, diff --git a/include/net/tcp.h b/include/net/tcp.h index 7547d90fbb57..8e48dc56837b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -672,8 +672,7 @@ void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); -int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor); void tcp_initialize_rcv_mss(struct sock *sk); diff --git a/include/net/udp.h b/include/net/udp.h index b60eea2e3fae..987f7fc7c0aa 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -306,8 +306,7 @@ struct sock *__udp6_lib_lookup(struct net *net, struct sk_buff *skb); struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb, __be16 sport, __be16 dport); -int udp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +int udp_read_skb(struct sock *sk, skb_read_actor_t recv_actor); /* UDP uses skb->dev_scratch to cache as much information as possible and avoid * possibly multiple cache miss on dequeue() diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 7e03f96e441b..f7f63b7d990c 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1160,21 +1160,17 @@ static void sk_psock_done_strp(struct sk_psock *psock) } #endif /* CONFIG_BPF_STREAM_PARSER */ -static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb, - unsigned int offset, size_t orig_len) +static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb) { - struct sock *sk = (struct sock *)desc->arg.data; struct sk_psock *psock; struct bpf_prog *prog; int ret = __SK_DROP; - int len = orig_len; + int len = skb->len; /* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */ skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) { - desc->error = -ENOMEM; + if (!skb) return 0; - } rcu_read_lock(); psock = sk_psock(sk); @@ -1204,16 +1200,10 @@ out: static void sk_psock_verdict_data_ready(struct sock *sk) { struct socket *sock = sk->sk_socket; - read_descriptor_t desc; - if (unlikely(!sock || !sock->ops || !sock->ops->read_sock)) + if (unlikely(!sock || !sock->ops || !sock->ops->read_skb)) return; - - desc.arg.data = sk; - desc.error = 0; - desc.count = 1; - - sock->ops->read_sock(sk, &desc, sk_psock_verdict_recv); + sock->ops->read_skb(sk, sk_psock_verdict_recv); } void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index da81f56fdd1c..7abd652a558f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1040,6 +1040,7 @@ const struct proto_ops inet_stream_ops = { .sendpage = inet_sendpage, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, + .read_skb = tcp_read_skb, .sendmsg_locked = tcp_sendmsg_locked, .sendpage_locked = tcp_sendpage_locked, .peek_len = tcp_peek_len, @@ -1067,7 +1068,7 @@ const struct proto_ops inet_dgram_ops = { .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, - .read_sock = udp_read_sock, + .read_skb = udp_read_skb, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .sendpage = inet_sendpage, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 124f384f8695..9d2fd3ced21b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1734,8 +1734,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, } EXPORT_SYMBOL(tcp_read_sock); -int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { struct tcp_sock *tp = tcp_sk(sk); u32 seq = tp->copied_seq; @@ -1750,7 +1749,7 @@ int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, int used; __skb_unlink(skb, &sk->sk_receive_queue); - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -1765,9 +1764,7 @@ int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, break; } consume_skb(skb); - if (!desc->count) - break; - WRITE_ONCE(tp->copied_seq, seq); + break; } WRITE_ONCE(tp->copied_seq, seq); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6172b4750a88..c660b0bc4d14 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1797,8 +1797,7 @@ busy_check: } EXPORT_SYMBOL(__skb_recv_udp); -int udp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +int udp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { int copied = 0; @@ -1820,7 +1819,7 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc, continue; } - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -1831,13 +1830,12 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc, } kfree_skb(skb); - if (!desc->count) - break; + break; } return copied; } -EXPORT_SYMBOL(udp_read_sock); +EXPORT_SYMBOL(udp_read_skb); /* * This should be easy, if there is something there we diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 658823e91eca..0ee0770e79aa 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -702,6 +702,7 @@ const struct proto_ops inet6_stream_ops = { .sendpage_locked = tcp_sendpage_locked, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, + .read_skb = tcp_read_skb, .peek_len = tcp_peek_len, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, @@ -727,7 +728,7 @@ const struct proto_ops inet6_dgram_ops = { .getsockopt = sock_common_getsockopt, /* ok */ .sendmsg = inet6_sendmsg, /* retpoline's sake */ .recvmsg = inet6_recvmsg, /* retpoline's sake */ - .read_sock = udp_read_sock, + .read_skb = udp_read_skb, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, .set_peek_off = sk_set_peek_off, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3453e0053f76..1bed3739768c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -741,10 +741,8 @@ static ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, unsigned int flags); static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); -static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); -static int unix_stream_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor); +static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor); static int unix_dgram_connect(struct socket *, struct sockaddr *, int, int); static int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t); @@ -798,7 +796,7 @@ static const struct proto_ops unix_stream_ops = { .shutdown = unix_shutdown, .sendmsg = unix_stream_sendmsg, .recvmsg = unix_stream_recvmsg, - .read_sock = unix_stream_read_sock, + .read_skb = unix_stream_read_skb, .mmap = sock_no_mmap, .sendpage = unix_stream_sendpage, .splice_read = unix_stream_splice_read, @@ -823,7 +821,7 @@ static const struct proto_ops unix_dgram_ops = { .listen = sock_no_listen, .shutdown = unix_shutdown, .sendmsg = unix_dgram_sendmsg, - .read_sock = unix_read_sock, + .read_skb = unix_read_skb, .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, @@ -2487,8 +2485,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, size_t si return __unix_dgram_recvmsg(sk, msg, size, flags); } -static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { int copied = 0; @@ -2503,7 +2500,7 @@ static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, if (!skb) return err; - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -2514,8 +2511,7 @@ static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, } kfree_skb(skb); - if (!desc->count) - break; + break; } return copied; @@ -2650,13 +2646,12 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, } #endif -static int unix_stream_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { if (unlikely(sk->sk_state != TCP_ESTABLISHED)) return -ENOTCONN; - return unix_read_sock(sk, desc, recv_actor); + return unix_read_skb(sk, recv_actor); } static int unix_stream_read_generic(struct unix_stream_read_state *state, -- cgit v1.2.3 From af185d8c76333daa877678e0166a7b45e63bf3c4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 20 Jun 2022 03:05:09 -0700 Subject: raw: complete rcu conversion raw_diag_dump() can use rcu_read_lock() instead of read_lock() Now the hashinfo lock is only used from process context, in write mode only, we can convert it to a spinlock, and we do not need to block BH anymore. Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20220620100509.3493504-1-eric.dumazet@gmail.com Signed-off-by: Paolo Abeni --- include/net/raw.h | 4 ++-- net/ipv4/raw.c | 8 ++++---- net/ipv4/raw_diag.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/include/net/raw.h b/include/net/raw.h index d81eeeb8f1e6..d224376360e1 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -32,7 +32,7 @@ int raw_rcv(struct sock *, struct sk_buff *); #define RAW_HTABLE_SIZE MAX_INET_PROTOS struct raw_hashinfo { - rwlock_t lock; + spinlock_t lock; struct hlist_nulls_head ht[RAW_HTABLE_SIZE]; }; @@ -40,7 +40,7 @@ static inline void raw_hashinfo_init(struct raw_hashinfo *hashinfo) { int i; - rwlock_init(&hashinfo->lock); + spin_lock_init(&hashinfo->lock); for (i = 0; i < RAW_HTABLE_SIZE; i++) INIT_HLIST_NULLS_HEAD(&hashinfo->ht[i], i); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 959bea12dc48..027389969915 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -95,10 +95,10 @@ int raw_hash_sk(struct sock *sk) hlist = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; - write_lock_bh(&h->lock); + spin_lock(&h->lock); __sk_nulls_add_node_rcu(sk, hlist); sock_set_flag(sk, SOCK_RCU_FREE); - write_unlock_bh(&h->lock); + spin_unlock(&h->lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); return 0; @@ -109,10 +109,10 @@ void raw_unhash_sk(struct sock *sk) { struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; - write_lock_bh(&h->lock); + spin_lock(&h->lock); if (__sk_nulls_del_node_init_rcu(sk)) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&h->lock); + spin_unlock(&h->lock); } EXPORT_SYMBOL_GPL(raw_unhash_sk); diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index ac4b6525d3c6..999321834b94 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -156,7 +156,7 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, s_slot = cb->args[0]; num = s_num = cb->args[1]; - read_lock(&hashinfo->lock); + rcu_read_lock(); for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { num = 0; @@ -184,7 +184,7 @@ next: } out_unlock: - read_unlock(&hashinfo->lock); + rcu_read_unlock(); cb->args[0] = slot; cb->args[1] = num; -- cgit v1.2.3 From f302d180c6d430ea99643b9b2b3407aedaa36703 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 21 Jun 2022 10:19:09 -0700 Subject: af_unix: Include the whole hash table size in UNIX_HASH_SIZE. Currently, the size of AF_UNIX hash table is UNIX_HASH_SIZE * 2, the first half for bind()ed sockets and the second half for unbound ones. UNIX_HASH_SIZE * 2 is used to define the table and iterate over it. In some places, we use ARRAY_SIZE(unix_socket_table) instead of UNIX_HASH_SIZE * 2. However, we cannot use it anymore because we will allocate the hash table dynamically. Then, we would have to add UNIX_HASH_SIZE * 2 in many places, which would be troublesome. This patch adapts the UNIX_HASH_SIZE definition to include bound and unbound sockets and defines a new UNIX_HASH_MOD macro to ease calculations. Signed-off-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/af_unix.h | 7 ++++--- net/unix/af_unix.c | 18 +++++++++--------- net/unix/diag.c | 6 ++---- 3 files changed, 15 insertions(+), 16 deletions(-) (limited to 'include/net') diff --git a/include/net/af_unix.h b/include/net/af_unix.h index a7ef624ed726..acb56e463db1 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -16,12 +16,13 @@ void wait_for_unix_gc(void); struct sock *unix_get_socket(struct file *filp); struct sock *unix_peer_get(struct sock *sk); -#define UNIX_HASH_SIZE 256 +#define UNIX_HASH_MOD (256 - 1) +#define UNIX_HASH_SIZE (256 * 2) #define UNIX_HASH_BITS 8 extern unsigned int unix_tot_inflight; -extern spinlock_t unix_table_locks[2 * UNIX_HASH_SIZE]; -extern struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; +extern spinlock_t unix_table_locks[UNIX_HASH_SIZE]; +extern struct hlist_head unix_socket_table[UNIX_HASH_SIZE]; struct unix_address { refcount_t refcnt; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 990257f02e7c..c0804ae9c96a 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -118,9 +118,9 @@ #include "scm.h" -spinlock_t unix_table_locks[2 * UNIX_HASH_SIZE]; +spinlock_t unix_table_locks[UNIX_HASH_SIZE]; EXPORT_SYMBOL_GPL(unix_table_locks); -struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; +struct hlist_head unix_socket_table[UNIX_HASH_SIZE]; EXPORT_SYMBOL_GPL(unix_socket_table); static atomic_long_t unix_nr_socks; @@ -137,12 +137,12 @@ static unsigned int unix_unbound_hash(struct sock *sk) hash ^= hash >> 8; hash ^= sk->sk_type; - return UNIX_HASH_SIZE + (hash & (UNIX_HASH_SIZE - 1)); + return UNIX_HASH_MOD + 1 + (hash & UNIX_HASH_MOD); } static unsigned int unix_bsd_hash(struct inode *i) { - return i->i_ino & (UNIX_HASH_SIZE - 1); + return i->i_ino & UNIX_HASH_MOD; } static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr, @@ -155,14 +155,14 @@ static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr, hash ^= hash >> 8; hash ^= type; - return hash & (UNIX_HASH_SIZE - 1); + return hash & UNIX_HASH_MOD; } static void unix_table_double_lock(unsigned int hash1, unsigned int hash2) { /* hash1 and hash2 is never the same because - * one is between 0 and UNIX_HASH_SIZE - 1, and - * another is between UNIX_HASH_SIZE and UNIX_HASH_SIZE * 2. + * one is between 0 and UNIX_HASH_MOD, and + * another is between UNIX_HASH_MOD + 1 and UNIX_HASH_SIZE - 1. */ if (hash1 > hash2) swap(hash1, hash2); @@ -3239,7 +3239,7 @@ static struct sock *unix_get_first(struct seq_file *seq, loff_t *pos) unsigned long bucket = get_bucket(*pos); struct sock *sk; - while (bucket < ARRAY_SIZE(unix_socket_table)) { + while (bucket < UNIX_HASH_SIZE) { spin_lock(&unix_table_locks[bucket]); sk = unix_from_bucket(seq, pos); @@ -3666,7 +3666,7 @@ static int __init af_unix_init(void) BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb)); - for (i = 0; i < 2 * UNIX_HASH_SIZE; i++) + for (i = 0; i < UNIX_HASH_SIZE; i++) spin_lock_init(&unix_table_locks[i]); rc = proto_register(&unix_dgram_proto, 1); diff --git a/net/unix/diag.c b/net/unix/diag.c index 4e3dc8179fa4..c5d1cca72aa5 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -204,9 +204,7 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) s_slot = cb->args[0]; num = s_num = cb->args[1]; - for (slot = s_slot; - slot < ARRAY_SIZE(unix_socket_table); - s_num = 0, slot++) { + for (slot = s_slot; slot < UNIX_HASH_SIZE; s_num = 0, slot++) { struct sock *sk; num = 0; @@ -242,7 +240,7 @@ static struct sock *unix_lookup_by_ino(unsigned int ino) struct sock *sk; int i; - for (i = 0; i < ARRAY_SIZE(unix_socket_table); i++) { + for (i = 0; i < UNIX_HASH_SIZE; i++) { spin_lock(&unix_table_locks[i]); sk_for_each(sk, &unix_socket_table[i]) if (ino == sock_i_ino(sk)) { -- cgit v1.2.3 From b6e811383062f88212082714db849127fa95142c Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 21 Jun 2022 10:19:10 -0700 Subject: af_unix: Define a per-netns hash table. This commit adds a per netns hash table for AF_UNIX, which size is fixed as UNIX_HASH_SIZE for now. The first implementation defines a per-netns hash table as a single array of lock and list: struct unix_hashbucket { spinlock_t lock; struct hlist_head head; }; struct netns_unix { struct unix_hashbucket *hash; ... }; But, Eric pointed out memory cost that the structure has holes because of sizeof(spinlock_t), which is 4 (or more if LOCKDEP is enabled). [0] It could be expensive on a host with thousands of netns and few AF_UNIX sockets. For this reason, a per-netns hash table uses two dense arrays. struct unix_table { spinlock_t *locks; struct hlist_head *buckets; }; struct netns_unix { struct unix_table table; ... }; Note the length of the list has a significant impact rather than lock contention, so having shared locks can be an option. But, per-netns locks and lists still perform better than the global locks and per-netns lists. [1] Also, this patch adds a change so that struct netns_unix disappears from struct net if CONFIG_UNIX is disabled. [0]: https://lore.kernel.org/netdev/CANn89iLVxO5aqx16azNU7p7Z-nz5NrnM5QTqOzueVxEnkVTxyg@mail.gmail.com/ [1]: https://lore.kernel.org/netdev/20220617175215.1769-1-kuniyu@amazon.com/ Signed-off-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/net_namespace.h | 2 ++ include/net/netns/unix.h | 6 ++++++ net/unix/af_unix.c | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index c4f5601f6e32..20a2992901c2 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -120,7 +120,9 @@ struct net { struct netns_core core; struct netns_mib mib; struct netns_packet packet; +#if IS_ENABLED(CONFIG_UNIX) struct netns_unix unx; +#endif struct netns_nexthop nexthop; struct netns_ipv4 ipv4; #if IS_ENABLED(CONFIG_IPV6) diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h index 91a3d7e39198..6f1a33df061d 100644 --- a/include/net/netns/unix.h +++ b/include/net/netns/unix.h @@ -5,8 +5,14 @@ #ifndef __NETNS_UNIX_H__ #define __NETNS_UNIX_H__ +struct unix_table { + spinlock_t *locks; + struct hlist_head *buckets; +}; + struct ctl_table_header; struct netns_unix { + struct unix_table table; int sysctl_max_dgram_qlen; struct ctl_table_header *ctl; }; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c0804ae9c96a..cdd12881a39d 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -3559,7 +3559,7 @@ static const struct net_proto_family unix_family_ops = { static int __net_init unix_net_init(struct net *net) { - int error = -ENOMEM; + int i; net->unx.sysctl_max_dgram_qlen = 10; if (unix_sysctl_register(net)) @@ -3567,18 +3567,44 @@ static int __net_init unix_net_init(struct net *net) #ifdef CONFIG_PROC_FS if (!proc_create_net("unix", 0, net->proc_net, &unix_seq_ops, - sizeof(struct seq_net_private))) { - unix_sysctl_unregister(net); - goto out; + sizeof(struct seq_net_private))) + goto err_sysctl; +#endif + + net->unx.table.locks = kvmalloc_array(UNIX_HASH_SIZE, + sizeof(spinlock_t), GFP_KERNEL); + if (!net->unx.table.locks) + goto err_proc; + + net->unx.table.buckets = kvmalloc_array(UNIX_HASH_SIZE, + sizeof(struct hlist_head), + GFP_KERNEL); + if (!net->unx.table.buckets) + goto free_locks; + + for (i = 0; i < UNIX_HASH_SIZE; i++) { + spin_lock_init(&net->unx.table.locks[i]); + INIT_HLIST_HEAD(&net->unx.table.buckets[i]); } + + return 0; + +free_locks: + kvfree(net->unx.table.locks); +err_proc: +#ifdef CONFIG_PROC_FS + remove_proc_entry("unix", net->proc_net); +err_sysctl: #endif - error = 0; + unix_sysctl_unregister(net); out: - return error; + return -ENOMEM; } static void __net_exit unix_net_exit(struct net *net) { + kvfree(net->unx.table.buckets); + kvfree(net->unx.table.locks); unix_sysctl_unregister(net); remove_proc_entry("unix", net->proc_net); } -- cgit v1.2.3 From cf2f225e2653734e66e91c09e1cbe004bfd3d4a7 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 21 Jun 2022 10:19:12 -0700 Subject: af_unix: Put a socket into a per-netns hash table. This commit replaces the global hash table with a per-netns one and removes the global one. We now link a socket in each netns's hash table so we can save some netns comparisons when iterating through a hash bucket. Signed-off-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/af_unix.h | 1 - net/unix/af_unix.c | 50 ++++++++++++++++++++------------------------------ net/unix/diag.c | 9 +++------ 3 files changed, 23 insertions(+), 37 deletions(-) (limited to 'include/net') diff --git a/include/net/af_unix.h b/include/net/af_unix.h index acb56e463db1..b1748c9b6db2 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -22,7 +22,6 @@ struct sock *unix_peer_get(struct sock *sk); extern unsigned int unix_tot_inflight; extern spinlock_t unix_table_locks[UNIX_HASH_SIZE]; -extern struct hlist_head unix_socket_table[UNIX_HASH_SIZE]; struct unix_address { refcount_t refcnt; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 79f8fc5cdce8..9d0b07235dbc 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -120,8 +120,6 @@ spinlock_t unix_table_locks[UNIX_HASH_SIZE]; EXPORT_SYMBOL_GPL(unix_table_locks); -struct hlist_head unix_socket_table[UNIX_HASH_SIZE]; -EXPORT_SYMBOL_GPL(unix_socket_table); static atomic_long_t unix_nr_socks; /* SMP locking strategy: @@ -308,20 +306,20 @@ static void __unix_remove_socket(struct sock *sk) sk_del_node_init(sk); } -static void __unix_insert_socket(struct sock *sk) +static void __unix_insert_socket(struct net *net, struct sock *sk) { DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk)); - sk_add_node(sk, &unix_socket_table[sk->sk_hash]); + sk_add_node(sk, &net->unx.table.buckets[sk->sk_hash]); } -static void __unix_set_addr_hash(struct sock *sk, struct unix_address *addr, - unsigned int hash) +static void __unix_set_addr_hash(struct net *net, struct sock *sk, + struct unix_address *addr, unsigned int hash) { __unix_remove_socket(sk); smp_store_release(&unix_sk(sk)->addr, addr); sk->sk_hash = hash; - __unix_insert_socket(sk); + __unix_insert_socket(net, sk); } static void unix_remove_socket(struct net *net, struct sock *sk) @@ -337,7 +335,7 @@ static void unix_insert_unbound_socket(struct net *net, struct sock *sk) { spin_lock(&unix_table_locks[sk->sk_hash]); spin_lock(&net->unx.table.locks[sk->sk_hash]); - __unix_insert_socket(sk); + __unix_insert_socket(net, sk); spin_unlock(&net->unx.table.locks[sk->sk_hash]); spin_unlock(&unix_table_locks[sk->sk_hash]); } @@ -348,12 +346,9 @@ static struct sock *__unix_find_socket_byname(struct net *net, { struct sock *s; - sk_for_each(s, &unix_socket_table[hash]) { + sk_for_each(s, &net->unx.table.buckets[hash]) { struct unix_sock *u = unix_sk(s); - if (!net_eq(sock_net(s), net)) - continue; - if (u->addr->len == len && !memcmp(u->addr->name, sunname, len)) return s; @@ -384,7 +379,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) spin_lock(&unix_table_locks[hash]); spin_lock(&net->unx.table.locks[hash]); - sk_for_each(s, &unix_socket_table[hash]) { + sk_for_each(s, &net->unx.table.buckets[hash]) { struct dentry *dentry = unix_sk(s)->path.dentry; if (dentry && d_backing_inode(dentry) == i) { @@ -1140,7 +1135,7 @@ retry: goto retry; } - __unix_set_addr_hash(sk, addr, new_hash); + __unix_set_addr_hash(net, sk, addr, new_hash); unix_table_double_unlock(net, old_hash, new_hash); err = 0; @@ -1199,7 +1194,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, unix_table_double_lock(net, old_hash, new_hash); u->path.mnt = mntget(parent.mnt); u->path.dentry = dget(dentry); - __unix_set_addr_hash(sk, addr, new_hash); + __unix_set_addr_hash(net, sk, addr, new_hash); unix_table_double_unlock(net, old_hash, new_hash); mutex_unlock(&u->bindlock); done_path_create(&parent, dentry); @@ -1246,7 +1241,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr, if (__unix_find_socket_byname(net, addr->name, addr->len, new_hash)) goto out_spin; - __unix_set_addr_hash(sk, addr, new_hash); + __unix_set_addr_hash(net, sk, addr, new_hash); unix_table_double_unlock(net, old_hash, new_hash); mutex_unlock(&u->bindlock); return 0; @@ -3239,12 +3234,11 @@ static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos) { unsigned long offset = get_offset(*pos); unsigned long bucket = get_bucket(*pos); - struct sock *sk; unsigned long count = 0; + struct sock *sk; - for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) { - if (sock_net(sk) != seq_file_net(seq)) - continue; + for (sk = sk_head(&seq_file_net(seq)->unx.table.buckets[bucket]); + sk; sk = sk_next(sk)) { if (++count == offset) break; } @@ -3279,13 +3273,13 @@ static struct sock *unix_get_next(struct seq_file *seq, struct sock *sk, loff_t *pos) { unsigned long bucket = get_bucket(*pos); - struct net *net = seq_file_net(seq); - for (sk = sk_next(sk); sk; sk = sk_next(sk)) - if (sock_net(sk) == net) - return sk; + sk = sk_next(sk); + if (sk) + return sk; + - spin_unlock(&net->unx.table.locks[bucket]); + spin_unlock(&seq_file_net(seq)->unx.table.locks[bucket]); spin_unlock(&unix_table_locks[bucket]); *pos = set_bucket_offset(++bucket, 1); @@ -3406,7 +3400,6 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) { struct bpf_unix_iter_state *iter = seq->private; - struct net *net = seq_file_net(seq); unsigned int expected = 1; struct sock *sk; @@ -3414,9 +3407,6 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) iter->batch[iter->end_sk++] = start_sk; for (sk = sk_next(start_sk); sk; sk = sk_next(sk)) { - if (sock_net(sk) != net) - continue; - if (iter->end_sk < iter->max_sk) { sock_hold(sk); iter->batch[iter->end_sk++] = sk; @@ -3425,7 +3415,7 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) expected++; } - spin_unlock(&net->unx.table.locks[start_sk->sk_hash]); + spin_unlock(&seq_file_net(seq)->unx.table.locks[start_sk->sk_hash]); spin_unlock(&unix_table_locks[start_sk->sk_hash]); return expected; diff --git a/net/unix/diag.c b/net/unix/diag.c index 7fc377435114..4d0f0ca6a1eb 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -210,9 +210,7 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) num = 0; spin_lock(&unix_table_locks[slot]); spin_lock(&net->unx.table.locks[slot]); - sk_for_each(sk, &unix_socket_table[slot]) { - if (!net_eq(sock_net(sk), net)) - continue; + sk_for_each(sk, &net->unx.table.buckets[slot]) { if (num < s_num) goto next; if (!(req->udiag_states & (1 << sk->sk_state))) @@ -246,13 +244,14 @@ static struct sock *unix_lookup_by_ino(struct net *net, unsigned int ino) for (i = 0; i < UNIX_HASH_SIZE; i++) { spin_lock(&unix_table_locks[i]); spin_lock(&net->unx.table.locks[i]); - sk_for_each(sk, &unix_socket_table[i]) + sk_for_each(sk, &net->unx.table.buckets[i]) { if (ino == sock_i_ino(sk)) { sock_hold(sk); spin_unlock(&net->unx.table.locks[i]); spin_unlock(&unix_table_locks[i]); return sk; } + } spin_unlock(&net->unx.table.locks[i]); spin_unlock(&unix_table_locks[i]); } @@ -277,8 +276,6 @@ static int unix_diag_get_exact(struct sk_buff *in_skb, err = -ENOENT; if (sk == NULL) goto out_nosk; - if (!net_eq(sock_net(sk), net)) - goto out; err = sock_diag_check_cookie(sk, req->udiag_cookie); if (err) -- cgit v1.2.3 From 2f7ca90a0188b57a54d3b1159eb7874427a7e07a Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 21 Jun 2022 10:19:13 -0700 Subject: af_unix: Remove unix_table_locks. unix_table_locks are to protect the global hash table, unix_socket_table. The previous commit removed it, so let's clean up the unnecessary locks. Here is a test result on EC2 c5.9xlarge where 10 processes run concurrently in different netns and bind 100,000 sockets for each. without this series : 1m 38s with this series : 11s It is ~10x faster because the global hash table is split into 10 netns in this case. Signed-off-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/af_unix.h | 1 - net/unix/af_unix.c | 42 ++++++++---------------------------------- net/unix/diag.c | 8 +------- 3 files changed, 9 insertions(+), 42 deletions(-) (limited to 'include/net') diff --git a/include/net/af_unix.h b/include/net/af_unix.h index b1748c9b6db2..480fa579787e 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -21,7 +21,6 @@ struct sock *unix_peer_get(struct sock *sk); #define UNIX_HASH_BITS 8 extern unsigned int unix_tot_inflight; -extern spinlock_t unix_table_locks[UNIX_HASH_SIZE]; struct unix_address { refcount_t refcnt; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 9d0b07235dbc..49f6626330c3 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -118,13 +118,11 @@ #include "scm.h" -spinlock_t unix_table_locks[UNIX_HASH_SIZE]; -EXPORT_SYMBOL_GPL(unix_table_locks); static atomic_long_t unix_nr_socks; /* SMP locking strategy: - * hash table is protected with spinlock unix_table_locks - * each socket state is protected by separate spin lock. + * hash table is protected with spinlock. + * each socket state is protected by separate spinlock. */ static unsigned int unix_unbound_hash(struct sock *sk) @@ -166,9 +164,6 @@ static void unix_table_double_lock(struct net *net, if (hash1 > hash2) swap(hash1, hash2); - spin_lock(&unix_table_locks[hash1]); - spin_lock_nested(&unix_table_locks[hash2], SINGLE_DEPTH_NESTING); - spin_lock(&net->unx.table.locks[hash1]); spin_lock_nested(&net->unx.table.locks[hash2], SINGLE_DEPTH_NESTING); } @@ -178,9 +173,6 @@ static void unix_table_double_unlock(struct net *net, { spin_unlock(&net->unx.table.locks[hash1]); spin_unlock(&net->unx.table.locks[hash2]); - - spin_unlock(&unix_table_locks[hash1]); - spin_unlock(&unix_table_locks[hash2]); } #ifdef CONFIG_SECURITY_NETWORK @@ -324,20 +316,16 @@ static void __unix_set_addr_hash(struct net *net, struct sock *sk, static void unix_remove_socket(struct net *net, struct sock *sk) { - spin_lock(&unix_table_locks[sk->sk_hash]); spin_lock(&net->unx.table.locks[sk->sk_hash]); __unix_remove_socket(sk); spin_unlock(&net->unx.table.locks[sk->sk_hash]); - spin_unlock(&unix_table_locks[sk->sk_hash]); } static void unix_insert_unbound_socket(struct net *net, struct sock *sk) { - spin_lock(&unix_table_locks[sk->sk_hash]); spin_lock(&net->unx.table.locks[sk->sk_hash]); __unix_insert_socket(net, sk); spin_unlock(&net->unx.table.locks[sk->sk_hash]); - spin_unlock(&unix_table_locks[sk->sk_hash]); } static struct sock *__unix_find_socket_byname(struct net *net, @@ -362,13 +350,11 @@ static inline struct sock *unix_find_socket_byname(struct net *net, { struct sock *s; - spin_lock(&unix_table_locks[hash]); spin_lock(&net->unx.table.locks[hash]); s = __unix_find_socket_byname(net, sunname, len, hash); if (s) sock_hold(s); spin_unlock(&net->unx.table.locks[hash]); - spin_unlock(&unix_table_locks[hash]); return s; } @@ -377,7 +363,6 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) unsigned int hash = unix_bsd_hash(i); struct sock *s; - spin_lock(&unix_table_locks[hash]); spin_lock(&net->unx.table.locks[hash]); sk_for_each(s, &net->unx.table.buckets[hash]) { struct dentry *dentry = unix_sk(s)->path.dentry; @@ -385,12 +370,10 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) if (dentry && d_backing_inode(dentry) == i) { sock_hold(s); spin_unlock(&net->unx.table.locks[hash]); - spin_unlock(&unix_table_locks[hash]); return s; } } spin_unlock(&net->unx.table.locks[hash]); - spin_unlock(&unix_table_locks[hash]); return NULL; } @@ -1551,9 +1534,9 @@ restart: * * The contents of *(otheru->addr) and otheru->path * are seen fully set up here, since we have found - * otheru in hash under unix_table_locks. Insertion - * into the hash chain we'd found it in had been done - * in an earlier critical area protected by unix_table_locks, + * otheru in hash under its lock. Insertion into the + * hash chain we'd found it in had been done in an + * earlier critical area protected by the chain's lock, * the same one where we'd set *(otheru->addr) contents, * as well as otheru->path and otheru->addr itself. * @@ -3253,7 +3236,6 @@ static struct sock *unix_get_first(struct seq_file *seq, loff_t *pos) struct sock *sk; while (bucket < UNIX_HASH_SIZE) { - spin_lock(&unix_table_locks[bucket]); spin_lock(&net->unx.table.locks[bucket]); sk = unix_from_bucket(seq, pos); @@ -3261,7 +3243,6 @@ static struct sock *unix_get_first(struct seq_file *seq, loff_t *pos) return sk; spin_unlock(&net->unx.table.locks[bucket]); - spin_unlock(&unix_table_locks[bucket]); *pos = set_bucket_offset(++bucket, 1); } @@ -3280,7 +3261,6 @@ static struct sock *unix_get_next(struct seq_file *seq, struct sock *sk, spin_unlock(&seq_file_net(seq)->unx.table.locks[bucket]); - spin_unlock(&unix_table_locks[bucket]); *pos = set_bucket_offset(++bucket, 1); @@ -3309,10 +3289,8 @@ static void unix_seq_stop(struct seq_file *seq, void *v) { struct sock *sk = v; - if (sk) { + if (sk) spin_unlock(&seq_file_net(seq)->unx.table.locks[sk->sk_hash]); - spin_unlock(&unix_table_locks[sk->sk_hash]); - } } static int unix_seq_show(struct seq_file *seq, void *v) @@ -3337,7 +3315,7 @@ static int unix_seq_show(struct seq_file *seq, void *v) (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), sock_i_ino(s)); - if (u->addr) { // under unix_table_locks here + if (u->addr) { // under a hash table lock here int i, len; seq_putc(seq, ' '); @@ -3416,7 +3394,6 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) } spin_unlock(&seq_file_net(seq)->unx.table.locks[start_sk->sk_hash]); - spin_unlock(&unix_table_locks[start_sk->sk_hash]); return expected; } @@ -3705,13 +3682,10 @@ static void __init bpf_iter_register(void) static int __init af_unix_init(void) { - int i, rc = -1; + int rc = -1; BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb)); - for (i = 0; i < UNIX_HASH_SIZE; i++) - spin_lock_init(&unix_table_locks[i]); - rc = proto_register(&unix_dgram_proto, 1); if (rc != 0) { pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); diff --git a/net/unix/diag.c b/net/unix/diag.c index 4d0f0ca6a1eb..105f522a89fe 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -13,7 +13,7 @@ static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb) { - /* might or might not have unix_table_locks */ + /* might or might not have a hash table lock */ struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr); if (!addr) @@ -208,7 +208,6 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) struct sock *sk; num = 0; - spin_lock(&unix_table_locks[slot]); spin_lock(&net->unx.table.locks[slot]); sk_for_each(sk, &net->unx.table.buckets[slot]) { if (num < s_num) @@ -220,14 +219,12 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) cb->nlh->nlmsg_seq, NLM_F_MULTI) < 0) { spin_unlock(&net->unx.table.locks[slot]); - spin_unlock(&unix_table_locks[slot]); goto done; } next: num++; } spin_unlock(&net->unx.table.locks[slot]); - spin_unlock(&unix_table_locks[slot]); } done: cb->args[0] = slot; @@ -242,18 +239,15 @@ static struct sock *unix_lookup_by_ino(struct net *net, unsigned int ino) int i; for (i = 0; i < UNIX_HASH_SIZE; i++) { - spin_lock(&unix_table_locks[i]); spin_lock(&net->unx.table.locks[i]); sk_for_each(sk, &net->unx.table.buckets[i]) { if (ino == sock_i_ino(sk)) { sock_hold(sk); spin_unlock(&net->unx.table.locks[i]); - spin_unlock(&unix_table_locks[i]); return sk; } } spin_unlock(&net->unx.table.locks[i]); - spin_unlock(&unix_table_locks[i]); } return NULL; } -- cgit v1.2.3 From f41b284a2c187c299f496f6fa1914ec986bdf0ee Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Wed, 15 Jun 2022 09:55:19 +0800 Subject: xfrm: change the type of xfrm_register_km and xfrm_unregister_km Functions xfrm_register_km and xfrm_unregister_km do always return 0, change the type of functions to void. Signed-off-by: Zhengchao Shao Signed-off-by: Steffen Klassert --- include/net/xfrm.h | 4 ++-- net/key/af_key.c | 6 +----- net/xfrm/xfrm_state.c | 6 ++---- net/xfrm/xfrm_user.c | 6 ++---- 4 files changed, 7 insertions(+), 15 deletions(-) (limited to 'include/net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 9287712ad977..afb5940919f8 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -583,8 +583,8 @@ struct xfrm_mgr { bool (*is_alive)(const struct km_event *c); }; -int xfrm_register_km(struct xfrm_mgr *km); -int xfrm_unregister_km(struct xfrm_mgr *km); +void xfrm_register_km(struct xfrm_mgr *km); +void xfrm_unregister_km(struct xfrm_mgr *km); struct xfrm_tunnel_skb_cb { union { diff --git a/net/key/af_key.c b/net/key/af_key.c index fb16d7c4e1b8..fda2dcc8a383 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3894,14 +3894,10 @@ static int __init ipsec_pfkey_init(void) err = sock_register(&pfkey_family_ops); if (err != 0) goto out_unregister_pernet; - err = xfrm_register_km(&pfkeyv2_mgr); - if (err != 0) - goto out_sock_unregister; + xfrm_register_km(&pfkeyv2_mgr); out: return err; -out_sock_unregister: - sock_unregister(PF_KEY); out_unregister_pernet: unregister_pernet_subsys(&pfkey_net_ops); out_unregister_key_proto: diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 08564e0eef20..03b180878e61 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -2481,22 +2481,20 @@ EXPORT_SYMBOL(xfrm_user_policy); static DEFINE_SPINLOCK(xfrm_km_lock); -int xfrm_register_km(struct xfrm_mgr *km) +void xfrm_register_km(struct xfrm_mgr *km) { spin_lock_bh(&xfrm_km_lock); list_add_tail_rcu(&km->list, &xfrm_km_list); spin_unlock_bh(&xfrm_km_lock); - return 0; } EXPORT_SYMBOL(xfrm_register_km); -int xfrm_unregister_km(struct xfrm_mgr *km) +void xfrm_unregister_km(struct xfrm_mgr *km) { spin_lock_bh(&xfrm_km_lock); list_del_rcu(&km->list); spin_unlock_bh(&xfrm_km_lock); synchronize_rcu(); - return 0; } EXPORT_SYMBOL(xfrm_unregister_km); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6a58fec6a1fb..2ff017117730 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -3633,10 +3633,8 @@ static int __init xfrm_user_init(void) rv = register_pernet_subsys(&xfrm_user_net_ops); if (rv < 0) return rv; - rv = xfrm_register_km(&netlink_mgr); - if (rv < 0) - unregister_pernet_subsys(&xfrm_user_net_ops); - return rv; + xfrm_register_km(&netlink_mgr); + return 0; } static void __exit xfrm_user_exit(void) -- cgit v1.2.3 From f2b3b28ce5237a4995a17d6f6aac9e05243d7a0b Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 21 Jun 2022 15:49:18 +0800 Subject: bonding: add slave_dev field for bond_opt_value Currently, bond_opt_value are mostly used for bonding option settings. If we want to set a value for slave, we need to re-alloc a string to store both slave name and vlaue, like bond_option_queue_id_set() does, which is complex and dumb. As Jon suggested, let's add a union field slave_dev for bond_opt_value, which will be benefit for future slave option setting. In function __bond_opt_init(), we will always check the extra field and set it if it's not NULL. Suggested-by: Jonathan Toppins Signed-off-by: Hangbin Liu Acked-by: Jonathan Toppins Signed-off-by: David S. Miller --- include/net/bond_options.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 1618b76f4903..eade8236a4df 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -83,7 +83,10 @@ struct bond_opt_value { char *string; u64 value; u32 flags; - char extra[BOND_OPT_EXTRA_MAXLEN]; + union { + char extra[BOND_OPT_EXTRA_MAXLEN]; + struct net_device *slave_dev; + }; }; struct bonding; @@ -133,13 +136,16 @@ static inline void __bond_opt_init(struct bond_opt_value *optval, optval->value = value; else if (string) optval->string = string; - else if (extra_len <= BOND_OPT_EXTRA_MAXLEN) + + if (extra && extra_len <= BOND_OPT_EXTRA_MAXLEN) memcpy(optval->extra, extra, extra_len); } #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value, NULL, 0) #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX, NULL, 0) #define bond_opt_initextra(optval, extra, extra_len) \ __bond_opt_init(optval, NULL, ULLONG_MAX, extra, extra_len) +#define bond_opt_slave_initval(optval, slave_dev, value) \ + __bond_opt_init(optval, NULL, value, slave_dev, sizeof(struct net_device *)) void bond_option_arp_ip_targets_clear(struct bonding *bond); #if IS_ENABLED(CONFIG_IPV6) -- cgit v1.2.3 From 0a2ff7cc8ad48a86939a91bd3457f38e59e741a1 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 21 Jun 2022 15:49:19 +0800 Subject: Bonding: add per-port priority for failover re-selection Add per port priority support for bonding active slave re-selection during failover. A higher number means higher priority in selection. The primary slave still has the highest priority. This option also follows the primary_reselect rules. This option could only be configured via netlink. Signed-off-by: Hangbin Liu Acked-by: Jonathan Toppins Signed-off-by: David S. Miller --- Documentation/networking/bonding.rst | 11 +++++++++++ drivers/net/bonding/bond_main.c | 27 +++++++++++++++++++++++++++ drivers/net/bonding/bond_netlink.c | 15 +++++++++++++++ drivers/net/bonding/bond_options.c | 33 +++++++++++++++++++++++++++++++++ include/net/bond_options.h | 1 + include/net/bonding.h | 1 + include/uapi/linux/if_link.h | 1 + tools/include/uapi/linux/if_link.h | 1 + 8 files changed, 90 insertions(+) (limited to 'include/net') diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index 43be3782e5df..53a18ff7cf23 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -780,6 +780,17 @@ peer_notif_delay value is 0 which means to match the value of the link monitor interval. +prio + Slave priority. A higher number means higher priority. + The primary slave has the highest priority. This option also + follows the primary_reselect rules. + + This option could only be configured via netlink, and is only valid + for active-backup(1), balance-tlb (5) and balance-alb (6) mode. + The valid value range is a signed 32 bit integer. + + The default value is 0. + primary A string (eth0, eth2, etc) specifying which slave is the diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index dc3e9a06e1aa..e75acb14d066 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1026,12 +1026,38 @@ out: } +/** + * bond_choose_primary_or_current - select the primary or high priority slave + * @bond: our bonding struct + * + * - Check if there is a primary link. If the primary link was set and is up, + * go on and do link reselection. + * + * - If primary link is not set or down, find the highest priority link. + * If the highest priority link is not current slave, set it as primary + * link and do link reselection. + */ static struct slave *bond_choose_primary_or_current(struct bonding *bond) { struct slave *prim = rtnl_dereference(bond->primary_slave); struct slave *curr = rtnl_dereference(bond->curr_active_slave); + struct slave *slave, *hprio = NULL; + struct list_head *iter; if (!prim || prim->link != BOND_LINK_UP) { + bond_for_each_slave(bond, slave, iter) { + if (slave->link == BOND_LINK_UP) { + hprio = hprio ?: slave; + if (slave->prio > hprio->prio) + hprio = slave; + } + } + + if (hprio && hprio != curr) { + prim = hprio; + goto link_reselect; + } + if (!curr || curr->link != BOND_LINK_UP) return NULL; return curr; @@ -1042,6 +1068,7 @@ static struct slave *bond_choose_primary_or_current(struct bonding *bond) return prim; } +link_reselect: if (!curr || curr->link != BOND_LINK_UP) return prim; diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 5a6f44455b95..c2d080fc4fc4 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -27,6 +27,7 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ 0; } @@ -53,6 +54,9 @@ static int bond_fill_slave_info(struct sk_buff *skb, if (nla_put_u16(skb, IFLA_BOND_SLAVE_QUEUE_ID, slave->queue_id)) goto nla_put_failure; + if (nla_put_s32(skb, IFLA_BOND_SLAVE_PRIO, slave->prio)) + goto nla_put_failure; + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { const struct aggregator *agg; const struct port *ad_port; @@ -117,6 +121,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, + [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[], @@ -157,6 +162,16 @@ static int bond_slave_changelink(struct net_device *bond_dev, return err; } + if (data[IFLA_BOND_SLAVE_PRIO]) { + int prio = nla_get_s32(data[IFLA_BOND_SLAVE_PRIO]); + + bond_opt_slave_initval(&newval, &slave_dev, prio); + err = __bond_opt_set(bond, BOND_OPT_PRIO, &newval, + data[IFLA_BOND_SLAVE_PRIO], extack); + if (err) + return err; + } + return 0; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 96eef19cffc4..3498db1c1b3c 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -40,6 +40,8 @@ static int bond_option_arp_validate_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_arp_all_targets_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); static int bond_option_primary_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_primary_reselect_set(struct bonding *bond, @@ -365,6 +367,16 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_intmax_tbl, .set = bond_option_miimon_set }, + [BOND_OPT_PRIO] = { + .id = BOND_OPT_PRIO, + .name = "prio", + .desc = "Link priority for failover re-selection", + .flags = BOND_OPTFLAG_RAWVAL, + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) | + BIT(BOND_MODE_TLB) | + BIT(BOND_MODE_ALB)), + .set = bond_option_prio_set + }, [BOND_OPT_PRIMARY] = { .id = BOND_OPT_PRIMARY, .name = "primary", @@ -1306,6 +1318,27 @@ static int bond_option_missed_max_set(struct bonding *bond, return 0; } +static int bond_option_prio_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + struct slave *slave; + + slave = bond_slave_get_rtnl(newval->slave_dev); + if (!slave) { + netdev_dbg(newval->slave_dev, "%s called on NULL slave\n", __func__); + return -ENODEV; + } + slave->prio = newval->value; + + if (rtnl_dereference(bond->primary_slave)) + slave_warn(bond->dev, slave->dev, + "prio updated, but will not affect failover re-selection as primary slave have been set\n"); + else + bond_select_active_slave(bond); + + return 0; +} + static int bond_option_primary_set(struct bonding *bond, const struct bond_opt_value *newval) { diff --git a/include/net/bond_options.h b/include/net/bond_options.h index eade8236a4df..d2aea5cf1e41 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -67,6 +67,7 @@ enum { BOND_OPT_LACP_ACTIVE, BOND_OPT_MISSED_MAX, BOND_OPT_NS_TARGETS, + BOND_OPT_PRIO, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index cb904d356e31..6e78d657aa05 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -178,6 +178,7 @@ struct slave { u32 speed; u16 queue_id; u8 perm_hwaddr[MAX_ADDR_LEN]; + int prio; struct ad_slave_info *ad_info; struct tlb_slave_info tlb_info; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 5f58dcfe2787..e36d9d2c65a7 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -963,6 +963,7 @@ enum { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, __IFLA_BOND_SLAVE_MAX, }; diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index b339bf2196ca..0242f31e339c 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -890,6 +890,7 @@ enum { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, __IFLA_BOND_SLAVE_MAX, }; -- cgit v1.2.3 From ede57d58e6f38d5bc66137368e4a1e68a157af6e Mon Sep 17 00:00:00 2001 From: Richard Gobert Date: Wed, 22 Jun 2022 18:09:03 +0200 Subject: net: helper function skb_len_add Move the len fields manipulation in the skbs to a helper function. There is a comment specifically requesting this and there are several other areas in the code displaying the same pattern which can be refactored. This improves code readability. Signed-off-by: Richard Gobert Link: https://lore.kernel.org/r/20220622160853.GA6478@debian Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 12 ++++++++++++ include/net/sock.h | 4 +--- net/core/skbuff.c | 13 +++---------- net/ipv4/esp4.c | 4 +--- net/ipv4/ip_output.c | 8 ++------ 5 files changed, 19 insertions(+), 22 deletions(-) (limited to 'include/net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index cd4a8268894a..f6a27ab19202 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2351,6 +2351,18 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb) return skb_headlen(skb) + __skb_pagelen(skb); } +/** + * skb_len_add - adds a number to len fields of skb + * @skb: buffer to add len to + * @delta: number of bytes to add + */ +static inline void skb_len_add(struct sk_buff *skb, int delta) +{ + skb->len += delta; + skb->data_len += delta; + skb->truesize += delta; +} + /** * __skb_fill_page_desc - initialise a paged fragment in an skb * @skb: buffer containing fragment to be initialised diff --git a/include/net/sock.h b/include/net/sock.h index 5bed1ea7a722..40bbd0e8925b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2219,9 +2219,7 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *fro if (err) return err; - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; + skb_len_add(skb, copy); sk_wmem_queued_add(sk, copy); sk_mem_charge(sk, copy); return 0; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 00bf35ee8205..c62e42d0c531 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3195,9 +3195,7 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) } } - to->truesize += len + plen; - to->len += len + plen; - to->data_len += len + plen; + skb_len_add(to, len + plen); if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { skb_tx_error(from); @@ -3634,13 +3632,8 @@ onlymerged: tgt->ip_summed = CHECKSUM_PARTIAL; skb->ip_summed = CHECKSUM_PARTIAL; - /* Yak, is it really working this way? Some helper please? */ - skb->len -= shiftlen; - skb->data_len -= shiftlen; - skb->truesize -= shiftlen; - tgt->len += shiftlen; - tgt->data_len += shiftlen; - tgt->truesize += shiftlen; + skb_len_add(skb, -shiftlen); + skb_len_add(tgt, shiftlen); return shiftlen; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b21238df3301..7eae8d686e20 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -502,9 +502,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * nfrags++; - skb->len += tailen; - skb->data_len += tailen; - skb->truesize += tailen; + skb_len_add(skb, tailen); if (sk && sk_fullsock(sk)) refcount_add(tailen, &sk->sk_wmem_alloc); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 00b4bf26fd93..5e32a2f86fbd 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1214,9 +1214,7 @@ alloc_new_skb: pfrag->offset += copy; skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; + skb_len_add(skb, copy); wmem_alloc_delta += copy; } else { err = skb_zerocopy_iter_dgram(skb, from, copy); @@ -1443,9 +1441,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, skb->csum = csum_block_add(skb->csum, csum, skb->len); } - skb->len += len; - skb->data_len += len; - skb->truesize += len; + skb_len_add(skb, len); refcount_add(len, &sk->sk_wmem_alloc); offset += len; size -= len; -- cgit v1.2.3 From 67f38b1c7324a13113e23f7177b1f1c223da3f55 Mon Sep 17 00:00:00 2001 From: Clément Léger Date: Fri, 24 Jun 2022 16:39:47 +0200 Subject: net: dsa: add support for ethtool get_rmon_stats() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to allow dsa drivers to specify the .get_rmon_stats() operation. Signed-off-by: Clément Léger Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 3 +++ net/dsa/slave.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) (limited to 'include/net') diff --git a/include/net/dsa.h b/include/net/dsa.h index 14f07275852b..64da5ed27fdc 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -888,6 +888,9 @@ struct dsa_switch_ops { struct ethtool_eth_mac_stats *mac_stats); void (*get_eth_ctrl_stats)(struct dsa_switch *ds, int port, struct ethtool_eth_ctrl_stats *ctrl_stats); + void (*get_rmon_stats)(struct dsa_switch *ds, int port, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges); void (*get_stats64)(struct dsa_switch *ds, int port, struct rtnl_link_stats64 *s); void (*self_test)(struct dsa_switch *ds, int port, diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 509b98dd9954..760ca58307a3 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1002,6 +1002,18 @@ dsa_slave_get_eth_ctrl_stats(struct net_device *dev, ds->ops->get_eth_ctrl_stats(ds, dp->index, ctrl_stats); } +static void +dsa_slave_get_rmon_stats(struct net_device *dev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_rmon_stats) + ds->ops->get_rmon_stats(ds, dp->index, rmon_stats, ranges); +} + static void dsa_slave_net_selftest(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) { @@ -2081,6 +2093,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_eth_phy_stats = dsa_slave_get_eth_phy_stats, .get_eth_mac_stats = dsa_slave_get_eth_mac_stats, .get_eth_ctrl_stats = dsa_slave_get_eth_ctrl_stats, + .get_rmon_stats = dsa_slave_get_rmon_stats, .set_wol = dsa_slave_set_wol, .get_wol = dsa_slave_get_wol, .set_eee = dsa_slave_set_eee, -- cgit v1.2.3 From a08d6a6dc82036cbd889fe3d53f9c69dc13436eb Mon Sep 17 00:00:00 2001 From: Clément Léger Date: Fri, 24 Jun 2022 16:39:48 +0200 Subject: net: dsa: add Renesas RZ/N1 switch tag driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The switch that is present on the Renesas RZ/N1 SoC uses a specific VLAN value followed by 6 bytes which contains forwarding configuration. Signed-off-by: Clément Léger Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 2 + include/uapi/linux/if_ether.h | 1 + net/dsa/Kconfig | 7 +++ net/dsa/Makefile | 1 + net/dsa/tag_rzn1_a5psw.c | 113 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 net/dsa/tag_rzn1_a5psw.c (limited to 'include/net') diff --git a/include/net/dsa.h b/include/net/dsa.h index 64da5ed27fdc..33283eeda697 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -53,6 +53,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_SJA1110_VALUE 23 #define DSA_TAG_PROTO_RTL8_4_VALUE 24 #define DSA_TAG_PROTO_RTL8_4T_VALUE 25 +#define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -81,6 +82,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_SJA1110 = DSA_TAG_PROTO_SJA1110_VALUE, DSA_TAG_PROTO_RTL8_4 = DSA_TAG_PROTO_RTL8_4_VALUE, DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE, + DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE, }; struct dsa_switch; diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index 1d0bccc3fa54..d370165bc621 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -116,6 +116,7 @@ #define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_DSA_8021Q 0xDADB /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_DSA_A5PSW 0xE001 /* A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */ #define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */ diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 8cb87b5067ee..63853fff4e2f 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -132,6 +132,13 @@ config NET_DSA_TAG_RTL8_4 Say Y or M if you want to enable support for tagging frames for Realtek switches with 8 byte protocol 4 tags, such as the Realtek RTL8365MB-VC. +config NET_DSA_TAG_RZN1_A5PSW + tristate "Tag driver for Renesas RZ/N1 A5PSW switch" + help + Say Y or M if you want to enable support for tagging frames for + Renesas RZ/N1 embedded switch that uses an 8 byte tag located after + destination MAC address. + config NET_DSA_TAG_LAN9303 tristate "Tag driver for SMSC/Microchip LAN9303 family of switches" help diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 9f75820e7c98..af28c24ead18 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_DSA_TAG_OCELOT_8021Q) += tag_ocelot_8021q.o obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o obj-$(CONFIG_NET_DSA_TAG_RTL8_4) += tag_rtl8_4.o +obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) += tag_rzn1_a5psw.o obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c new file mode 100644 index 000000000000..e2a5ee6ae688 --- /dev/null +++ b/net/dsa/tag_rzn1_a5psw.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Schneider Electric + * + * Clément Léger + */ + +#include +#include +#include +#include + +#include "dsa_priv.h" + +/* To define the outgoing port and to discover the incoming port a TAG is + * inserted after Src MAC : + * + * Dest MAC Src MAC TAG Type + * ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |... + * |<--------------->| + * + * See struct a5psw_tag for layout + */ + +#define ETH_P_DSA_A5PSW 0xE001 +#define A5PSW_TAG_LEN 8 +#define A5PSW_CTRL_DATA_FORCE_FORWARD BIT(0) +/* This is both used for xmit tag and rcv tagging */ +#define A5PSW_CTRL_DATA_PORT GENMASK(3, 0) + +struct a5psw_tag { + __be16 ctrl_tag; + __be16 ctrl_data; + __be16 ctrl_data2_hi; + __be16 ctrl_data2_lo; +}; + +static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct a5psw_tag *ptag; + u32 data2_val; + + BUILD_BUG_ON(sizeof(*ptag) != A5PSW_TAG_LEN); + + /* The Ethernet switch we are interfaced with needs packets to be at + * least 60 bytes otherwise they will be discarded when they enter the + * switch port logic. + */ + if (__skb_put_padto(skb, ETH_ZLEN, false)) + return NULL; + + /* provide 'A5PSW_TAG_LEN' bytes additional space */ + skb_push(skb, A5PSW_TAG_LEN); + + /* make room between MACs and Ether-Type to insert tag */ + dsa_alloc_etype_header(skb, A5PSW_TAG_LEN); + + ptag = dsa_etype_header_pos_tx(skb); + + data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, BIT(dp->index)); + ptag->ctrl_tag = htons(ETH_P_DSA_A5PSW); + ptag->ctrl_data = htons(A5PSW_CTRL_DATA_FORCE_FORWARD); + ptag->ctrl_data2_lo = htons(data2_val); + ptag->ctrl_data2_hi = 0; + + return skb; +} + +static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb, + struct net_device *dev) +{ + struct a5psw_tag *tag; + int port; + + if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) { + dev_warn_ratelimited(&dev->dev, + "Dropping packet, cannot pull\n"); + return NULL; + } + + tag = dsa_etype_header_pos_rx(skb); + + if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) { + dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n"); + return NULL; + } + + port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data)); + + skb->dev = dsa_master_find_slave(dev, 0, port); + if (!skb->dev) + return NULL; + + skb_pull_rcsum(skb, A5PSW_TAG_LEN); + dsa_strip_etype_header(skb, A5PSW_TAG_LEN); + + dsa_default_offload_fwd_mark(skb); + + return skb; +} + +static const struct dsa_device_ops a5psw_netdev_ops = { + .name = "a5psw", + .proto = DSA_TAG_PROTO_RZN1_A5PSW, + .xmit = a5psw_tag_xmit, + .rcv = a5psw_tag_rcv, + .needed_headroom = A5PSW_TAG_LEN, +}; + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_A5PSW); +module_dsa_tag_driver(a5psw_netdev_ops); -- cgit v1.2.3 From 3d410403a572766628947754e2f62c29bcbf9035 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 28 Jun 2022 10:51:52 +0200 Subject: net: dsa: add get_pause_stats support Add support for pause stats Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- include/net/dsa.h | 2 ++ net/dsa/slave.c | 11 +++++++++++ 2 files changed, 13 insertions(+) (limited to 'include/net') diff --git a/include/net/dsa.h b/include/net/dsa.h index 33283eeda697..ea7bf007f34f 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -895,6 +895,8 @@ struct dsa_switch_ops { const struct ethtool_rmon_hist_range **ranges); void (*get_stats64)(struct dsa_switch *ds, int port, struct rtnl_link_stats64 *s); + void (*get_pause_stats)(struct dsa_switch *ds, int port, + struct ethtool_pause_stats *pause_stats); void (*self_test)(struct dsa_switch *ds, int port, struct ethtool_test *etest, u64 *data); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 760ca58307a3..ad6a6663feeb 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1109,6 +1109,16 @@ static int dsa_slave_set_link_ksettings(struct net_device *dev, return phylink_ethtool_ksettings_set(dp->pl, cmd); } +static void dsa_slave_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_pause_stats) + ds->ops->get_pause_stats(ds, dp->index, pause_stats); +} + static void dsa_slave_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) { @@ -2100,6 +2110,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_eee = dsa_slave_get_eee, .get_link_ksettings = dsa_slave_get_link_ksettings, .set_link_ksettings = dsa_slave_set_link_ksettings, + .get_pause_stats = dsa_slave_get_pause_stats, .get_pauseparam = dsa_slave_get_pauseparam, .set_pauseparam = dsa_slave_set_pauseparam, .get_rxnfc = dsa_slave_get_rxnfc, -- cgit v1.2.3 From 3eb4a4c3442c0642feaf466ecf6fe3cfb4af2c43 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 28 Jun 2022 13:08:31 +0300 Subject: net: switchdev: add reminder near struct switchdev_notifier_fdb_info br_switchdev_fdb_notify() creates an on-stack FDB info variable, and initializes it member by member. As such, newly added fields which are not initialized by br_switchdev_fdb_notify() will contain junk bytes from the stack. Other uses of struct switchdev_notifier_fdb_info have a struct initializer which should put zeroes in the uninitialized fields. Add a reminder above the structure for future developers. Recently discussed during review. Link: https://patchwork.kernel.org/project/netdevbpf/patch/20220524152144.40527-2-schultz.hans+netdev@gmail.com/#24877698 Link: https://patchwork.kernel.org/project/netdevbpf/patch/20220524152144.40527-3-schultz.hans+netdev@gmail.com/#24912269 Signed-off-by: Vladimir Oltean Reviewed-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Link: https://lore.kernel.org/r/20220628100831.2899434-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- include/net/switchdev.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/net') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index aa0171d5786d..7dcdc97c0bc3 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -239,6 +239,9 @@ struct switchdev_notifier_info { const void *ctx; }; +/* Remember to update br_switchdev_fdb_populate() when adding + * new members to this structure + */ struct switchdev_notifier_fdb_info { struct switchdev_notifier_info info; /* must be first */ const unsigned char *addr; -- cgit v1.2.3 From 211da42eaa45db7b0edfde187dd88a85fbd466b5 Mon Sep 17 00:00:00 2001 From: Yuwei Wang Date: Wed, 29 Jun 2022 08:48:32 +0000 Subject: net, neigh: introduce interval_probe_time_ms for periodic probe commit ed6cd6a17896 ("net, neigh: Set lower cap for neigh_managed_work rearming") fixed a case when DELAY_PROBE_TIME is configured to 0, the processing of the system work queue hog CPU to 100%, and further more we should introduce a new option used by periodic probe Signed-off-by: Yuwei Wang Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 6 ++++++ include/net/neighbour.h | 1 + include/uapi/linux/neighbour.h | 1 + include/uapi/linux/sysctl.h | 37 +++++++++++++++++----------------- net/core/neighbour.c | 32 +++++++++++++++++++++++++++-- net/decnet/dn_neigh.c | 1 + net/ipv4/arp.c | 1 + net/ipv6/ndisc.c | 1 + 8 files changed, 60 insertions(+), 20 deletions(-) (limited to 'include/net') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 9f41961d11d5..4c8bbf5acfd1 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -202,6 +202,12 @@ neigh/default/unres_qlen - INTEGER Default: 101 +neigh/default/interval_probe_time_ms - INTEGER + The probe interval for neighbor entries with NTF_MANAGED flag, + the min value is 1. + + Default: 5000 + mtu_expires - INTEGER Time, in seconds, that cached PMTU information is kept. diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 87419f7f5421..9f0bab0589d9 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -48,6 +48,7 @@ enum { NEIGH_VAR_RETRANS_TIME, NEIGH_VAR_BASE_REACHABLE_TIME, NEIGH_VAR_DELAY_PROBE_TIME, + NEIGH_VAR_INTERVAL_PROBE_TIME_MS, NEIGH_VAR_GC_STALETIME, NEIGH_VAR_QUEUE_LEN_BYTES, NEIGH_VAR_PROXY_QLEN, diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index 39c565e460c7..a998bf761635 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -154,6 +154,7 @@ enum { NDTPA_QUEUE_LENBYTES, /* u32 */ NDTPA_MCAST_REPROBES, /* u32 */ NDTPA_PAD, + NDTPA_INTERVAL_PROBE_TIME_MS, /* u64, msecs */ __NDTPA_MAX }; #define NDTPA_MAX (__NDTPA_MAX - 1) diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h index 6a3b194c50fe..8981f00204db 100644 --- a/include/uapi/linux/sysctl.h +++ b/include/uapi/linux/sysctl.h @@ -584,24 +584,25 @@ enum { /* /proc/sys/net//neigh/ */ enum { - NET_NEIGH_MCAST_SOLICIT=1, - NET_NEIGH_UCAST_SOLICIT=2, - NET_NEIGH_APP_SOLICIT=3, - NET_NEIGH_RETRANS_TIME=4, - NET_NEIGH_REACHABLE_TIME=5, - NET_NEIGH_DELAY_PROBE_TIME=6, - NET_NEIGH_GC_STALE_TIME=7, - NET_NEIGH_UNRES_QLEN=8, - NET_NEIGH_PROXY_QLEN=9, - NET_NEIGH_ANYCAST_DELAY=10, - NET_NEIGH_PROXY_DELAY=11, - NET_NEIGH_LOCKTIME=12, - NET_NEIGH_GC_INTERVAL=13, - NET_NEIGH_GC_THRESH1=14, - NET_NEIGH_GC_THRESH2=15, - NET_NEIGH_GC_THRESH3=16, - NET_NEIGH_RETRANS_TIME_MS=17, - NET_NEIGH_REACHABLE_TIME_MS=18, + NET_NEIGH_MCAST_SOLICIT = 1, + NET_NEIGH_UCAST_SOLICIT = 2, + NET_NEIGH_APP_SOLICIT = 3, + NET_NEIGH_RETRANS_TIME = 4, + NET_NEIGH_REACHABLE_TIME = 5, + NET_NEIGH_DELAY_PROBE_TIME = 6, + NET_NEIGH_GC_STALE_TIME = 7, + NET_NEIGH_UNRES_QLEN = 8, + NET_NEIGH_PROXY_QLEN = 9, + NET_NEIGH_ANYCAST_DELAY = 10, + NET_NEIGH_PROXY_DELAY = 11, + NET_NEIGH_LOCKTIME = 12, + NET_NEIGH_GC_INTERVAL = 13, + NET_NEIGH_GC_THRESH1 = 14, + NET_NEIGH_GC_THRESH2 = 15, + NET_NEIGH_GC_THRESH3 = 16, + NET_NEIGH_RETRANS_TIME_MS = 17, + NET_NEIGH_REACHABLE_TIME_MS = 18, + NET_NEIGH_INTERVAL_PROBE_TIME_MS = 19, }; /* /proc/sys/net/dccp */ diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d8ec70622ecb..6a8c2596ebab 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1579,7 +1579,7 @@ static void neigh_managed_work(struct work_struct *work) list_for_each_entry(neigh, &tbl->managed_list, managed_list) neigh_event_send_probe(neigh, NULL, false); queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, - max(NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME), HZ)); + NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS)); write_unlock_bh(&tbl->lock); } @@ -2100,7 +2100,9 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) nla_put_msecs(skb, NDTPA_PROXY_DELAY, NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) || nla_put_msecs(skb, NDTPA_LOCKTIME, - NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD)) + NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD) || + nla_put_msecs(skb, NDTPA_INTERVAL_PROBE_TIME_MS, + NEIGH_VAR(parms, INTERVAL_PROBE_TIME_MS), NDTPA_PAD)) goto nla_put_failure; return nla_nest_end(skb, nest); @@ -2255,6 +2257,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 }, [NDTPA_PROXY_DELAY] = { .type = NLA_U64 }, [NDTPA_LOCKTIME] = { .type = NLA_U64 }, + [NDTPA_INTERVAL_PROBE_TIME_MS] = { .type = NLA_U64, .min = 1 }, }; static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2373,6 +2376,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, nla_get_msecs(tbp[i])); call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p); break; + case NDTPA_INTERVAL_PROBE_TIME_MS: + NEIGH_VAR_SET(p, INTERVAL_PROBE_TIME_MS, + nla_get_msecs(tbp[i])); + break; case NDTPA_RETRANS_TIME: NEIGH_VAR_SET(p, RETRANS_TIME, nla_get_msecs(tbp[i])); @@ -3562,6 +3569,22 @@ static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, return ret; } +static int neigh_proc_dointvec_ms_jiffies_positive(struct ctl_table *ctl, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table tmp = *ctl; + int ret; + + int min = msecs_to_jiffies(1); + + tmp.extra1 = &min; + tmp.extra2 = NULL; + + ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos); + neigh_proc_update(ctl, write); + return ret; +} + int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer, size_t *lenp, loff_t *ppos) { @@ -3658,6 +3681,9 @@ static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write, #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies) +#define NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(attr, name) \ + NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies_positive) + #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies) @@ -3676,6 +3702,8 @@ static struct neigh_sysctl_table { NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"), NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"), NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"), + NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(INTERVAL_PROBE_TIME_MS, + "interval_probe_time_ms"), NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"), NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"), NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"), diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index fbd98ac853ea..7c569bcc0aca 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -94,6 +94,7 @@ struct neigh_table dn_neigh_table = { [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, [NEIGH_VAR_PROXY_QLEN] = 0, diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index ab4a5601c82a..af2f12ffc9ca 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -168,6 +168,7 @@ struct neigh_table arp_tbl = { [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, [NEIGH_VAR_PROXY_QLEN] = 64, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b0dfe97ea4ee..cd84cbdac0a2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -128,6 +128,7 @@ struct neigh_table nd_tbl = { [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER, [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME, [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, + [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX, [NEIGH_VAR_PROXY_QLEN] = 64, -- cgit v1.2.3 From 2d8b08fef0af23aa2fe7f1a1719ac5b11478042f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2022 10:46:05 +0100 Subject: wifi: cfg80211: fix kernel-doc warnings all over the file There are currently 17 kernel-doc warnings on this file: include/net/cfg80211.h:391: warning: Function parameter or member 'bw' not described in 'ieee80211_eht_mcs_nss_supp' include/net/cfg80211.h:437: warning: Function parameter or member 'eht_cap' not described in 'ieee80211_sband_iftype_data' include/net/cfg80211.h:507: warning: Function parameter or member 's1g' not described in 'ieee80211_sta_s1g_cap' include/net/cfg80211.h:1390: warning: Function parameter or member 'counter_offset_beacon' not described in 'cfg80211_color_change_settings' include/net/cfg80211.h:1390: warning: Function parameter or member 'counter_offset_presp' not described in 'cfg80211_color_change_settings' include/net/cfg80211.h:1430: warning: Enum value 'STATION_PARAM_APPLY_STA_TXPOWER' not described in enum 'station_parameters_apply_mask' include/net/cfg80211.h:2195: warning: Function parameter or member 'dot11MeshConnectedToAuthServer' not described in 'mesh_config' include/net/cfg80211.h:2341: warning: Function parameter or member 'short_ssid' not described in 'cfg80211_scan_6ghz_params' include/net/cfg80211.h:3328: warning: Function parameter or member 'kck_len' not described in 'cfg80211_gtk_rekey_data' include/net/cfg80211.h:3698: warning: Function parameter or member 'ftm' not described in 'cfg80211_pmsr_result' include/net/cfg80211.h:3828: warning: Function parameter or member 'global_mcast_stypes' not described in 'mgmt_frame_regs' include/net/cfg80211.h:4977: warning: Function parameter or member 'ftm' not described in 'cfg80211_pmsr_capabilities' include/net/cfg80211.h:5742: warning: Function parameter or member 'u' not described in 'wireless_dev' include/net/cfg80211.h:5742: warning: Function parameter or member 'links' not described in 'wireless_dev' include/net/cfg80211.h:5742: warning: Function parameter or member 'valid_links' not described in 'wireless_dev' include/net/cfg80211.h:6076: warning: Function parameter or member 'is_amsdu' not described in 'ieee80211_data_to_8023_exthdr' include/net/cfg80211.h:6949: warning: Function parameter or member 'sig_dbm' not described in 'cfg80211_notify_new_peer_candidate' Address them, in order to build a better documentation from this header. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/f6f522cdc716a01744bb0eae2186f4592976222b.1656409369.git.mchehab@kernel.org Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 996782c44838..c7e641071eff 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -374,6 +374,7 @@ struct ieee80211_sta_he_cap { * and NSS Set field" * * @only_20mhz: MCS/NSS support for 20 MHz-only STA. + * @bw: MCS/NSS support for 80, 160 and 320 MHz * @bw._80: MCS/NSS support for BW <= 80 MHz * @bw._160: MCS/NSS support for BW = 160 MHz * @bw._320: MCS/NSS support for BW = 320 MHz @@ -420,6 +421,7 @@ struct ieee80211_sta_eht_cap { * @he_cap: holds the HE capabilities * @he_6ghz_capa: HE 6 GHz capabilities, must be filled in for a * 6 GHz band channel (and 0 may be valid value). + * @eht_cap: STA's EHT capabilities * @vendor_elems: vendor element(s) to advertise * @vendor_elems.data: vendor element(s) data * @vendor_elems.len: vendor element(s) length @@ -495,7 +497,7 @@ struct ieee80211_edmg { * This structure describes most essential parameters needed * to describe 802.11ah S1G capabilities for a STA. * - * @s1g_supported: is STA an S1G STA + * @s1g: is STA an S1G STA * @cap: S1G capabilities information * @nss_mcs: Supported NSS MCS set */ @@ -1373,8 +1375,8 @@ struct cfg80211_csa_settings { * Used for bss color change * * @beacon_color_change: beacon data while performing the color countdown - * @counter_offsets_beacon: offsets of the counters within the beacon (tail) - * @counter_offsets_presp: offsets of the counters within the probe response + * @counter_offset_beacon: offsets of the counters within the beacon (tail) + * @counter_offset_presp: offsets of the counters within the probe response * @beacon_next: beacon data to be used after the color change * @count: number of beacons until the color change * @color: the color used after the change @@ -1417,6 +1419,7 @@ struct iface_combination_params { * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) * @STATION_PARAM_APPLY_CAPABILITY: apply new capability * @STATION_PARAM_APPLY_PLINK_STATE: apply new plink state + * @STATION_PARAM_APPLY_STA_TXPOWER: apply tx power for STA * * Not all station parameters have in-band "no change" signalling, * for those that don't these flags will are used. @@ -2149,6 +2152,9 @@ struct bss_parameters { * @plink_timeout: If no tx activity is seen from a STA we've established * peering with for longer than this time (in seconds), then remove it * from the STA's list of peers. Default is 30 minutes. + * @dot11MeshConnectedToAuthServer: if set to true then this mesh STA + * will advertise that it is connected to a authentication server + * in the mesh formation field. * @dot11MeshConnectedToMeshGate: if set to true, advertise that this STA is * connected to a mesh gate in mesh formation info. If false, the * value in mesh formation is determined by the presence of root paths @@ -2321,12 +2327,12 @@ struct cfg80211_scan_info { /** * struct cfg80211_scan_6ghz_params - relevant for 6 GHz only * - * @short_bssid: short ssid to scan for + * @short_ssid: short ssid to scan for * @bssid: bssid to scan for * @channel_idx: idx of the channel in the channel array in the scan request * which the above info relvant to * @unsolicited_probe: the AP transmits unsolicited probe response every 20 TU - * @short_ssid_valid: short_ssid is valid and can be used + * @short_ssid_valid: @short_ssid is valid and can be used * @psc_no_listen: when set, and the channel is a PSC channel, no need to wait * 20 TUs before starting to send probe requests. */ @@ -3317,7 +3323,7 @@ struct cfg80211_wowlan_wakeup { * @kck: key confirmation key (@kck_len bytes) * @replay_ctr: replay counter (NL80211_REPLAY_CTR_LEN bytes) * @kek_len: length of kek - * @kck_len length of kck + * @kck_len: length of kck * @akm: akm (oui, id) */ struct cfg80211_gtk_rekey_data { @@ -3679,6 +3685,7 @@ struct cfg80211_pmsr_ftm_result { * @type: type of the measurement reported, note that we only support reporting * one type at a time, but you can report multiple results separately and * they're all aggregated for userspace. + * @ftm: FTM result */ struct cfg80211_pmsr_result { u64 host_time, ap_tsf; @@ -3817,7 +3824,7 @@ struct cfg80211_update_owe_info { * for the entire device * @interface_stypes: bitmap of management frame subtypes registered * for the given interface - * @global_mcast_rx: mcast RX is needed globally for these subtypes + * @global_mcast_stypes: mcast RX is needed globally for these subtypes * @interface_mcast_stypes: mcast RX is needed on this interface * for these subtypes */ @@ -4940,6 +4947,7 @@ struct wiphy_iftype_ext_capab { * @max_peers: maximum number of peers in a single measurement * @report_ap_tsf: can report assoc AP's TSF for radio resource measurement * @randomize_mac_addr: can randomize MAC address for measurement + * @ftm: FTM measurement data * @ftm.supported: FTM measurement is supported * @ftm.asap: ASAP-mode is supported * @ftm.non_asap: non-ASAP-mode is supported @@ -5563,6 +5571,7 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @netdev: (private) Used to reference back to the netdev, may be %NULL * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev + * @u: union containing data specific to @iftype * @connected_addr: (private) BSSID or AP MLD address if connected * @connected: indicates if connected or not (STA mode) * @current_bss: (private) Used by the internal configuration code @@ -5624,6 +5633,9 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @pmsr_free_wk: (private) peer measurements cleanup work * @unprot_beacon_reported: (private) timestamp of last * unprotected beacon report + * @links: array of %IEEE80211_MLD_MAX_NUM_LINKS elements containing @addr + * @ap and @client for each link + * @valid_links: bitmap describing what elements of @links are valid */ struct wireless_dev { struct wiphy *wiphy; @@ -6068,6 +6080,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); * @addr: the device MAC address * @iftype: the virtual interface type * @data_offset: offset of payload after the 802.11 header + * @is_amsdu: true if the 802.11 header is A-MSDU * Return: 0 on success. Non-zero on error. */ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, @@ -6937,6 +6950,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, * @macaddr: the MAC address of the new candidate * @ie: information elements advertised by the peer candidate * @ie_len: length of the information elements buffer + * @sig_dbm: signal level in dBm * @gfp: allocation flags * * This function notifies cfg80211 that the mesh peer candidate has been -- cgit v1.2.3 From 82757b792be7a549460137b2dbfb9d48003a072a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2022 10:46:06 +0100 Subject: wifi: mac80211: add a missing comma at kernel-doc markup The lack of the colon makes it not parse the function parameter: include/net/mac80211.h:6250: warning: Function parameter or member 'vif' not described in 'ieee80211_channel_switch_disconnect' Fix it. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/11c1bdb861d89c93058fcfe312749b482851cbdb.1656409369.git.mchehab@kernel.org Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 27f24ac0426d..c0557142343f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6238,7 +6238,7 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success); /** * ieee80211_channel_switch_disconnect - disconnect due to channel switch error - * @vif &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @block_tx: if %true, do not send deauth frame. * * Instruct mac80211 to disconnect due to a channel switch error. The channel -- cgit v1.2.3 From c8a9415e6ddef98a948f8c30d9ec2e749c0ccd9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 10:36:36 +0200 Subject: wifi: cfg80211: remove redundant documentation These struct members no longer exist, remove them from documentation. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c7e641071eff..87ebed6a48bd 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5572,18 +5572,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev * @u: union containing data specific to @iftype - * @connected_addr: (private) BSSID or AP MLD address if connected * @connected: indicates if connected or not (STA mode) - * @current_bss: (private) Used by the internal configuration code - * @chandef: (private) Used by the internal configuration code to track - * the user-set channel definition. - * @preset_chandef: (private) Used by the internal configuration code to - * track the channel to be used for AP later * @bssid: (private) Used by the internal configuration code - * @ssid: (private) Used by the internal configuration code - * @ssid_len: (private) Used by the internal configuration code - * @mesh_id_len: (private) Used by the internal configuration code - * @mesh_id_up_len: (private) Used by the internal configuration code * @wext: (private) Used by the internal wireless extensions compat code * @wext.ibss: (private) IBSS data part of wext handling * @wext.connect: (private) connection handling data -- cgit v1.2.3 From 7f884baae68adc85db55b97e3fc903a1f20bd1f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 10:42:40 +0200 Subject: wifi: mac80211: fix a kernel-doc complaint Somehow kernel-doc complains here about strong markup, but we really don't need the [] so just remove that. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c0557142343f..853d4d9ebf23 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4045,7 +4045,7 @@ struct ieee80211_prep_tx_info { * removing the old link information is still valid (link_conf pointer), * but may immediately disappear after the function returns. The old or * new links bitmaps may be 0 if going from/to a non-MLO situation. - * The @old[] array contains pointers to the old bss_conf structures + * The @old array contains pointers to the old bss_conf structures * that were already removed, in case they're needed. * This callback can sleep. * @change_sta_links: Change the valid links of a station, similar to -- cgit v1.2.3 From 942741dabcb43236006f557178801ce2051e69f9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 25 Jun 2022 23:24:05 +0200 Subject: wifi: mac80211: switch airtime fairness back to deficit round-robin scheduling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commits 6a789ba679d652587532cec2a0e0274fda172f3b and 2433647bc8d983a543e7d31b41ca2de1c7e2c198. The virtual time scheduler code has a number of issues: - queues slowed down by hardware/firmware powersave handling were not properly handled. - on ath10k in push-pull mode, tx queues that the driver tries to pull from were starved, causing excessive latency - delay between tx enqueue and reported airtime use were causing excessively bursty tx behavior The bursty behavior may also be present on the round-robin scheduler, but there it is much easier to fix without introducing additional regressions Signed-off-by: Felix Fietkau Acked-by: Toke Høiland-Jørgensen Link: https://lore.kernel.org/r/20220625212411.36675-1-nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/mac80211.h | 17 +- net/mac80211/cfg.c | 35 +--- net/mac80211/debugfs.c | 70 ++------ net/mac80211/debugfs_netdev.c | 32 +--- net/mac80211/debugfs_sta.c | 24 +-- net/mac80211/ieee80211_i.h | 182 ++------------------- net/mac80211/iface.c | 4 - net/mac80211/main.c | 11 +- net/mac80211/rx.c | 6 +- net/mac80211/sta_info.c | 67 +++----- net/mac80211/sta_info.h | 11 +- net/mac80211/status.c | 19 --- net/mac80211/tx.c | 366 ++++++++++++------------------------------ 13 files changed, 190 insertions(+), 654 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 853d4d9ebf23..256b9215e17b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6832,6 +6832,9 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) { } +void __ieee80211_schedule_txq(struct ieee80211_hw *hw, + struct ieee80211_txq *txq, bool force); + /** * ieee80211_schedule_txq - schedule a TXQ for transmission * @@ -6844,7 +6847,11 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) * The driver may call this function if it has buffered packets for * this TXQ internally. */ -void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); +static inline void +ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ + __ieee80211_schedule_txq(hw, txq, true); +} /** * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() @@ -6856,8 +6863,12 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); * The driver may set force=true if it has buffered packets for this TXQ * internally. */ -void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, - bool force); +static inline void +ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, + bool force) +{ + __ieee80211_schedule_txq(hw, txq, force); +} /** * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b387f5f4fef0..fd6c4291c971 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1581,38 +1581,6 @@ static void sta_apply_mesh_params(struct ieee80211_local *local, #endif } -static void sta_apply_airtime_params(struct ieee80211_local *local, - struct sta_info *sta, - struct station_parameters *params) -{ - u8 ac; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct airtime_sched_info *air_sched = &local->airtime[ac]; - struct airtime_info *air_info = &sta->airtime[ac]; - struct txq_info *txqi; - u8 tid; - - spin_lock_bh(&air_sched->lock); - for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { - if (air_info->weight == params->airtime_weight || - !sta->sta.txq[tid] || - ac != ieee80211_ac_from_tid(tid)) - continue; - - airtime_weight_set(air_info, params->airtime_weight); - - txqi = to_txq_info(sta->sta.txq[tid]); - if (RB_EMPTY_NODE(&txqi->schedule_order)) - continue; - - ieee80211_update_airtime_weight(local, air_sched, - 0, true); - } - spin_unlock_bh(&air_sched->lock); - } -} - static int sta_apply_parameters(struct ieee80211_local *local, struct sta_info *sta, struct station_parameters *params) @@ -1811,8 +1779,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, sta_apply_mesh_params(local, sta, params); if (params->airtime_weight) - sta_apply_airtime_params(local, sta, params); - + sta->airtime_weight = params->airtime_weight; /* set the STA state after all sta info from usermode has been set */ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) || diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 1fe43b264d75..0c748b1eb023 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct file *file, "VI %u %u\n" "BE %u %u\n" "BK %u %u\n", - local->airtime[IEEE80211_AC_VO].aql_txq_limit_low, - local->airtime[IEEE80211_AC_VO].aql_txq_limit_high, - local->airtime[IEEE80211_AC_VI].aql_txq_limit_low, - local->airtime[IEEE80211_AC_VI].aql_txq_limit_high, - local->airtime[IEEE80211_AC_BE].aql_txq_limit_low, - local->airtime[IEEE80211_AC_BE].aql_txq_limit_high, - local->airtime[IEEE80211_AC_BK].aql_txq_limit_low, - local->airtime[IEEE80211_AC_BK].aql_txq_limit_high); + local->aql_txq_limit_low[IEEE80211_AC_VO], + local->aql_txq_limit_high[IEEE80211_AC_VO], + local->aql_txq_limit_low[IEEE80211_AC_VI], + local->aql_txq_limit_high[IEEE80211_AC_VI], + local->aql_txq_limit_low[IEEE80211_AC_BE], + local->aql_txq_limit_high[IEEE80211_AC_BE], + local->aql_txq_limit_low[IEEE80211_AC_BK], + local->aql_txq_limit_high[IEEE80211_AC_BK]); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struct file *file, if (ac >= IEEE80211_NUM_ACS) return -EINVAL; - q_limit_low_old = local->airtime[ac].aql_txq_limit_low; - q_limit_high_old = local->airtime[ac].aql_txq_limit_high; + q_limit_low_old = local->aql_txq_limit_low[ac]; + q_limit_high_old = local->aql_txq_limit_high[ac]; - local->airtime[ac].aql_txq_limit_low = q_limit_low; - local->airtime[ac].aql_txq_limit_high = q_limit_high; + local->aql_txq_limit_low[ac] = q_limit_low; + local->aql_txq_limit_high[ac] = q_limit_high; mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { @@ -382,46 +382,6 @@ static const struct file_operations force_tx_status_ops = { .llseek = default_llseek, }; -static ssize_t airtime_read(struct file *file, - char __user *user_buf, - size_t count, - loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[200]; - u64 v_t[IEEE80211_NUM_ACS]; - u64 wt[IEEE80211_NUM_ACS]; - int len = 0, ac; - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - spin_lock_bh(&local->airtime[ac].lock); - v_t[ac] = local->airtime[ac].v_t; - wt[ac] = local->airtime[ac].weight_sum; - spin_unlock_bh(&local->airtime[ac].lock); - } - len = scnprintf(buf, sizeof(buf), - "\tVO VI BE BK\n" - "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n" - "Weight\t%-10llu %-10llu %-10llu %-10llu\n", - v_t[0], - v_t[1], - v_t[2], - v_t[3], - wt[0], - wt[1], - wt[2], - wt[3]); - - return simple_read_from_buffer(user_buf, count, ppos, - buf, len); -} - -static const struct file_operations airtime_ops = { - .read = airtime_read, - .open = simple_open, - .llseek = default_llseek, -}; - #ifdef CONFIG_PM static ssize_t reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -675,11 +635,7 @@ void debugfs_hw_add(struct ieee80211_local *local) if (local->ops->wake_tx_queue) DEBUGFS_ADD_MODE(aqm, 0600); - if (wiphy_ext_feature_isset(local->hw.wiphy, - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { - DEBUGFS_ADD_MODE(airtime, 0600); - DEBUGFS_ADD_MODE(airtime_flags, 0600); - } + DEBUGFS_ADD_MODE(airtime_flags, 0600); DEBUGFS_ADD(aql_txq_limit); debugfs_create_u32("aql_threshold", 0600, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index dfb194e15018..ead917501d6c 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -510,34 +510,6 @@ static ssize_t ieee80211_if_fmt_aqm( } IEEE80211_IF_FILE_R(aqm); -static ssize_t ieee80211_if_fmt_airtime( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_txq *txq = sdata->vif.txq; - struct airtime_info *air_info; - int len; - - if (!txq) - return 0; - - spin_lock_bh(&local->airtime[txq->ac].lock); - air_info = to_airtime_info(txq); - len = scnprintf(buf, - buflen, - "RX: %llu us\nTX: %llu us\nWeight: %u\n" - "Virt-T: %lld us\n", - air_info->rx_airtime, - air_info->tx_airtime, - air_info->weight, - air_info->v_t); - spin_unlock_bh(&local->airtime[txq->ac].lock); - - return len; -} - -IEEE80211_IF_FILE_R(airtime); - IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX); /* IBSS attributes */ @@ -683,10 +655,8 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) if (sdata->local->ops->wake_tx_queue && sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && - sdata->vif.type != NL80211_IFTYPE_NAN) { + sdata->vif.type != NL80211_IFTYPE_NAN) DEBUGFS_ADD(aqm); - DEBUGFS_ADD(airtime); - } } static void add_sta_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 182094be9001..1dc238fc24f0 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf, size_t bufsz = 400; char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; u64 rx_airtime = 0, tx_airtime = 0; - u64 v_t[IEEE80211_NUM_ACS]; + s64 deficit[IEEE80211_NUM_ACS]; ssize_t rv; int ac; @@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf, return -ENOMEM; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - spin_lock_bh(&local->airtime[ac].lock); + spin_lock_bh(&local->active_txq_lock[ac]); rx_airtime += sta->airtime[ac].rx_airtime; tx_airtime += sta->airtime[ac].tx_airtime; - v_t[ac] = sta->airtime[ac].v_t; - spin_unlock_bh(&local->airtime[ac].lock); + deficit[ac] = sta->airtime[ac].deficit; + spin_unlock_bh(&local->active_txq_lock[ac]); } p += scnprintf(p, bufsz + buf - p, "RX: %llu us\nTX: %llu us\nWeight: %u\n" - "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", - rx_airtime, tx_airtime, sta->airtime[0].weight, - v_t[0], v_t[1], v_t[2], v_t[3]); + "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", + rx_airtime, tx_airtime, sta->airtime_weight, + deficit[0], deficit[1], deficit[2], deficit[3]); rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); kfree(buf); @@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf, int ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - spin_lock_bh(&local->airtime[ac].lock); + spin_lock_bh(&local->active_txq_lock[ac]); sta->airtime[ac].rx_airtime = 0; sta->airtime[ac].tx_airtime = 0; - sta->airtime[ac].v_t = 0; - spin_unlock_bh(&local->airtime[ac].lock); + sta->airtime[ac].deficit = sta->airtime_weight; + spin_unlock_bh(&local->active_txq_lock[ac]); } return count; @@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file *file, char __user *userbuf, return -ENOMEM; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - spin_lock_bh(&local->airtime[ac].lock); + spin_lock_bh(&local->active_txq_lock[ac]); q_limit_l[ac] = sta->airtime[ac].aql_limit_low; q_limit_h[ac] = sta->airtime[ac].aql_limit_high; - spin_unlock_bh(&local->airtime[ac].lock); + spin_unlock_bh(&local->active_txq_lock[ac]); q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2190d08f4e34..f21e456dbad7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -818,16 +818,20 @@ enum txq_info_flags { * @def_flow: used as a fallback flow when a packet destined to @tin hashes to * a fq_flow which is already owned by a different tin * @def_cvars: codel vars for @def_flow - * @schedule_order: used with ieee80211_local->active_txqs * @frags: used to keep fragments created after dequeue + * @schedule_order: used with ieee80211_local->active_txqs + * @schedule_round: counter to prevent infinite loops on TXQ scheduling */ struct txq_info { struct fq_tin tin; struct codel_vars def_cvars; struct codel_stats cstats; - struct rb_node schedule_order; + + u16 schedule_round; + struct list_head schedule_order; struct sk_buff_head frags; + unsigned long flags; /* keep last! */ @@ -923,8 +927,6 @@ struct ieee80211_link_data { struct ieee80211_key __rcu *default_mgmt_key; struct ieee80211_key __rcu *default_beacon_key; - struct airtime_info airtime[IEEE80211_NUM_ACS]; - struct work_struct csa_finalize_work; bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ struct cfg80211_chan_def csa_chandef; @@ -1208,44 +1210,6 @@ enum mac80211_scan_state { SCAN_ABORT, }; -/** - * struct airtime_sched_info - state used for airtime scheduling and AQL - * - * @lock: spinlock that protects all the fields in this struct - * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time - * @schedule_pos: the current position maintained while a driver walks the tree - * with ieee80211_next_txq() - * @active_list: list of struct airtime_info structs that were active within - * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute - * weight_sum - * @last_weight_update: used for rate limiting walking active_list - * @last_schedule_time: tracks the last time a transmission was scheduled; used - * for catching up v_t if no stations are eligible for - * transmission. - * @v_t: global virtual time; queues with v_t < this are eligible for - * transmission - * @weight_sum: total sum of all active stations used for dividing airtime - * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast - * path - see comment above - * IEEE80211_RECIPROCAL_DIVISOR_64) - * @aql_txq_limit_low: AQL limit when total outstanding airtime - * is < IEEE80211_AQL_THRESHOLD - * @aql_txq_limit_high: AQL limit when total outstanding airtime - * is > IEEE80211_AQL_THRESHOLD - */ -struct airtime_sched_info { - spinlock_t lock; - struct rb_root_cached active_txqs; - struct rb_node *schedule_pos; - struct list_head active_list; - u64 last_weight_update; - u64 last_schedule_activity; - u64 v_t; - u64 weight_sum; - u64 weight_sum_reciprocal; - u32 aql_txq_limit_low; - u32 aql_txq_limit_high; -}; DECLARE_STATIC_KEY_FALSE(aql_disable); struct ieee80211_local { @@ -1259,8 +1223,13 @@ struct ieee80211_local { struct codel_params cparams; /* protects active_txqs and txqi->schedule_order */ - struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; + spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; + struct list_head active_txqs[IEEE80211_NUM_ACS]; + u16 schedule_round[IEEE80211_NUM_ACS]; + u16 airtime_flags; + u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; + u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; u32 aql_threshold; atomic_t aql_total_pending_airtime; @@ -1683,125 +1652,6 @@ static inline bool txq_has_queue(struct ieee80211_txq *txq) return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets); } -static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq) -{ - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - - if (txq->sta) { - sta = container_of(txq->sta, struct sta_info, sta); - return &sta->airtime[txq->ac]; - } - - sdata = vif_to_sdata(txq->vif); - return &sdata->deflink.airtime[txq->ac]; -} - -/* To avoid divisions in the fast path, we keep pre-computed reciprocals for - * airtime weight calculations. There are two different weights to keep track - * of: The per-station weight and the sum of weights per phy. - * - * For the per-station weights (kept in airtime_info below), we use 32-bit - * reciprocals with a devisor of 2^19. This lets us keep the multiplications and - * divisions for the station weights as 32-bit operations at the cost of a bit - * of rounding error for high weights; but the choice of divisor keeps rounding - * errors <10% for weights <2^15, assuming no more than 8ms of airtime is - * reported at a time. - * - * For the per-phy sum of weights the values can get higher, so we use 64-bit - * operations for those with a 32-bit divisor, which should avoid any - * significant rounding errors. - */ -#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL -#define IEEE80211_RECIPROCAL_SHIFT_64 32 -#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U -#define IEEE80211_RECIPROCAL_SHIFT_32 19 - -static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight) -{ - if (air_info->weight == weight) - return; - - air_info->weight = weight; - if (weight) { - air_info->weight_reciprocal = - IEEE80211_RECIPROCAL_DIVISOR_32 / weight; - } else { - air_info->weight_reciprocal = 0; - } -} - -static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched, - int weight_sum) -{ - if (air_sched->weight_sum == weight_sum) - return; - - air_sched->weight_sum = weight_sum; - if (air_sched->weight_sum) { - air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64; - do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum); - } else { - air_sched->weight_sum_reciprocal = 0; - } -} - -/* A problem when trying to enforce airtime fairness is that we want to divide - * the airtime between the currently *active* stations. However, basing this on - * the instantaneous queue state of stations doesn't work, as queues tend to - * oscillate very quickly between empty and occupied, leading to the scheduler - * thinking only a single station is active when deciding whether to allow - * transmission (and thus not throttling correctly). - * - * To fix this we use a timer-based notion of activity: a station is considered - * active if it has been scheduled within the last 100 ms; we keep a separate - * list of all the stations considered active in this manner, and lazily update - * the total weight of active stations from this list (filtering the stations in - * the list by their 'last active' time). - * - * We add one additional safeguard to guard against stations that manage to get - * scheduled every 100 ms but don't transmit a lot of data, and thus don't use - * up any airtime. Such stations would be able to get priority for an extended - * period of time if they do start transmitting at full capacity again, and so - * we add an explicit maximum for how far behind a station is allowed to fall in - * the virtual airtime domain. This limit is set to a relatively high value of - * 20 ms because the main mechanism for catching up idle stations is the active - * state as described above; i.e., the hard limit should only be hit in - * pathological cases. - */ -#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC) -#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */ - -static inline bool airtime_is_active(struct airtime_info *air_info, u64 now) -{ - return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION; -} - -static inline void airtime_set_active(struct airtime_sched_info *air_sched, - struct airtime_info *air_info, u64 now) -{ - air_info->last_scheduled = now; - air_sched->last_schedule_activity = now; - list_move_tail(&air_info->list, &air_sched->active_list); -} - -static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched, - u64 v_t, u64 now) -{ - air_sched->v_t = v_t; - return true; -} - -static inline void init_airtime_info(struct airtime_info *air_info, - struct airtime_sched_info *air_sched) -{ - atomic_set(&air_info->aql_tx_pending, 0); - air_info->aql_limit_low = air_sched->aql_txq_limit_low; - air_info->aql_limit_high = air_sched->aql_txq_limit_high; - airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT); - INIT_LIST_HEAD(&air_info->list); -} - static inline bool ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) { @@ -2047,14 +1897,6 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, u64 *cookie); int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len); -void ieee80211_resort_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq); -void ieee80211_unschedule_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq, - bool purge); -void ieee80211_update_airtime_weight(struct ieee80211_local *local, - struct airtime_sched_info *air_sched, - u64 now, bool force); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 0cf5a395d925..56dd831fe45f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -2176,10 +2176,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, } } - for (i = 0; i < IEEE80211_NUM_ACS; i++) - init_airtime_info(&sdata->deflink.airtime[i], - &local->airtime[i]); - ieee80211_set_default_queues(sdata); sdata->deflink.ap_power_level = IEEE80211_UNSET_POWER_LEVEL; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 08f153b82a23..e6c1cafbe9e5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -784,13 +784,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, spin_lock_init(&local->queue_stop_reason_lock); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - struct airtime_sched_info *air_sched = &local->airtime[i]; - - air_sched->active_txqs = RB_ROOT_CACHED; - INIT_LIST_HEAD(&air_sched->active_list); - spin_lock_init(&air_sched->lock); - air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; - air_sched->aql_txq_limit_high = + INIT_LIST_HEAD(&local->active_txqs[i]); + spin_lock_init(&local->active_txq_lock[i]); + local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; + local->aql_txq_limit_high[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d017ad14d7db..834d2171f344 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1565,8 +1565,12 @@ static void sta_ps_start(struct sta_info *sta) for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { struct ieee80211_txq *txq = sta->sta.txq[tid]; + struct txq_info *txqi = to_txq_info(txq); - ieee80211_unschedule_txq(&local->hw, txq, false); + spin_lock(&local->active_txq_lock[txq->ac]); + if (!list_empty(&txqi->schedule_order)) + list_del_init(&txqi->schedule_order); + spin_unlock(&local->active_txq_lock[txq->ac]); if (txq_has_queue(txq)) set_bit(tid, &sta->txq_buffered_tids); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 014032369994..a1a2118b4bf0 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -559,11 +559,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (sta_prepare_rate_control(local, sta, gfp)) goto free_txq; + sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; for (i = 0; i < IEEE80211_NUM_ACS; i++) { skb_queue_head_init(&sta->ps_tx_buf[i]); skb_queue_head_init(&sta->tx_filtered[i]); - init_airtime_info(&sta->airtime[i], &local->airtime[i]); + sta->airtime[i].deficit = sta->airtime_weight; + atomic_set(&sta->airtime[i].aql_tx_pending, 0); + sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; + sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; } for (i = 0; i < IEEE80211_NUM_TIDS; i++) @@ -2035,59 +2039,24 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, } EXPORT_SYMBOL(ieee80211_sta_set_buffered); -void ieee80211_register_airtime(struct ieee80211_txq *txq, - u32 tx_airtime, u32 rx_airtime) +void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, + u32 tx_airtime, u32 rx_airtime) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); - struct ieee80211_local *local = sdata->local; - u64 weight_sum, weight_sum_reciprocal; - struct airtime_sched_info *air_sched; - struct airtime_info *air_info; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_local *local = sta->sdata->local; + u8 ac = ieee80211_ac_from_tid(tid); u32 airtime = 0; - air_sched = &local->airtime[txq->ac]; - air_info = to_airtime_info(txq); - - if (local->airtime_flags & AIRTIME_USE_TX) + if (sta->local->airtime_flags & AIRTIME_USE_TX) airtime += tx_airtime; - if (local->airtime_flags & AIRTIME_USE_RX) + if (sta->local->airtime_flags & AIRTIME_USE_RX) airtime += rx_airtime; - /* Weights scale so the unit weight is 256 */ - airtime <<= 8; - - spin_lock_bh(&air_sched->lock); - - air_info->tx_airtime += tx_airtime; - air_info->rx_airtime += rx_airtime; - - if (air_sched->weight_sum) { - weight_sum = air_sched->weight_sum; - weight_sum_reciprocal = air_sched->weight_sum_reciprocal; - } else { - weight_sum = air_info->weight; - weight_sum_reciprocal = air_info->weight_reciprocal; - } - - /* Round the calculation of global vt */ - air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) * - weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64; - air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) * - air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32; - ieee80211_resort_txq(&local->hw, txq); - - spin_unlock_bh(&air_sched->lock); -} - -void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, - u32 tx_airtime, u32 rx_airtime) -{ - struct ieee80211_txq *txq = pubsta->txq[tid]; - - if (!txq) - return; - - ieee80211_register_airtime(txq, tx_airtime, rx_airtime); + spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].tx_airtime += tx_airtime; + sta->airtime[ac].rx_airtime += rx_airtime; + sta->airtime[ac].deficit -= airtime; + spin_unlock_bh(&local->active_txq_lock[ac]); } EXPORT_SYMBOL(ieee80211_sta_register_airtime); @@ -2501,7 +2470,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, } if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { - sinfo->airtime_weight = sta->airtime[0].weight; + sinfo->airtime_weight = sta->airtime_weight; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4e0b969891de..3e26ad3be800 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -135,25 +135,18 @@ enum ieee80211_agg_stop_reason { #define AIRTIME_USE_TX BIT(0) #define AIRTIME_USE_RX BIT(1) - struct airtime_info { u64 rx_airtime; u64 tx_airtime; - u64 v_t; - u64 last_scheduled; - struct list_head list; + s64 deficit; atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ u32 aql_limit_low; u32 aql_limit_high; - u32 weight_reciprocal; - u16 weight; }; void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, struct sta_info *sta, u8 ac, u16 tx_airtime, bool tx_completed); -void ieee80211_register_airtime(struct ieee80211_txq *txq, - u32 tx_airtime, u32 rx_airtime); struct sta_info; @@ -609,6 +602,7 @@ struct link_sta_info { * @tid_seq: per-TID sequence numbers for sending to this STA * @airtime: per-AC struct airtime_info describing airtime statistics for this * station + * @airtime_weight: station weight for airtime fairness calculation purposes * @ampdu_mlme: A-MPDU state machine state * @mesh: mesh STA information * @debugfs_dir: debug filesystem directory dentry @@ -693,6 +687,7 @@ struct sta_info { u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; struct airtime_info airtime[IEEE80211_NUM_ACS]; + u16 airtime_weight; /* * Aggregation information, locked with lock. diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 5c2202a7ea1c..9bd4d336d444 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -998,25 +998,6 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) ieee80211_frame_acked(sta, skb); - } else if (wiphy_ext_feature_isset(local->hw.wiphy, - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { - struct ieee80211_sub_if_data *sdata; - struct ieee80211_txq *txq; - u32 airtime; - - /* Account airtime to multicast queue */ - sdata = ieee80211_sdata_from_skb(local, skb); - - if (sdata && (txq = sdata->vif.txq)) { - airtime = info->status.tx_time ?: - ieee80211_calc_expected_tx_airtime(hw, - &sdata->vif, - NULL, - skb->len, - false); - - ieee80211_register_airtime(txq, airtime, 0); - } } /* SNMP counters diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c3e14ef20c05..fcee60ce2456 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -1479,7 +1478,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, codel_vars_init(&txqi->def_cvars); codel_stats_init(&txqi->cstats); __skb_queue_head_init(&txqi->frags); - RB_CLEAR_NODE(&txqi->schedule_order); + INIT_LIST_HEAD(&txqi->schedule_order); txqi->txq.vif = &sdata->vif; @@ -1523,7 +1522,9 @@ void ieee80211_txq_purge(struct ieee80211_local *local, ieee80211_purge_tx_queue(&local->hw, &txqi->frags); spin_unlock_bh(&fq->lock); - ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); + spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); + list_del_init(&txqi->schedule_order); + spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); } void ieee80211_txq_set_params(struct ieee80211_local *local) @@ -3802,259 +3803,102 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue); struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) { struct ieee80211_local *local = hw_to_local(hw); - struct airtime_sched_info *air_sched; - u64 now = ktime_get_coarse_boottime_ns(); struct ieee80211_txq *ret = NULL; - struct airtime_info *air_info; - struct txq_info *txqi = NULL; - struct rb_node *node; - bool first = false; + struct txq_info *txqi = NULL, *head = NULL; + bool found_eligible_txq = false; - air_sched = &local->airtime[ac]; - spin_lock_bh(&air_sched->lock); + spin_lock_bh(&local->active_txq_lock[ac]); - node = air_sched->schedule_pos; - -begin: - if (!node) { - node = rb_first_cached(&air_sched->active_txqs); - first = true; - } else { - node = rb_next(node); - } - - if (!node) - goto out; - - txqi = container_of(node, struct txq_info, schedule_order); - air_info = to_airtime_info(&txqi->txq); - - if (air_info->v_t > air_sched->v_t && - (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now))) + begin: + txqi = list_first_entry_or_null(&local->active_txqs[ac], + struct txq_info, + schedule_order); + if (!txqi) goto out; - if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { - first = false; - goto begin; - } - - air_sched->schedule_pos = node; - air_sched->last_schedule_activity = now; - ret = &txqi->txq; -out: - spin_unlock_bh(&air_sched->lock); - return ret; -} -EXPORT_SYMBOL(ieee80211_next_txq); - -static void __ieee80211_insert_txq(struct rb_root_cached *root, - struct txq_info *txqi) -{ - struct rb_node **new = &root->rb_root.rb_node; - struct airtime_info *old_air, *new_air; - struct rb_node *parent = NULL; - struct txq_info *__txqi; - bool leftmost = true; - - while (*new) { - parent = *new; - __txqi = rb_entry(parent, struct txq_info, schedule_order); - old_air = to_airtime_info(&__txqi->txq); - new_air = to_airtime_info(&txqi->txq); - - if (new_air->v_t <= old_air->v_t) { - new = &parent->rb_left; - } else { - new = &parent->rb_right; - leftmost = false; - } + if (txqi == head) { + if (!found_eligible_txq) + goto out; + else + found_eligible_txq = false; } - rb_link_node(&txqi->schedule_order, parent, new); - rb_insert_color_cached(&txqi->schedule_order, root, leftmost); -} + if (!head) + head = txqi; -void ieee80211_resort_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) -{ - struct airtime_info *air_info = to_airtime_info(txq); - struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); - struct airtime_sched_info *air_sched; - - air_sched = &local->airtime[txq->ac]; - - lockdep_assert_held(&air_sched->lock); + if (txqi->txq.sta) { + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); + s64 deficit = sta->airtime[txqi->txq.ac].deficit; - if (!RB_EMPTY_NODE(&txqi->schedule_order)) { - struct airtime_info *a_prev = NULL, *a_next = NULL; - struct txq_info *t_prev, *t_next; - struct rb_node *n_prev, *n_next; + if (aql_check) + found_eligible_txq = true; - /* Erasing a node can cause an expensive rebalancing operation, - * so we check the previous and next nodes first and only remove - * and re-insert if the current node is not already in the - * correct position. - */ - if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) { - t_prev = container_of(n_prev, struct txq_info, - schedule_order); - a_prev = to_airtime_info(&t_prev->txq); - } + if (deficit < 0) + sta->airtime[txqi->txq.ac].deficit += + sta->airtime_weight; - if ((n_next = rb_next(&txqi->schedule_order)) != NULL) { - t_next = container_of(n_next, struct txq_info, - schedule_order); - a_next = to_airtime_info(&t_next->txq); + if (deficit < 0 || !aql_check) { + list_move_tail(&txqi->schedule_order, + &local->active_txqs[txqi->txq.ac]); + goto begin; } - - if ((!a_prev || a_prev->v_t <= air_info->v_t) && - (!a_next || a_next->v_t > air_info->v_t)) - return; - - if (air_sched->schedule_pos == &txqi->schedule_order) - air_sched->schedule_pos = n_prev; - - rb_erase_cached(&txqi->schedule_order, - &air_sched->active_txqs); - RB_CLEAR_NODE(&txqi->schedule_order); - __ieee80211_insert_txq(&air_sched->active_txqs, txqi); } -} -void ieee80211_update_airtime_weight(struct ieee80211_local *local, - struct airtime_sched_info *air_sched, - u64 now, bool force) -{ - struct airtime_info *air_info, *tmp; - u64 weight_sum = 0; - - if (unlikely(!now)) - now = ktime_get_coarse_boottime_ns(); - lockdep_assert_held(&air_sched->lock); - - if (!force && (air_sched->last_weight_update < - now - AIRTIME_ACTIVE_DURATION)) - return; - - list_for_each_entry_safe(air_info, tmp, - &air_sched->active_list, list) { - if (airtime_is_active(air_info, now)) - weight_sum += air_info->weight; - else - list_del_init(&air_info->list); - } - airtime_weight_sum_set(air_sched, weight_sum); - air_sched->last_weight_update = now; -} - -void ieee80211_schedule_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - __acquires(txq_lock) __releases(txq_lock) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); - struct airtime_sched_info *air_sched; - u64 now = ktime_get_coarse_boottime_ns(); - struct airtime_info *air_info; - u8 ac = txq->ac; - bool was_active; - - air_sched = &local->airtime[ac]; - air_info = to_airtime_info(txq); - - spin_lock_bh(&air_sched->lock); - was_active = airtime_is_active(air_info, now); - airtime_set_active(air_sched, air_info, now); - - if (!RB_EMPTY_NODE(&txqi->schedule_order)) + if (txqi->schedule_round == local->schedule_round[ac]) goto out; - /* If the station has been inactive for a while, catch up its v_t so it - * doesn't get indefinite priority; see comment above the definition of - * AIRTIME_MAX_BEHIND. - */ - if ((!was_active && air_info->v_t < air_sched->v_t) || - air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND) - air_info->v_t = air_sched->v_t; - - ieee80211_update_airtime_weight(local, air_sched, now, !was_active); - __ieee80211_insert_txq(&air_sched->active_txqs, txqi); + list_del_init(&txqi->schedule_order); + txqi->schedule_round = local->schedule_round[ac]; + ret = &txqi->txq; out: - spin_unlock_bh(&air_sched->lock); -} -EXPORT_SYMBOL(ieee80211_schedule_txq); - -static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq, - bool purge) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); - struct airtime_sched_info *air_sched; - struct airtime_info *air_info; - - air_sched = &local->airtime[txq->ac]; - air_info = to_airtime_info(&txqi->txq); - - lockdep_assert_held(&air_sched->lock); - - if (purge) { - list_del_init(&air_info->list); - ieee80211_update_airtime_weight(local, air_sched, 0, true); - } - - if (RB_EMPTY_NODE(&txqi->schedule_order)) - return; - - if (air_sched->schedule_pos == &txqi->schedule_order) - air_sched->schedule_pos = rb_prev(&txqi->schedule_order); - - if (!purge) - airtime_set_active(air_sched, air_info, - ktime_get_coarse_boottime_ns()); - - rb_erase_cached(&txqi->schedule_order, - &air_sched->active_txqs); - RB_CLEAR_NODE(&txqi->schedule_order); + spin_unlock_bh(&local->active_txq_lock[ac]); + return ret; } +EXPORT_SYMBOL(ieee80211_next_txq); -void ieee80211_unschedule_txq(struct ieee80211_hw *hw, +void __ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, - bool purge) - __acquires(txq_lock) __releases(txq_lock) -{ - struct ieee80211_local *local = hw_to_local(hw); - - spin_lock_bh(&local->airtime[txq->ac].lock); - __ieee80211_unschedule_txq(hw, txq, purge); - spin_unlock_bh(&local->airtime[txq->ac].lock); -} - -void ieee80211_return_txq(struct ieee80211_hw *hw, - struct ieee80211_txq *txq, bool force) + bool force) { struct ieee80211_local *local = hw_to_local(hw); struct txq_info *txqi = to_txq_info(txq); - spin_lock_bh(&local->airtime[txq->ac].lock); - - if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && - !txq_has_queue(txq)) - __ieee80211_unschedule_txq(hw, txq, false); + spin_lock_bh(&local->active_txq_lock[txq->ac]); + + if (list_empty(&txqi->schedule_order) && + (force || !skb_queue_empty(&txqi->frags) || + txqi->tin.backlog_packets)) { + /* If airtime accounting is active, always enqueue STAs at the + * head of the list to ensure that they only get moved to the + * back by the airtime DRR scheduler once they have a negative + * deficit. A station that already has a negative deficit will + * get immediately moved to the back of the list on the next + * call to ieee80211_next_txq(). + */ + if (txqi->txq.sta && local->airtime_flags && + wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + list_add(&txqi->schedule_order, + &local->active_txqs[txq->ac]); + else + list_add_tail(&txqi->schedule_order, + &local->active_txqs[txq->ac]); + } - spin_unlock_bh(&local->airtime[txq->ac].lock); + spin_unlock_bh(&local->active_txq_lock[txq->ac]); } -EXPORT_SYMBOL(ieee80211_return_txq); +EXPORT_SYMBOL(__ieee80211_schedule_txq); DEFINE_STATIC_KEY_FALSE(aql_disable); bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { - struct airtime_info *air_info = to_airtime_info(txq); + struct sta_info *sta; struct ieee80211_local *local = hw_to_local(hw); if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) @@ -4069,12 +3913,15 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) return true; - if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) + sta = container_of(txq->sta, struct sta_info, sta); + if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < + sta->airtime[txq->ac].aql_limit_low) return true; if (atomic_read(&local->aql_total_pending_airtime) < local->aql_threshold && - atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) + atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < + sta->airtime[txq->ac].aql_limit_high) return true; return false; @@ -4084,59 +3931,60 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_check); bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { - struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq); struct ieee80211_local *local = hw_to_local(hw); - struct airtime_sched_info *air_sched; - struct airtime_info *air_info; - struct rb_node *node = NULL; - bool ret = false; - u64 now; - - - if (!ieee80211_txq_airtime_check(hw, txq)) - return false; + struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); + struct sta_info *sta; + u8 ac = txq->ac; - air_sched = &local->airtime[txq->ac]; - spin_lock_bh(&air_sched->lock); + spin_lock_bh(&local->active_txq_lock[ac]); - if (RB_EMPTY_NODE(&txqi->schedule_order)) + if (!txqi->txq.sta) goto out; - now = ktime_get_coarse_boottime_ns(); + if (list_empty(&txqi->schedule_order)) + goto out; - /* Like in ieee80211_next_txq(), make sure the first station in the - * scheduling order is eligible for transmission to avoid starvation. - */ - node = rb_first_cached(&air_sched->active_txqs); - if (node) { - first_txqi = container_of(node, struct txq_info, - schedule_order); - air_info = to_airtime_info(&first_txqi->txq); + list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], + schedule_order) { + if (iter == txqi) + break; - if (air_sched->v_t < air_info->v_t) - airtime_catchup_v_t(air_sched, air_info->v_t, now); + if (!iter->txq.sta) { + list_move_tail(&iter->schedule_order, + &local->active_txqs[ac]); + continue; + } + sta = container_of(iter->txq.sta, struct sta_info, sta); + if (sta->airtime[ac].deficit < 0) + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); } - air_info = to_airtime_info(&txqi->txq); - if (air_info->v_t <= air_sched->v_t) { - air_sched->last_schedule_activity = now; - ret = true; - } + sta = container_of(txqi->txq.sta, struct sta_info, sta); + if (sta->airtime[ac].deficit >= 0) + goto out; + + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); + spin_unlock_bh(&local->active_txq_lock[ac]); + return false; out: - spin_unlock_bh(&air_sched->lock); - return ret; + if (!list_empty(&txqi->schedule_order)) + list_del_init(&txqi->schedule_order); + spin_unlock_bh(&local->active_txq_lock[ac]); + + return true; } EXPORT_SYMBOL(ieee80211_txq_may_transmit); void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) { struct ieee80211_local *local = hw_to_local(hw); - struct airtime_sched_info *air_sched = &local->airtime[ac]; - spin_lock_bh(&air_sched->lock); - air_sched->schedule_pos = NULL; - spin_unlock_bh(&air_sched->lock); + spin_lock_bh(&local->active_txq_lock[ac]); + local->schedule_round[ac]++; + spin_unlock_bh(&local->active_txq_lock[ac]); } EXPORT_SYMBOL(ieee80211_txq_schedule_start); -- cgit v1.2.3 From ecad3b0b99bff7247a11f8c7cb19ac9b0cb28b09 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Mon, 23 May 2022 18:55:58 +0530 Subject: wifi: cfg80211: Increase akm_suites array size in cfg80211_crypto_settings Increase akm_suites array size in struct cfg80211_crypto_settings to 10 and advertise the capability to userspace. This allows userspace to send more than two AKMs to driver in netlink commands such as NL80211_CMD_CONNECT. This capability is needed for implementing WPA3-Personal transition mode correctly with any driver that handles roaming internally. Currently, the possible AKMs for multi-AKM connect can include PSK, PSK-SHA-256, SAE, FT-PSK and FT-SAE. Since the count is already 5, increasing the akm_suites array size to 10 should be reasonable for future usecases. Signed-off-by: Veerendranath Jakkam Link: https://lore.kernel.org/r/1653312358-12321-1-git-send-email-quic_vjakkam@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 12 ++++++++---- include/net/cfg80211.h | 11 ++++++++++- include/uapi/linux/nl80211.h | 14 ++++++++++++++ net/wireless/core.c | 6 ++++++ net/wireless/nl80211.c | 7 ++++++- 5 files changed, 44 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 3d734a7a5ba8..0fad53693292 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -241,6 +241,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; + int n; if (!qtnf_cmd_start_ap_can_fit(vif, s)) return -E2BIG; @@ -280,8 +281,9 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) aen->ciphers_pairwise[i] = cpu_to_le32(s->crypto.ciphers_pairwise[i]); - aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites); - for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + n = min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites); + aen->n_akm_suites = cpu_to_le32(n); + for (i = 0; i < n; i++) aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]); aen->control_port = s->crypto.control_port; aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt; @@ -2076,6 +2078,7 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; + int n; u32 connect_flags = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2132,9 +2135,10 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, aen->ciphers_pairwise[i] = cpu_to_le32(sme->crypto.ciphers_pairwise[i]); - aen->n_akm_suites = cpu_to_le32(sme->crypto.n_akm_suites); + n = min(QLINK_MAX_NR_AKM_SUITES, sme->crypto.n_akm_suites); + aen->n_akm_suites = cpu_to_le32(n); - for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + for (i = 0; i < n; i++) aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]); aen->control_port = sme->crypto.control_port; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 87ebed6a48bd..6bc161d653f3 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1063,6 +1063,7 @@ struct survey_info { }; #define CFG80211_MAX_WEP_KEYS 4 +#define CFG80211_MAX_NUM_AKM_SUITES 10 /** * struct cfg80211_crypto_settings - Crypto settings @@ -1114,7 +1115,7 @@ struct cfg80211_crypto_settings { int n_ciphers_pairwise; u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; int n_akm_suites; - u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; + u32 akm_suites[CFG80211_MAX_NUM_AKM_SUITES]; bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; @@ -5200,6 +5201,13 @@ struct wiphy_iftype_akm_suites { * @ema_max_profile_periodicity: maximum profile periodicity supported by * the driver. Setting this field to a non-zero value indicates that the * driver supports enhanced multi-BSSID advertisements (EMA AP). + * @max_num_akm_suites: maximum number of AKM suites allowed for + * configuration through %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_START_AP. Set to NL80211_MAX_NR_AKM_SUITES if not set by + * driver. If set by driver minimum allowed value is + * NL80211_MAX_NR_AKM_SUITES in order to avoid compatibility issues with + * legacy userspace and maximum allowed value is + * CFG80211_MAX_NUM_AKM_SUITES. */ struct wiphy { struct mutex mtx; @@ -5346,6 +5354,7 @@ struct wiphy { u8 mbssid_max_interfaces; u8 ema_max_profile_periodicity; + u16 max_num_akm_suites; char priv[] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 89f64f46b98d..279f9715919e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2694,6 +2694,13 @@ enum nl80211_commands { * connection. Used with %NL80211_CMD_CONNECT. If this attribute is not * included in NL80211_CMD_CONNECT drivers must not perform MLO connection. * + * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of + * AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_START_AP in %NL80211_CMD_GET_WIPHY response. If this + * attribute is not present userspace shall consider maximum number of AKM + * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum + * number prior to the introduction of this attribute. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3214,6 +3221,8 @@ enum nl80211_attrs { NL80211_ATTR_MLO_SUPPORT, + NL80211_ATTR_MAX_NUM_AKM_SUITES, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3268,6 +3277,11 @@ enum nl80211_attrs { #define NL80211_HE_MIN_CAPABILITY_LEN 16 #define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 + +/* + * NL80211_MAX_NR_AKM_SUITES is obsolete when %NL80211_ATTR_MAX_NUM_AKM_SUITES + * present in %NL80211_CMD_GET_WIPHY response. + */ #define NL80211_MAX_NR_AKM_SUITES 2 #define NL80211_EHT_MIN_CAPABILITY_LEN 13 #define NL80211_EHT_MAX_CAPABILITY_LEN 51 diff --git a/net/wireless/core.c b/net/wireless/core.c index 3e5d12040726..6b5321bb1176 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -913,6 +913,12 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; #endif + if (!wiphy->max_num_akm_suites) + wiphy->max_num_akm_suites = NL80211_MAX_NR_AKM_SUITES; + else if (wiphy->max_num_akm_suites < NL80211_MAX_NR_AKM_SUITES || + wiphy->max_num_akm_suites > CFG80211_MAX_NUM_AKM_SUITES) + return -EINVAL; + /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b583a76ef492..e2b6740268a6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -798,6 +798,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, }; /* policy for the key attributes */ @@ -2932,6 +2933,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) goto nla_put_failure; + if (nla_put_u16(msg, NL80211_ATTR_MAX_NUM_AKM_SUITES, + rdev->wiphy.max_num_akm_suites)) + goto nla_put_failure; + /* done */ state->split_start = 0; break; @@ -10431,7 +10436,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, if (len % sizeof(u32)) return -EINVAL; - if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES) + if (settings->n_akm_suites > rdev->wiphy.max_num_akm_suites) return -EINVAL; memcpy(settings->akm_suites, data, len); -- cgit v1.2.3 From 8bc65d38ee466897a264c9e336fe21058818b1b1 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Sun, 22 May 2022 23:49:04 -0700 Subject: wifi: nl80211: retrieve EHT related elements in AP mode Add support to retrieve EHT capabilities and EHT operation elements passed by the userspace in the beacon template and store the pointers in struct cfg80211_ap_settings to be used by the drivers. Co-developed-by: Vikram Kandukuri Signed-off-by: Vikram Kandukuri Co-developed-by: Veerendranath Jakkam Signed-off-by: Veerendranath Jakkam Signed-off-by: Aloka Dixit Link: https://lore.kernel.org/r/20220523064904.28523-1-quic_alokad@quicinc.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ net/wireless/nl80211.c | 26 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6bc161d653f3..140354f5f15b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1296,6 +1296,8 @@ struct cfg80211_unsol_bcast_probe_resp { * @ht_cap: HT capabilities (or %NULL if HT isn't enabled) * @vht_cap: VHT capabilities (or %NULL if VHT isn't enabled) * @he_cap: HE capabilities (or %NULL if HE isn't enabled) + * @eht_cap: EHT capabilities (or %NULL if EHT isn't enabled) + * @eht_oper: EHT operation IE (or %NULL if EHT isn't enabled) * @ht_required: stations must support HT * @vht_required: stations must support VHT * @twt_responder: Enable Target Wait Time @@ -1332,6 +1334,8 @@ struct cfg80211_ap_settings { const struct ieee80211_vht_cap *vht_cap; const struct ieee80211_he_cap_elem *he_cap; const struct ieee80211_he_operation *he_oper; + const struct ieee80211_eht_cap_elem *eht_cap; + const struct ieee80211_eht_operation *eht_oper; bool ht_required, vht_required, he_required, sae_h2e_required; bool twt_responder; u32 flags; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e2b6740268a6..eda2ad029c90 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5522,7 +5522,7 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params, * HT/VHT requirements/capabilities, we parse them out of the IEs for the * benefit of drivers that rebuild IEs in the firmware. */ -static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) +static int nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) { const struct cfg80211_beacon_data *bcn = ¶ms->beacon; size_t ies_len = bcn->tail_len; @@ -5548,6 +5548,26 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len); if (cap && cap->datalen >= sizeof(*params->he_oper) + 1) params->he_oper = (void *)(cap->data + 1); + cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_CAPABILITY, ies, ies_len); + if (cap) { + if (!cap->datalen) + return -EINVAL; + params->eht_cap = (void *)(cap->data + 1); + if (!ieee80211_eht_capa_size_ok((const u8 *)params->he_cap, + (const u8 *)params->eht_cap, + cap->datalen - 1)) + return -EINVAL; + } + cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ies, ies_len); + if (cap) { + if (!cap->datalen) + return -EINVAL; + params->eht_oper = (void *)(cap->data + 1); + if (!ieee80211_eht_oper_size_ok((const u8 *)params->eht_oper, + cap->datalen - 1)) + return -EINVAL; + } + return 0; } static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, @@ -5873,7 +5893,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } - nl80211_calculate_ap_params(params); + err = nl80211_calculate_ap_params(params); + if (err) + goto out_unlock; if (info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]) params->flags = nla_get_u32( -- cgit v1.2.3 From e918c137db4083e59866d2aaa603887cbd9969bf Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 30 Jun 2022 15:17:57 -0700 Subject: net: remove SK_RECLAIM_THRESHOLD and SK_RECLAIM_CHUNK There are no more users for the mentioned macros, just drop them. Signed-off-by: Paolo Abeni Signed-off-by: Mat Martineau Signed-off-by: David S. Miller --- include/net/sock.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 40bbd0e8925b..0dd43c3df49b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1619,11 +1619,6 @@ static inline void sk_mem_charge(struct sock *sk, int size) sk->sk_forward_alloc -= size; } -/* the following macros control memory reclaiming in mptcp_rmem_uncharge() - */ -#define SK_RECLAIM_THRESHOLD (1 << 21) -#define SK_RECLAIM_CHUNK (1 << 20) - static inline void sk_mem_uncharge(struct sock *sk, int size) { if (!sk_has_account(sk)) -- cgit v1.2.3 From b48dbb998d70b7f48c2ec0a15c3cf47136808e4e Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sun, 12 Jun 2022 13:42:32 +0900 Subject: 9p fid refcount: add p9_fid_get/put wrappers I was recently reminded that it is not clear that p9_client_clunk() was actually just decrementing refcount and clunking only when that reaches zero: make it clear through a set of helpers. This will also allow instrumenting refcounting better for debugging next patch Link: https://lkml.kernel.org/r/20220612085330.1451496-5-asmadeus@codewreck.org Reviewed-by: Tyler Hicks Reviewed-by: Christian Schoenebeck Signed-off-by: Dominique Martinet --- fs/9p/fid.c | 18 +++++++++--------- fs/9p/fid.h | 2 +- fs/9p/vfs_addr.c | 4 ++-- fs/9p/vfs_dentry.c | 4 ++-- fs/9p/vfs_dir.c | 2 +- fs/9p/vfs_file.c | 4 ++-- fs/9p/vfs_inode.c | 48 ++++++++++++++++++++++++------------------------ fs/9p/vfs_inode_dotl.c | 42 +++++++++++++++++++++--------------------- fs/9p/vfs_super.c | 6 +++--- fs/9p/xattr.c | 8 ++++---- include/net/9p/client.h | 28 ++++++++++++++++++++++++++++ net/9p/client.c | 15 +++------------ 12 files changed, 100 insertions(+), 81 deletions(-) (limited to 'include/net') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index e8fad28fc5bd..d792499349c4 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -56,7 +56,7 @@ static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid) h = (struct hlist_head *)&inode->i_private; hlist_for_each_entry(fid, h, ilist) { if (uid_eq(fid->uid, uid)) { - refcount_inc(&fid->count); + p9_fid_get(fid); ret = fid; break; } @@ -104,7 +104,7 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) hlist_for_each_entry(fid, h, dlist) { if (any || uid_eq(fid->uid, uid)) { ret = fid; - refcount_inc(&ret->count); + p9_fid_get(ret); break; } } @@ -172,7 +172,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, old_fid = fid; fid = p9_client_walk(old_fid, 1, &dentry->d_name.name, 1); - p9_client_clunk(old_fid); + p9_fid_put(old_fid); goto fid_out; } up_read(&v9ses->rename_sem); @@ -194,7 +194,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, if (IS_ERR(root_fid)) return root_fid; - refcount_inc(&root_fid->count); + p9_fid_get(root_fid); v9fs_fid_add(dentry->d_sb->s_root, root_fid); } /* If we are root ourself just return that */ @@ -225,7 +225,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, old_fid == root_fid /* clone */); /* non-cloning walk will return the same fid */ if (fid != old_fid) { - p9_client_clunk(old_fid); + p9_fid_put(old_fid); old_fid = fid; } if (IS_ERR(fid)) { @@ -240,11 +240,11 @@ fid_out: spin_lock(&dentry->d_lock); if (d_unhashed(dentry)) { spin_unlock(&dentry->d_lock); - p9_client_clunk(fid); + p9_fid_put(fid); fid = ERR_PTR(-ENOENT); } else { __add_fid(dentry, fid); - refcount_inc(&fid->count); + p9_fid_get(fid); spin_unlock(&dentry->d_lock); } } @@ -301,7 +301,7 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) fid = clone_fid(ofid); if (IS_ERR(fid)) goto error_out; - p9_client_clunk(ofid); + p9_fid_put(ofid); /* * writeback fid will only be used to write back the * dirty pages. We always request for the open fid in read-write @@ -310,7 +310,7 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) */ err = p9_client_open(fid, O_RDWR); if (err < 0) { - p9_client_clunk(fid); + p9_fid_put(fid); fid = ERR_PTR(err); goto error_out; } diff --git a/fs/9p/fid.h b/fs/9p/fid.h index f7f33509e169..3168dfad510e 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -29,7 +29,7 @@ static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry) return fid; nfid = clone_fid(fid); - p9_client_clunk(fid); + p9_fid_put(fid); return nfid; } #endif diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index d0833fa69faf..47b9a1122f34 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -73,7 +73,7 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file) BUG_ON(!fid); } - refcount_inc(&fid->count); + p9_fid_get(fid); rreq->netfs_priv = fid; return 0; } @@ -86,7 +86,7 @@ static void v9fs_free_request(struct netfs_io_request *rreq) { struct p9_fid *fid = rreq->netfs_priv; - p9_client_clunk(fid); + p9_fid_put(fid); } /** diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 1c609e99d280..f89f01734587 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -54,7 +54,7 @@ static void v9fs_dentry_release(struct dentry *dentry) p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n", dentry, dentry); hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata) - p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); + p9_fid_put(hlist_entry(p, struct p9_fid, dlist)); dentry->d_fsdata = NULL; } @@ -85,7 +85,7 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) retval = v9fs_refresh_inode_dotl(fid, inode); else retval = v9fs_refresh_inode(fid, inode); - p9_client_clunk(fid); + p9_fid_put(fid); if (retval == -ENOENT) return 0; diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 958680f7f23e..000fbaae9b18 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -218,7 +218,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) spin_lock(&inode->i_lock); hlist_del(&fid->ilist); spin_unlock(&inode->i_lock); - p9_client_clunk(fid); + p9_fid_put(fid); } if ((filp->f_mode & FMODE_WRITE)) { diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 2573c08f335c..8276f3af35d7 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -63,7 +63,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) err = p9_client_open(fid, omode); if (err < 0) { - p9_client_clunk(fid); + p9_fid_put(fid); return err; } if ((file->f_flags & O_APPEND) && @@ -98,7 +98,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) v9fs_open_fid_add(inode, fid); return 0; out_error: - p9_client_clunk(file->private_data); + p9_fid_put(file->private_data); file->private_data = NULL; return err; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 3d8297714772..bde18776f0c7 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -400,7 +400,7 @@ void v9fs_evict_inode(struct inode *inode) fscache_relinquish_cookie(v9fs_inode_cookie(v9inode), false); /* clunk the fid stashed in writeback_fid */ if (v9inode->writeback_fid) { - p9_client_clunk(v9inode->writeback_fid); + p9_fid_put(v9inode->writeback_fid); v9inode->writeback_fid = NULL; } } @@ -569,7 +569,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) if (v9fs_proto_dotl(v9ses)) retval = p9_client_unlinkat(dfid, dentry->d_name.name, v9fs_at_to_dotl_flags(flags)); - p9_client_clunk(dfid); + p9_fid_put(dfid); if (retval == -EOPNOTSUPP) { /* Try the one based on path */ v9fid = v9fs_fid_clone(dentry); @@ -633,14 +633,14 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, if (IS_ERR(ofid)) { err = PTR_ERR(ofid); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); return ERR_PTR(err); } err = p9_client_fcreate(ofid, name, perm, mode, extension); if (err < 0) { p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); goto error; } @@ -652,7 +652,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); fid = NULL; - p9_client_clunk(dfid); + p9_fid_put(dfid); goto error; } /* @@ -663,20 +663,20 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, err = PTR_ERR(inode); p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); goto error; } v9fs_fid_add(dentry, fid); d_instantiate(dentry, inode); } - p9_client_clunk(dfid); + p9_fid_put(dfid); return ofid; error: if (ofid) - p9_client_clunk(ofid); + p9_fid_put(ofid); if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); return ERR_PTR(err); } @@ -708,7 +708,7 @@ v9fs_vfs_create(struct user_namespace *mnt_userns, struct inode *dir, return PTR_ERR(fid); v9fs_invalidate_inode_attr(dir); - p9_client_clunk(fid); + p9_fid_put(fid); return 0; } @@ -744,7 +744,7 @@ static int v9fs_vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, } if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); return err; } @@ -785,7 +785,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, */ name = dentry->d_name.name; fid = p9_client_walk(dfid, 1, &name, 1); - p9_client_clunk(dfid); + p9_fid_put(dfid); if (fid == ERR_PTR(-ENOENT)) inode = NULL; else if (IS_ERR(fid)) @@ -808,7 +808,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, else if (!IS_ERR(res)) v9fs_fid_add(res, fid); else - p9_client_clunk(fid); + p9_fid_put(fid); } return res; } @@ -891,7 +891,7 @@ out: error: if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); goto out; } @@ -959,7 +959,7 @@ v9fs_vfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, dfid = v9fs_parent_fid(old_dentry); olddirfid = clone_fid(dfid); if (dfid && !IS_ERR(dfid)) - p9_client_clunk(dfid); + p9_fid_put(dfid); if (IS_ERR(olddirfid)) { retval = PTR_ERR(olddirfid); @@ -968,7 +968,7 @@ v9fs_vfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, dfid = v9fs_parent_fid(new_dentry); newdirfid = clone_fid(dfid); - p9_client_clunk(dfid); + p9_fid_put(dfid); if (IS_ERR(newdirfid)) { retval = PTR_ERR(newdirfid); @@ -1020,13 +1020,13 @@ clunk_newdir: d_move(old_dentry, new_dentry); } up_write(&v9ses->rename_sem); - p9_client_clunk(newdirfid); + p9_fid_put(newdirfid); clunk_olddir: - p9_client_clunk(olddirfid); + p9_fid_put(olddirfid); done: - p9_client_clunk(oldfid); + p9_fid_put(oldfid); return retval; } @@ -1060,7 +1060,7 @@ v9fs_vfs_getattr(struct user_namespace *mnt_userns, const struct path *path, return PTR_ERR(fid); st = p9_client_stat(fid); - p9_client_clunk(fid); + p9_fid_put(fid); if (IS_ERR(st)) return PTR_ERR(st); @@ -1136,7 +1136,7 @@ static int v9fs_vfs_setattr(struct user_namespace *mnt_userns, retval = p9_client_wstat(fid, &wstat); if (use_dentry) - p9_client_clunk(fid); + p9_fid_put(fid); if (retval < 0) return retval; @@ -1261,7 +1261,7 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry, return ERR_CAST(fid); st = p9_client_stat(fid); - p9_client_clunk(fid); + p9_fid_put(fid); if (IS_ERR(st)) return ERR_CAST(st); @@ -1308,7 +1308,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, return PTR_ERR(fid); v9fs_invalidate_inode_attr(dir); - p9_client_clunk(fid); + p9_fid_put(fid); return 0; } @@ -1364,7 +1364,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, v9fs_refresh_inode(oldfid, d_inode(old_dentry)); v9fs_invalidate_inode_attr(dir); } - p9_client_clunk(oldfid); + p9_fid_put(oldfid); return retval; } diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index b6eb1160296c..09b124fe349c 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -274,7 +274,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, if (IS_ERR(ofid)) { err = PTR_ERR(ofid); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); goto out; } @@ -286,7 +286,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, if (err) { p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); goto error; } err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags), @@ -294,14 +294,14 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, if (err < 0) { p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n", err); - p9_client_clunk(dfid); + p9_fid_put(dfid); goto error; } v9fs_invalidate_inode_attr(dir); /* instantiate inode and assign the unopened fid to the dentry */ fid = p9_client_walk(dfid, 1, &name, 1); - p9_client_clunk(dfid); + p9_fid_put(dfid); if (IS_ERR(fid)) { err = PTR_ERR(fid); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); @@ -358,10 +358,10 @@ out: error: if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); err_clunk_old_fid: if (ofid) - p9_client_clunk(ofid); + p9_fid_put(ofid); goto out; } @@ -458,9 +458,9 @@ static int v9fs_vfs_mkdir_dotl(struct user_namespace *mnt_userns, v9fs_invalidate_inode_attr(dir); error: if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); v9fs_put_acl(dacl, pacl); - p9_client_clunk(dfid); + p9_fid_put(dfid); return err; } @@ -489,7 +489,7 @@ v9fs_vfs_getattr_dotl(struct user_namespace *mnt_userns, */ st = p9_client_getattr_dotl(fid, P9_STATS_ALL); - p9_client_clunk(fid); + p9_fid_put(fid); if (IS_ERR(st)) return PTR_ERR(st); @@ -603,7 +603,7 @@ int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns, retval = p9_client_setattr(fid, &p9attr); if (retval < 0) { if (use_dentry) - p9_client_clunk(fid); + p9_fid_put(fid); return retval; } @@ -619,12 +619,12 @@ int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns, retval = v9fs_acl_chmod(inode, fid); if (retval < 0) { if (use_dentry) - p9_client_clunk(fid); + p9_fid_put(fid); return retval; } } if (use_dentry) - p9_client_clunk(fid); + p9_fid_put(fid); return 0; } @@ -771,9 +771,9 @@ v9fs_vfs_symlink_dotl(struct user_namespace *mnt_userns, struct inode *dir, error: if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); - p9_client_clunk(dfid); + p9_fid_put(dfid); return err; } @@ -803,14 +803,14 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, oldfid = v9fs_fid_lookup(old_dentry); if (IS_ERR(oldfid)) { - p9_client_clunk(dfid); + p9_fid_put(dfid); return PTR_ERR(oldfid); } err = p9_client_link(dfid, oldfid, dentry->d_name.name); - p9_client_clunk(dfid); - p9_client_clunk(oldfid); + p9_fid_put(dfid); + p9_fid_put(oldfid); if (err < 0) { p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); return err; @@ -826,7 +826,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, return PTR_ERR(fid); v9fs_refresh_inode_dotl(fid, d_inode(old_dentry)); - p9_client_clunk(fid); + p9_fid_put(fid); } ihold(d_inode(old_dentry)); d_instantiate(dentry, d_inode(old_dentry)); @@ -924,9 +924,9 @@ v9fs_vfs_mknod_dotl(struct user_namespace *mnt_userns, struct inode *dir, } error: if (fid) - p9_client_clunk(fid); + p9_fid_put(fid); v9fs_put_acl(dacl, pacl); - p9_client_clunk(dfid); + p9_fid_put(dfid); return err; } @@ -956,7 +956,7 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry, if (IS_ERR(fid)) return ERR_CAST(fid); retval = p9_client_readlink(fid, &target); - p9_client_clunk(fid); + p9_fid_put(fid); if (retval) return ERR_PTR(retval); set_delayed_call(done, kfree_link, target); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 97e23b4e6982..bf350fad9500 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -190,7 +190,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, return dget(sb->s_root); clunk_fid: - p9_client_clunk(fid); + p9_fid_put(fid); v9fs_session_close(v9ses); free_session: kfree(v9ses); @@ -203,7 +203,7 @@ release_sb: * attached the fid to dentry so it won't get clunked * automatically. */ - p9_client_clunk(fid); + p9_fid_put(fid); deactivate_locked_super(sb); return ERR_PTR(retval); } @@ -270,7 +270,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) } res = simple_statfs(dentry, buf); done: - p9_client_clunk(fid); + p9_fid_put(fid); return res; } diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c index a824441b95a2..1f9298a4bd42 100644 --- a/fs/9p/xattr.c +++ b/fs/9p/xattr.c @@ -44,7 +44,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name, if (err) retval = err; } - p9_client_clunk(attr_fid); + p9_fid_put(attr_fid); return retval; } @@ -71,7 +71,7 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, if (IS_ERR(fid)) return PTR_ERR(fid); ret = v9fs_fid_xattr_get(fid, name, buffer, buffer_size); - p9_client_clunk(fid); + p9_fid_put(fid); return ret; } @@ -98,7 +98,7 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name, if (IS_ERR(fid)) return PTR_ERR(fid); ret = v9fs_fid_xattr_set(fid, name, value, value_len, flags); - p9_client_clunk(fid); + p9_fid_put(fid); return ret; } @@ -128,7 +128,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, retval); else p9_client_write(fid, 0, &from, &retval); - err = p9_client_clunk(fid); + err = p9_fid_put(fid); if (!retval && err) retval = err; return retval; diff --git a/include/net/9p/client.h b/include/net/9p/client.h index ec1d1706f43c..eabb53992350 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -237,6 +237,34 @@ static inline int p9_req_try_get(struct p9_req_t *r) int p9_req_put(struct p9_req_t *r); +/* fid reference counting helpers: + * - fids used for any length of time should always be referenced through + * p9_fid_get(), and released with p9_fid_put() + * - v9fs_fid_lookup() or similar will automatically call get for you + * and also require a put + * - the *_fid_add() helpers will stash the fid in the inode, + * at which point it is the responsibility of evict_inode() + * to call the put + * - the last put will automatically send a clunk to the server + */ +static inline struct p9_fid *p9_fid_get(struct p9_fid *fid) +{ + refcount_inc(&fid->count); + + return fid; +} + +static inline int p9_fid_put(struct p9_fid *fid) +{ + if (!fid || IS_ERR(fid)) + return 0; + + if (!refcount_dec_and_test(&fid->count)) + return 0; + + return p9_client_clunk(fid); +} + void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status); int p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, diff --git a/net/9p/client.c b/net/9p/client.c index 8bba0d9cf975..f3eb280c7d9d 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1228,7 +1228,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, clunk_fid: kfree(wqids); - p9_client_clunk(fid); + p9_fid_put(fid); fid = NULL; error: @@ -1459,15 +1459,6 @@ int p9_client_clunk(struct p9_fid *fid) struct p9_req_t *req; int retries = 0; - if (!fid || IS_ERR(fid)) { - pr_warn("%s (%d): Trying to clunk with invalid fid\n", - __func__, task_pid_nr(current)); - dump_stack(); - return 0; - } - if (!refcount_dec_and_test(&fid->count)) - return 0; - again: p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid, retries); @@ -1519,7 +1510,7 @@ int p9_client_remove(struct p9_fid *fid) p9_tag_remove(clnt, req); error: if (err == -ERESTARTSYS) - p9_client_clunk(fid); + p9_fid_put(fid); else p9_fid_destroy(fid); return err; @@ -2042,7 +2033,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, attr_fid->fid, *attr_size); return attr_fid; clunk_fid: - p9_client_clunk(attr_fid); + p9_fid_put(attr_fid); attr_fid = NULL; error: if (attr_fid && attr_fid != file_fid) -- cgit v1.2.3 From 286c171b86ebc693e18b485dde3a3fc470af37bd Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 13 Jun 2022 08:32:06 +0900 Subject: 9p fid refcount: add a 9p_fid_ref tracepoint This adds a tracepoint event for 9p fid lifecycle tracing: when a fid is created, its reference count increased/decreased, and freed. The new 9p_fid_ref tracepoint should help anyone wishing to debug any fid problem such as missing clunk (destroy) or use-after-free. Link: https://lkml.kernel.org/r/20220612085330.1451496-6-asmadeus@codewreck.org Signed-off-by: Dominique Martinet --- include/net/9p/client.h | 13 +++++++++++++ include/trace/events/9p.h | 48 +++++++++++++++++++++++++++++++++++++++++++++++ net/9p/client.c | 20 +++++++++++++++++++- 3 files changed, 80 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index eabb53992350..8f629f1df865 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -11,6 +11,7 @@ #include #include +#include /* Number of requests per row */ #define P9_ROW_MAXTAG 255 @@ -237,6 +238,12 @@ static inline int p9_req_try_get(struct p9_req_t *r) int p9_req_put(struct p9_req_t *r); +/* We cannot have the real tracepoints in header files, + * use a wrapper function */ +DECLARE_TRACEPOINT(9p_fid_ref); +void do_trace_9p_fid_get(struct p9_fid *fid); +void do_trace_9p_fid_put(struct p9_fid *fid); + /* fid reference counting helpers: * - fids used for any length of time should always be referenced through * p9_fid_get(), and released with p9_fid_put() @@ -249,6 +256,9 @@ int p9_req_put(struct p9_req_t *r); */ static inline struct p9_fid *p9_fid_get(struct p9_fid *fid) { + if (tracepoint_enabled(9p_fid_ref)) + do_trace_9p_fid_get(fid); + refcount_inc(&fid->count); return fid; @@ -259,6 +269,9 @@ static inline int p9_fid_put(struct p9_fid *fid) if (!fid || IS_ERR(fid)) return 0; + if (tracepoint_enabled(9p_fid_ref)) + do_trace_9p_fid_put(fid); + if (!refcount_dec_and_test(&fid->count)) return 0; diff --git a/include/trace/events/9p.h b/include/trace/events/9p.h index 78c5608a1648..4dfa6d7f83ba 100644 --- a/include/trace/events/9p.h +++ b/include/trace/events/9p.h @@ -77,6 +77,13 @@ EM( P9_TWSTAT, "P9_TWSTAT" ) \ EMe(P9_RWSTAT, "P9_RWSTAT" ) + +#define P9_FID_REFTYPE \ + EM( P9_FID_REF_CREATE, "create " ) \ + EM( P9_FID_REF_GET, "get " ) \ + EM( P9_FID_REF_PUT, "put " ) \ + EMe(P9_FID_REF_DESTROY, "destroy" ) + /* Define EM() to export the enums to userspace via TRACE_DEFINE_ENUM() */ #undef EM #undef EMe @@ -84,6 +91,21 @@ #define EMe(a, b) TRACE_DEFINE_ENUM(a); P9_MSG_T +P9_FID_REFTYPE + +/* And also use EM/EMe to define helper enums -- once */ +#ifndef __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE +#define __9P_DECLARE_TRACE_ENUMS_ONLY_ONCE +#undef EM +#undef EMe +#define EM(a, b) a, +#define EMe(a, b) a + +enum p9_fid_reftype { + P9_FID_REFTYPE +} __mode(byte); + +#endif /* * Now redefine the EM() and EMe() macros to map the enums to the strings @@ -96,6 +118,8 @@ P9_MSG_T #define show_9p_op(type) \ __print_symbolic(type, P9_MSG_T) +#define show_9p_fid_reftype(type) \ + __print_symbolic(type, P9_FID_REFTYPE) TRACE_EVENT(9p_client_req, TP_PROTO(struct p9_client *clnt, int8_t type, int tag), @@ -168,6 +192,30 @@ TRACE_EVENT(9p_protocol_dump, __entry->tag, 0, __entry->line, 16, __entry->line + 16) ); + +TRACE_EVENT(9p_fid_ref, + TP_PROTO(struct p9_fid *fid, __u8 type), + + TP_ARGS(fid, type), + + TP_STRUCT__entry( + __field( int, fid ) + __field( int, refcount ) + __field( __u8, type ) + ), + + TP_fast_assign( + __entry->fid = fid->fid; + __entry->refcount = refcount_read(&fid->count); + __entry->type = type; + ), + + TP_printk("%s fid %d, refcount %d", + show_9p_fid_reftype(__entry->type), + __entry->fid, __entry->refcount) +); + + #endif /* _TRACE_9P_H */ /* This part must be outside protection */ diff --git a/net/9p/client.c b/net/9p/client.c index f3eb280c7d9d..dfe8beb864fc 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -907,8 +907,10 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) GFP_NOWAIT); spin_unlock_irq(&clnt->lock); idr_preload_end(); - if (!ret) + if (!ret) { + trace_9p_fid_ref(fid, P9_FID_REF_CREATE); return fid; + } kfree(fid); return NULL; @@ -920,6 +922,7 @@ static void p9_fid_destroy(struct p9_fid *fid) unsigned long flags; p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid); + trace_9p_fid_ref(fid, P9_FID_REF_DESTROY); clnt = fid->clnt; spin_lock_irqsave(&clnt->lock, flags); idr_remove(&clnt->fids, fid->fid); @@ -928,6 +931,21 @@ static void p9_fid_destroy(struct p9_fid *fid) kfree(fid); } +/* We also need to export tracepoint symbols for tracepoint_enabled() */ +EXPORT_TRACEPOINT_SYMBOL(9p_fid_ref); + +void do_trace_9p_fid_get(struct p9_fid *fid) +{ + trace_9p_fid_ref(fid, P9_FID_REF_GET); +} +EXPORT_SYMBOL(do_trace_9p_fid_get); + +void do_trace_9p_fid_put(struct p9_fid *fid) +{ + trace_9p_fid_ref(fid, P9_FID_REF_PUT); +} +EXPORT_SYMBOL(do_trace_9p_fid_put); + static int p9_client_version(struct p9_client *c) { int err = 0; -- cgit v1.2.3 From 092f875131dcdbd8f48b2ece9416225a141e656b Mon Sep 17 00:00:00 2001 From: Prasanna Vengateshan Date: Fri, 1 Jul 2022 20:30:20 +0530 Subject: net: dsa: tag_ksz: add tag handling for Microchip LAN937x The Microchip LAN937X switches have a tagging protocol which is very similar to KSZ tagging. So that the implementation is added to tag_ksz.c and reused common APIs Signed-off-by: Prasanna Vengateshan Signed-off-by: Arun Ramadoss Reviewed-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 4 ++-- net/dsa/tag_ksz.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/dsa.h b/include/net/dsa.h index ea7bf007f34f..b902b31bebce 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -54,6 +54,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_RTL8_4_VALUE 24 #define DSA_TAG_PROTO_RTL8_4T_VALUE 25 #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26 +#define DSA_TAG_PROTO_LAN937X_VALUE 27 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -83,6 +84,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_RTL8_4 = DSA_TAG_PROTO_RTL8_4_VALUE, DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE, DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE, + DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE, }; struct dsa_switch; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 63853fff4e2f..3eef72ce99a4 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -87,10 +87,10 @@ config NET_DSA_TAG_MTK Mediatek switches. config NET_DSA_TAG_KSZ - tristate "Tag driver for Microchip 8795/9477/9893 families of switches" + tristate "Tag driver for Microchip 8795/937x/9477/9893 families of switches" help Say Y if you want to enable support for tagging frames for the - Microchip 8795/9477/9893 families of switches. + Microchip 8795/937x/9477/9893 families of switches. config NET_DSA_TAG_OCELOT tristate "Tag driver for Ocelot family of switches, using NPI port" diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 3509fc967ca9..38fa19c1e2d5 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -193,10 +193,69 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); +/* For xmit, 2 bytes are added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0 : represents tag override, lookup and valid + * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) + * + * For rcv, 1 byte is added before FCS. + * --------------------------------------------------------------------------- + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --------------------------------------------------------------------------- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x07=port8) + */ +#define LAN937X_EGRESS_TAG_LEN 2 + +#define LAN937X_TAIL_TAG_BLOCKING_OVERRIDE BIT(11) +#define LAN937X_TAIL_TAG_LOOKUP BIT(12) +#define LAN937X_TAIL_TAG_VALID BIT(13) +#define LAN937X_TAIL_TAG_PORT_MASK 7 + +static struct sk_buff *lan937x_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + const struct ethhdr *hdr = eth_hdr(skb); + __be16 *tag; + u16 val; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + return NULL; + + tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN); + + val = BIT(dp->index); + + if (is_link_local_ether_addr(hdr->h_dest)) + val |= LAN937X_TAIL_TAG_BLOCKING_OVERRIDE; + + /* Tail tag valid bit - This bit should always be set by the CPU */ + val |= LAN937X_TAIL_TAG_VALID; + + put_unaligned_be16(val, tag); + + return skb; +} + +static const struct dsa_device_ops lan937x_netdev_ops = { + .name = "lan937x", + .proto = DSA_TAG_PROTO_LAN937X, + .xmit = lan937x_xmit, + .rcv = ksz9477_rcv, + .needed_tailroom = LAN937X_EGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(lan937x_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X); + static struct dsa_tag_driver *dsa_tag_driver_array[] = { &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), + &DSA_TAG_DRIVER_NAME(lan937x_netdev_ops), }; module_dsa_tag_drivers(dsa_tag_driver_array); -- cgit v1.2.3 From d7be266adbfd3aca6965ea6a0c36b2c3d8fc9fc8 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 4 Jul 2022 22:02:40 +0300 Subject: net: sched: provide shim definitions for taprio_offload_{get,free} All callers of taprio_offload_get() and taprio_offload_free() prior to the blamed commit are conditionally compiled based on CONFIG_NET_SCH_TAPRIO. felix_vsc9959.c is different; it provides vsc9959_qos_port_tas_set() even when taprio is compiled out. Provide shim definitions for the functions exported by taprio so that felix_vsc9959.c is able to compile. vsc9959_qos_port_tas_set() in that case is dead code anyway, and ocelot_port->taprio remains NULL, which is fine for the rest of the logic. Fixes: 1c9017e44af2 ("net: dsa: felix: keep reference on entire tc-taprio config") Reported-by: Colin Foster Signed-off-by: Vladimir Oltean Tested-by: Colin Foster Acked-by: Vinicius Costa Gomes Link: https://lore.kernel.org/r/20220704190241.1288847-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- include/net/pkt_sched.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include/net') diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 44a35531952e..3372a1f67cf4 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -173,11 +173,28 @@ struct tc_taprio_qopt_offload { struct tc_taprio_sched_entry entries[]; }; +#if IS_ENABLED(CONFIG_NET_SCH_TAPRIO) + /* Reference counting */ struct tc_taprio_qopt_offload *taprio_offload_get(struct tc_taprio_qopt_offload *offload); void taprio_offload_free(struct tc_taprio_qopt_offload *offload); +#else + +/* Reference counting */ +static inline struct tc_taprio_qopt_offload * +taprio_offload_get(struct tc_taprio_qopt_offload *offload) +{ + return NULL; +} + +static inline void taprio_offload_free(struct tc_taprio_qopt_offload *offload) +{ +} + +#endif + /* Ensure skb_mstamp_ns, which might have been populated with the txtime, is * not mistaken for a software timestamp, because this will otherwise prevent * the dispatch of hardware timestamps to the socket. -- cgit v1.2.3 From 88527790c079fb1ea41cbcfa4450ee37906a2fb0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 5 Jul 2022 16:59:24 -0700 Subject: tls: rx: add sockopt for enabling optimistic decrypt with TLS 1.3 Since optimisitic decrypt may add extra load in case of retries require socket owner to explicitly opt-in. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/networking/tls.rst | 18 ++++++++++ include/linux/sockptr.h | 8 +++++ include/net/tls.h | 3 ++ include/uapi/linux/snmp.h | 1 + include/uapi/linux/tls.h | 2 ++ net/tls/tls_main.c | 75 ++++++++++++++++++++++++++++++++++++++++ net/tls/tls_proc.c | 1 + net/tls/tls_sw.c | 21 +++++++---- 8 files changed, 122 insertions(+), 7 deletions(-) (limited to 'include/net') diff --git a/Documentation/networking/tls.rst b/Documentation/networking/tls.rst index be8e10c14b05..7a6643836e42 100644 --- a/Documentation/networking/tls.rst +++ b/Documentation/networking/tls.rst @@ -239,6 +239,19 @@ for the original TCP transmission and TCP retransmissions. To the receiver this will look like TLS records had been tampered with and will result in record authentication failures. +TLS_RX_EXPECT_NO_PAD +~~~~~~~~~~~~~~~~~~~~ + +TLS 1.3 only. Expect the sender to not pad records. This allows the data +to be decrypted directly into user space buffers with TLS 1.3. + +This optimization is safe to enable only if the remote end is trusted, +otherwise it is an attack vector to doubling the TLS processing cost. + +If the record decrypted turns out to had been padded or is not a data +record it will be decrypted again into a kernel buffer without zero copy. +Such events are counted in the ``TlsDecryptRetry`` statistic. + Statistics ========== @@ -264,3 +277,8 @@ TLS implementation exposes the following per-namespace statistics - ``TlsDeviceRxResync`` - number of RX resyncs sent to NICs handling cryptography + +- ``TlsDecryptRetry`` - + number of RX records which had to be re-decrypted due to + ``TLS_RX_EXPECT_NO_PAD`` mis-prediction. Note that this counter will + also increment for non-data records. diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index ea193414298b..d45902fb4cad 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -102,4 +102,12 @@ static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count) return strncpy_from_user(dst, src.user, count); } +static inline int check_zeroed_sockptr(sockptr_t src, size_t offset, + size_t size) +{ + if (!sockptr_is_kernel(src)) + return check_zeroed_user(src.user + offset, size); + return memchr_inv(src.kernel + offset, 0, size) == NULL; +} + #endif /* _LINUX_SOCKPTR_H */ diff --git a/include/net/tls.h b/include/net/tls.h index 8017f1703447..4fc16ca5f469 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -149,6 +149,7 @@ struct tls_sw_context_rx { struct sk_buff *recv_pkt; u8 async_capable:1; + u8 zc_capable:1; atomic_t decrypt_pending; /* protect crypto_wait with decrypt_pending*/ spinlock_t decrypt_compl_lock; @@ -239,6 +240,7 @@ struct tls_context { u8 tx_conf:3; u8 rx_conf:3; u8 zerocopy_sendfile:1; + u8 rx_no_pad:1; int (*push_pending_record)(struct sock *sk, int flags); void (*sk_write_space)(struct sock *sk); @@ -358,6 +360,7 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval, void tls_err_abort(struct sock *sk, int err); int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx); +void tls_update_rx_zc_capable(struct tls_context *tls_ctx); void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); void tls_sw_strparser_done(struct tls_context *tls_ctx); int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index 904909d020e2..1c9152add663 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -344,6 +344,7 @@ enum LINUX_MIB_TLSRXDEVICE, /* TlsRxDevice */ LINUX_MIB_TLSDECRYPTERROR, /* TlsDecryptError */ LINUX_MIB_TLSRXDEVICERESYNC, /* TlsRxDeviceResync */ + LINUX_MIN_TLSDECRYPTRETRY, /* TlsDecryptRetry */ __LINUX_MIB_TLSMAX }; diff --git a/include/uapi/linux/tls.h b/include/uapi/linux/tls.h index bb8f80812b0b..f1157d8f4acd 100644 --- a/include/uapi/linux/tls.h +++ b/include/uapi/linux/tls.h @@ -40,6 +40,7 @@ #define TLS_TX 1 /* Set transmit parameters */ #define TLS_RX 2 /* Set receive parameters */ #define TLS_TX_ZEROCOPY_RO 3 /* TX zerocopy (only sendfile now) */ +#define TLS_RX_EXPECT_NO_PAD 4 /* Attempt opportunistic zero-copy */ /* Supported versions */ #define TLS_VERSION_MINOR(ver) ((ver) & 0xFF) @@ -162,6 +163,7 @@ enum { TLS_INFO_TXCONF, TLS_INFO_RXCONF, TLS_INFO_ZC_RO_TX, + TLS_INFO_RX_NO_PAD, __TLS_INFO_MAX, }; #define TLS_INFO_MAX (__TLS_INFO_MAX - 1) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 2ffede463e4a..1b3efc96db0b 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -533,6 +533,37 @@ static int do_tls_getsockopt_tx_zc(struct sock *sk, char __user *optval, return 0; } +static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval, + int __user *optlen) +{ + struct tls_context *ctx = tls_get_ctx(sk); + unsigned int value; + int err, len; + + if (ctx->prot_info.version != TLS_1_3_VERSION) + return -EINVAL; + + if (get_user(len, optlen)) + return -EFAULT; + if (len < sizeof(value)) + return -EINVAL; + + lock_sock(sk); + err = -EINVAL; + if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW) + value = ctx->rx_no_pad; + release_sock(sk); + if (err) + return err; + + if (put_user(sizeof(value), optlen)) + return -EFAULT; + if (copy_to_user(optval, &value, sizeof(value))) + return -EFAULT; + + return 0; +} + static int do_tls_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen) { @@ -547,6 +578,9 @@ static int do_tls_getsockopt(struct sock *sk, int optname, case TLS_TX_ZEROCOPY_RO: rc = do_tls_getsockopt_tx_zc(sk, optval, optlen); break; + case TLS_RX_EXPECT_NO_PAD: + rc = do_tls_getsockopt_no_pad(sk, optval, optlen); + break; default: rc = -ENOPROTOOPT; break; @@ -718,6 +752,38 @@ static int do_tls_setsockopt_tx_zc(struct sock *sk, sockptr_t optval, return 0; } +static int do_tls_setsockopt_no_pad(struct sock *sk, sockptr_t optval, + unsigned int optlen) +{ + struct tls_context *ctx = tls_get_ctx(sk); + u32 val; + int rc; + + if (ctx->prot_info.version != TLS_1_3_VERSION || + sockptr_is_null(optval) || optlen < sizeof(val)) + return -EINVAL; + + rc = copy_from_sockptr(&val, optval, sizeof(val)); + if (rc) + return -EFAULT; + if (val > 1) + return -EINVAL; + rc = check_zeroed_sockptr(optval, sizeof(val), optlen - sizeof(val)); + if (rc < 1) + return rc == 0 ? -EINVAL : rc; + + lock_sock(sk); + rc = -EINVAL; + if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW) { + ctx->rx_no_pad = val; + tls_update_rx_zc_capable(ctx); + rc = 0; + } + release_sock(sk); + + return rc; +} + static int do_tls_setsockopt(struct sock *sk, int optname, sockptr_t optval, unsigned int optlen) { @@ -736,6 +802,9 @@ static int do_tls_setsockopt(struct sock *sk, int optname, sockptr_t optval, rc = do_tls_setsockopt_tx_zc(sk, optval, optlen); release_sock(sk); break; + case TLS_RX_EXPECT_NO_PAD: + rc = do_tls_setsockopt_no_pad(sk, optval, optlen); + break; default: rc = -ENOPROTOOPT; break; @@ -976,6 +1045,11 @@ static int tls_get_info(const struct sock *sk, struct sk_buff *skb) if (err) goto nla_failure; } + if (ctx->rx_no_pad) { + err = nla_put_flag(skb, TLS_INFO_RX_NO_PAD); + if (err) + goto nla_failure; + } rcu_read_unlock(); nla_nest_end(skb, start); @@ -997,6 +1071,7 @@ static size_t tls_get_info_size(const struct sock *sk) nla_total_size(sizeof(u16)) + /* TLS_INFO_RXCONF */ nla_total_size(sizeof(u16)) + /* TLS_INFO_TXCONF */ nla_total_size(0) + /* TLS_INFO_ZC_RO_TX */ + nla_total_size(0) + /* TLS_INFO_RX_NO_PAD */ 0; return size; diff --git a/net/tls/tls_proc.c b/net/tls/tls_proc.c index feeceb0e4cb4..0c200000cc45 100644 --- a/net/tls/tls_proc.c +++ b/net/tls/tls_proc.c @@ -18,6 +18,7 @@ static const struct snmp_mib tls_mib_list[] = { SNMP_MIB_ITEM("TlsRxDevice", LINUX_MIB_TLSRXDEVICE), SNMP_MIB_ITEM("TlsDecryptError", LINUX_MIB_TLSDECRYPTERROR), SNMP_MIB_ITEM("TlsRxDeviceResync", LINUX_MIB_TLSRXDEVICERESYNC), + SNMP_MIB_ITEM("TlsDecryptRetry", LINUX_MIN_TLSDECRYPTRETRY), SNMP_MIB_SENTINEL }; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 2bac57684429..7592b6519953 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1601,6 +1601,7 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb, if (unlikely(darg->zc && prot->version == TLS_1_3_VERSION && darg->tail != TLS_RECORD_TYPE_DATA)) { darg->zc = false; + TLS_INC_STATS(sock_net(sk), LINUX_MIN_TLSDECRYPTRETRY); return decrypt_skb_update(sk, skb, dest, darg); } @@ -1787,7 +1788,7 @@ int tls_sw_recvmsg(struct sock *sk, timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); zc_capable = !bpf_strp_enabled && !is_kvec && !is_peek && - prot->version != TLS_1_3_VERSION; + ctx->zc_capable; decrypted = 0; while (len && (decrypted + copied < target || ctx->recv_pkt)) { struct tls_decrypt_arg darg = {}; @@ -2269,6 +2270,14 @@ void tls_sw_strparser_arm(struct sock *sk, struct tls_context *tls_ctx) strp_check_rcv(&rx_ctx->strp); } +void tls_update_rx_zc_capable(struct tls_context *tls_ctx) +{ + struct tls_sw_context_rx *rx_ctx = tls_sw_ctx_rx(tls_ctx); + + rx_ctx->zc_capable = tls_ctx->rx_no_pad || + tls_ctx->prot_info.version != TLS_1_3_VERSION; +} + int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) { struct tls_context *tls_ctx = tls_get_ctx(sk); @@ -2504,12 +2513,10 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) if (sw_ctx_rx) { tfm = crypto_aead_tfm(sw_ctx_rx->aead_recv); - if (crypto_info->version == TLS_1_3_VERSION) - sw_ctx_rx->async_capable = 0; - else - sw_ctx_rx->async_capable = - !!(tfm->__crt_alg->cra_flags & - CRYPTO_ALG_ASYNC); + tls_update_rx_zc_capable(ctx); + sw_ctx_rx->async_capable = + crypto_info->version != TLS_1_3_VERSION && + !!(tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC); /* Set up strparser */ memset(&cb, 0, sizeof(cb)); -- cgit v1.2.3 From 2d91ecace6614cf6254001566292b808d7f70a91 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 7 Jul 2022 18:03:09 -0700 Subject: strparser: pad sk_skb_cb to avoid straddling cachelines sk_skb_cb lives within skb->cb[]. skb->cb[] straddles 2 cache lines, each containing 24B of data. The first cache line does not contain much interesting information for users of strparser, so pad things a little. Previously strp_msg->full_len would live in the first cache line and strp_msg->offset in the second. We need to reorder the 8 byte temp_reg with struct tls_msg to prevent a 4B hole which would push the struct over 48B. Signed-off-by: Jakub Kicinski --- include/net/strparser.h | 12 ++++++++---- net/strparser/strparser.c | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/strparser.h b/include/net/strparser.h index a191486eb1e4..88900b05443e 100644 --- a/include/net/strparser.h +++ b/include/net/strparser.h @@ -65,15 +65,19 @@ struct _strp_msg { struct sk_skb_cb { #define SK_SKB_CB_PRIV_LEN 20 unsigned char data[SK_SKB_CB_PRIV_LEN]; + /* align strp on cache line boundary within skb->cb[] */ + unsigned char pad[4]; struct _strp_msg strp; - /* temp_reg is a temporary register used for bpf_convert_data_end_access - * when dst_reg == src_reg. - */ - u64 temp_reg; + + /* strp users' data follows */ struct tls_msg { u8 control; u8 decrypted; } tls; + /* temp_reg is a temporary register used for bpf_convert_data_end_access + * when dst_reg == src_reg. + */ + u64 temp_reg; }; static inline struct strp_msg *strp_msg(struct sk_buff *skb) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index 1a72c67afed5..8299ceb3e373 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -533,6 +533,9 @@ EXPORT_SYMBOL_GPL(strp_check_rcv); static int __init strp_dev_init(void) { + BUILD_BUG_ON(sizeof(struct sk_skb_cb) > + sizeof_field(struct sk_buff, cb)); + strp_wq = create_singlethread_workqueue("kstrp"); if (unlikely(!strp_wq)) return -ENOMEM; -- cgit v1.2.3 From 50a07aa5316181e08fb80914fcf70229a827a2e0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 7 Jul 2022 18:03:10 -0700 Subject: tls: rx: always allocate max possible aad size for decrypt AAD size is either 5 or 13. Really no point complicating the code for the 8B of difference. This will also let us turn the chunked up buffer into a sane struct. Signed-off-by: Jakub Kicinski --- include/net/tls.h | 1 + net/tls/tls_sw.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index 4fc16ca5f469..9394c0459fe8 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -66,6 +66,7 @@ #define MAX_IV_SIZE 16 #define TLS_TAG_SIZE 16 #define TLS_MAX_REC_SEQ_SIZE 8 +#define TLS_MAX_AAD_SIZE TLS_AAD_SPACE_SIZE /* For CCM mode, the full 16-bytes of IV is made of '4' fields of given sizes. * diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index f1777d67527f..377c0f608167 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1450,7 +1450,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, aead_size = sizeof(*aead_req) + crypto_aead_reqsize(ctx->aead_recv); mem_size = aead_size + (nsg * sizeof(struct scatterlist)); - mem_size = mem_size + prot->aad_size; + mem_size = mem_size + TLS_MAX_AAD_SIZE; mem_size = mem_size + MAX_IV_SIZE; mem_size = mem_size + prot->tail_size; @@ -1467,7 +1467,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, sgin = (struct scatterlist *)(mem + aead_size); sgout = sgin + n_sgin; aad = (u8 *)(sgout + n_sgout); - iv = aad + prot->aad_size; + iv = aad + TLS_MAX_AAD_SIZE; tail = iv + MAX_IV_SIZE; /* For CCM based ciphers, first byte of nonce+iv is a constant */ @@ -2474,13 +2474,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) goto free_priv; } - /* Sanity-check the sizes for stack allocations. */ - if (iv_size > MAX_IV_SIZE || nonce_size > MAX_IV_SIZE || - rec_seq_size > TLS_MAX_REC_SEQ_SIZE || tag_size != TLS_TAG_SIZE) { - rc = -EINVAL; - goto free_priv; - } - if (crypto_info->version == TLS_1_3_VERSION) { nonce_size = 0; prot->aad_size = TLS_HEADER_SIZE; @@ -2490,6 +2483,14 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) prot->tail_size = 0; } + /* Sanity-check the sizes for stack allocations. */ + if (iv_size > MAX_IV_SIZE || nonce_size > MAX_IV_SIZE || + rec_seq_size > TLS_MAX_REC_SEQ_SIZE || tag_size != TLS_TAG_SIZE || + prot->aad_size > TLS_MAX_AAD_SIZE) { + rc = -EINVAL; + goto free_priv; + } + prot->version = crypto_info->version; prot->cipher_type = crypto_info->cipher_type; prot->prepend_size = TLS_HEADER_SIZE + nonce_size; -- cgit v1.2.3 From 5879031423089b2e19b769f30fc618af742264c3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 7 Jul 2022 18:03:13 -0700 Subject: tls: create an internal header include/net/tls.h is getting a little long, and is probably hard for driver authors to navigate. Split out the internals into a header which will live under net/tls/. While at it move some static inlines with a single user into the source files, add a few tls_ prefixes and fix spelling of 'proccess'. Signed-off-by: Jakub Kicinski --- include/net/tls.h | 277 +--------------------------------------- net/tls/tls.h | 290 ++++++++++++++++++++++++++++++++++++++++++ net/tls/tls_device.c | 3 +- net/tls/tls_device_fallback.c | 2 + net/tls/tls_main.c | 23 +++- net/tls/tls_proc.c | 2 + net/tls/tls_sw.c | 22 +++- net/tls/tls_toe.c | 2 + 8 files changed, 338 insertions(+), 283 deletions(-) create mode 100644 net/tls/tls.h (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index 9394c0459fe8..8742e13bc362 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -50,6 +49,7 @@ #include #include +struct tls_rec; /* Maximum data size carried in a TLS record */ #define TLS_MAX_PAYLOAD_SIZE ((size_t)1 << 14) @@ -78,13 +78,6 @@ #define TLS_AES_CCM_IV_B0_BYTE 2 #define TLS_SM4_CCM_IV_B0_BYTE 2 -#define __TLS_INC_STATS(net, field) \ - __SNMP_INC_STATS((net)->mib.tls_statistics, field) -#define TLS_INC_STATS(net, field) \ - SNMP_INC_STATS((net)->mib.tls_statistics, field) -#define TLS_DEC_STATS(net, field) \ - SNMP_DEC_STATS((net)->mib.tls_statistics, field) - enum { TLS_BASE, TLS_SW, @@ -93,32 +86,6 @@ enum { TLS_NUM_CONFIG, }; -/* TLS records are maintained in 'struct tls_rec'. It stores the memory pages - * allocated or mapped for each TLS record. After encryption, the records are - * stores in a linked list. - */ -struct tls_rec { - struct list_head list; - int tx_ready; - int tx_flags; - - struct sk_msg msg_plaintext; - struct sk_msg msg_encrypted; - - /* AAD | msg_plaintext.sg.data | sg_tag */ - struct scatterlist sg_aead_in[2]; - /* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */ - struct scatterlist sg_aead_out[2]; - - char content_type; - struct scatterlist sg_content_type; - - char aad_space[TLS_AAD_SPACE_SIZE]; - u8 iv_data[MAX_IV_SIZE]; - struct aead_request aead_req; - u8 aead_req_ctx[]; -}; - struct tx_work { struct delayed_work work; struct sock *sk; @@ -349,44 +316,6 @@ struct tls_offload_context_rx { #define TLS_OFFLOAD_CONTEXT_SIZE_RX \ (sizeof(struct tls_offload_context_rx) + TLS_DRIVER_STATE_SIZE_RX) -struct tls_context *tls_ctx_create(struct sock *sk); -void tls_ctx_free(struct sock *sk, struct tls_context *ctx); -void update_sk_prot(struct sock *sk, struct tls_context *ctx); - -int wait_on_pending_writer(struct sock *sk, long *timeo); -int tls_sk_query(struct sock *sk, int optname, char __user *optval, - int __user *optlen); -int tls_sk_attach(struct sock *sk, int optname, char __user *optval, - unsigned int optlen); -void tls_err_abort(struct sock *sk, int err); - -int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx); -void tls_update_rx_zc_capable(struct tls_context *tls_ctx); -void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); -void tls_sw_strparser_done(struct tls_context *tls_ctx); -int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); -int tls_sw_sendpage_locked(struct sock *sk, struct page *page, - int offset, size_t size, int flags); -int tls_sw_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); -void tls_sw_cancel_work_tx(struct tls_context *tls_ctx); -void tls_sw_release_resources_tx(struct sock *sk); -void tls_sw_free_ctx_tx(struct tls_context *tls_ctx); -void tls_sw_free_resources_rx(struct sock *sk); -void tls_sw_release_resources_rx(struct sock *sk); -void tls_sw_free_ctx_rx(struct tls_context *tls_ctx); -int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int flags, int *addr_len); -bool tls_sw_sock_is_readable(struct sock *sk); -ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, - struct pipe_inode_info *pipe, - size_t len, unsigned int flags); - -int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); -int tls_device_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); -int tls_tx_records(struct sock *sk, int flags); - struct tls_record_info *tls_get_record(struct tls_offload_context_tx *context, u32 seq, u64 *p_record_sn); @@ -400,58 +329,6 @@ static inline u32 tls_record_start_seq(struct tls_record_info *rec) return rec->end_seq - rec->len; } -int tls_push_sg(struct sock *sk, struct tls_context *ctx, - struct scatterlist *sg, u16 first_offset, - int flags); -int tls_push_partial_record(struct sock *sk, struct tls_context *ctx, - int flags); -void tls_free_partial_record(struct sock *sk, struct tls_context *ctx); - -static inline struct tls_msg *tls_msg(struct sk_buff *skb) -{ - struct sk_skb_cb *scb = (struct sk_skb_cb *)skb->cb; - - return &scb->tls; -} - -static inline bool tls_is_partially_sent_record(struct tls_context *ctx) -{ - return !!ctx->partially_sent_record; -} - -static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx) -{ - return tls_ctx->pending_open_record_frags; -} - -static inline bool is_tx_ready(struct tls_sw_context_tx *ctx) -{ - struct tls_rec *rec; - - rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); - if (!rec) - return false; - - return READ_ONCE(rec->tx_ready); -} - -static inline u16 tls_user_config(struct tls_context *ctx, bool tx) -{ - u16 config = tx ? ctx->tx_conf : ctx->rx_conf; - - switch (config) { - case TLS_BASE: - return TLS_CONF_BASE; - case TLS_SW: - return TLS_CONF_SW; - case TLS_HW: - return TLS_CONF_HW; - case TLS_HW_RECORD: - return TLS_CONF_HW_RECORD; - } - return 0; -} - struct sk_buff * tls_validate_xmit_skb(struct sock *sk, struct net_device *dev, struct sk_buff *skb); @@ -470,31 +347,6 @@ static inline bool tls_is_sk_tx_device_offloaded(struct sock *sk) #endif } -static inline bool tls_bigint_increment(unsigned char *seq, int len) -{ - int i; - - for (i = len - 1; i >= 0; i--) { - ++seq[i]; - if (seq[i] != 0) - break; - } - - return (i == -1); -} - -static inline void tls_bigint_subtract(unsigned char *seq, int n) -{ - u64 rcd_sn; - __be64 *p; - - BUILD_BUG_ON(TLS_MAX_REC_SEQ_SIZE != 8); - - p = (__be64 *)seq; - rcd_sn = be64_to_cpu(*p); - *p = cpu_to_be64(rcd_sn - n); -} - static inline struct tls_context *tls_get_ctx(const struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); @@ -505,82 +357,6 @@ static inline struct tls_context *tls_get_ctx(const struct sock *sk) return (__force void *)icsk->icsk_ulp_data; } -static inline void tls_advance_record_sn(struct sock *sk, - struct tls_prot_info *prot, - struct cipher_context *ctx) -{ - if (tls_bigint_increment(ctx->rec_seq, prot->rec_seq_size)) - tls_err_abort(sk, -EBADMSG); - - if (prot->version != TLS_1_3_VERSION && - prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305) - tls_bigint_increment(ctx->iv + prot->salt_size, - prot->iv_size); -} - -static inline void tls_fill_prepend(struct tls_context *ctx, - char *buf, - size_t plaintext_len, - unsigned char record_type) -{ - struct tls_prot_info *prot = &ctx->prot_info; - size_t pkt_len, iv_size = prot->iv_size; - - pkt_len = plaintext_len + prot->tag_size; - if (prot->version != TLS_1_3_VERSION && - prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305) { - pkt_len += iv_size; - - memcpy(buf + TLS_NONCE_OFFSET, - ctx->tx.iv + prot->salt_size, iv_size); - } - - /* we cover nonce explicit here as well, so buf should be of - * size KTLS_DTLS_HEADER_SIZE + KTLS_DTLS_NONCE_EXPLICIT_SIZE - */ - buf[0] = prot->version == TLS_1_3_VERSION ? - TLS_RECORD_TYPE_DATA : record_type; - /* Note that VERSION must be TLS_1_2 for both TLS1.2 and TLS1.3 */ - buf[1] = TLS_1_2_VERSION_MINOR; - buf[2] = TLS_1_2_VERSION_MAJOR; - /* we can use IV for nonce explicit according to spec */ - buf[3] = pkt_len >> 8; - buf[4] = pkt_len & 0xFF; -} - -static inline void tls_make_aad(char *buf, - size_t size, - char *record_sequence, - unsigned char record_type, - struct tls_prot_info *prot) -{ - if (prot->version != TLS_1_3_VERSION) { - memcpy(buf, record_sequence, prot->rec_seq_size); - buf += 8; - } else { - size += prot->tag_size; - } - - buf[0] = prot->version == TLS_1_3_VERSION ? - TLS_RECORD_TYPE_DATA : record_type; - buf[1] = TLS_1_2_VERSION_MAJOR; - buf[2] = TLS_1_2_VERSION_MINOR; - buf[3] = size >> 8; - buf[4] = size & 0xFF; -} - -static inline void xor_iv_with_seq(struct tls_prot_info *prot, char *iv, char *seq) -{ - int i; - - if (prot->version == TLS_1_3_VERSION || - prot->cipher_type == TLS_CIPHER_CHACHA20_POLY1305) { - for (i = 0; i < 8; i++) - iv[i + 4] ^= seq[i]; - } -} - - static inline struct tls_sw_context_rx *tls_sw_ctx_rx( const struct tls_context *tls_ctx) { @@ -617,9 +393,6 @@ static inline bool tls_sw_has_ctx_rx(const struct sock *sk) return !!tls_sw_ctx_rx(ctx); } -void tls_sw_write_space(struct sock *sk, struct tls_context *ctx); -void tls_device_write_space(struct sock *sk, struct tls_context *ctx); - static inline struct tls_offload_context_rx * tls_offload_ctx_rx(const struct tls_context *tls_ctx) { @@ -694,31 +467,11 @@ static inline bool tls_offload_tx_resync_pending(struct sock *sk) return ret; } -int __net_init tls_proc_init(struct net *net); -void __net_exit tls_proc_fini(struct net *net); - -int tls_proccess_cmsg(struct sock *sk, struct msghdr *msg, - unsigned char *record_type); -int decrypt_skb(struct sock *sk, struct sk_buff *skb, - struct scatterlist *sgout); struct sk_buff *tls_encrypt_skb(struct sk_buff *skb); -int tls_sw_fallback_init(struct sock *sk, - struct tls_offload_context_tx *offload_ctx, - struct tls_crypto_info *crypto_info); - #ifdef CONFIG_TLS_DEVICE -void tls_device_init(void); -void tls_device_cleanup(void); void tls_device_sk_destruct(struct sock *sk); -int tls_set_device_offload(struct sock *sk, struct tls_context *ctx); -void tls_device_free_resources_tx(struct sock *sk); -int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx); -void tls_device_offload_cleanup_rx(struct sock *sk); -void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq); void tls_offload_tx_resync_request(struct sock *sk, u32 got_seq, u32 exp_seq); -int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx, - struct sk_buff *skb, struct strp_msg *rxm); static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk) { @@ -727,33 +480,5 @@ static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk) return false; return tls_get_ctx(sk)->rx_conf == TLS_HW; } -#else -static inline void tls_device_init(void) {} -static inline void tls_device_cleanup(void) {} - -static inline int -tls_set_device_offload(struct sock *sk, struct tls_context *ctx) -{ - return -EOPNOTSUPP; -} - -static inline void tls_device_free_resources_tx(struct sock *sk) {} - -static inline int -tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) -{ - return -EOPNOTSUPP; -} - -static inline void tls_device_offload_cleanup_rx(struct sock *sk) {} -static inline void -tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq) {} - -static inline int -tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx, - struct sk_buff *skb, struct strp_msg *rxm) -{ - return 0; -} #endif #endif /* _TLS_OFFLOAD_H */ diff --git a/net/tls/tls.h b/net/tls/tls.h new file mode 100644 index 000000000000..8005ee25157d --- /dev/null +++ b/net/tls/tls.h @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. + * Copyright (c) 2016-2017, Dave Watson . All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TLS_INT_H +#define _TLS_INT_H + +#include +#include +#include +#include + +#define __TLS_INC_STATS(net, field) \ + __SNMP_INC_STATS((net)->mib.tls_statistics, field) +#define TLS_INC_STATS(net, field) \ + SNMP_INC_STATS((net)->mib.tls_statistics, field) +#define TLS_DEC_STATS(net, field) \ + SNMP_DEC_STATS((net)->mib.tls_statistics, field) + +/* TLS records are maintained in 'struct tls_rec'. It stores the memory pages + * allocated or mapped for each TLS record. After encryption, the records are + * stores in a linked list. + */ +struct tls_rec { + struct list_head list; + int tx_ready; + int tx_flags; + + struct sk_msg msg_plaintext; + struct sk_msg msg_encrypted; + + /* AAD | msg_plaintext.sg.data | sg_tag */ + struct scatterlist sg_aead_in[2]; + /* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */ + struct scatterlist sg_aead_out[2]; + + char content_type; + struct scatterlist sg_content_type; + + char aad_space[TLS_AAD_SPACE_SIZE]; + u8 iv_data[MAX_IV_SIZE]; + struct aead_request aead_req; + u8 aead_req_ctx[]; +}; + +int __net_init tls_proc_init(struct net *net); +void __net_exit tls_proc_fini(struct net *net); + +struct tls_context *tls_ctx_create(struct sock *sk); +void tls_ctx_free(struct sock *sk, struct tls_context *ctx); +void update_sk_prot(struct sock *sk, struct tls_context *ctx); + +int wait_on_pending_writer(struct sock *sk, long *timeo); +int tls_sk_query(struct sock *sk, int optname, char __user *optval, + int __user *optlen); +int tls_sk_attach(struct sock *sk, int optname, char __user *optval, + unsigned int optlen); +void tls_err_abort(struct sock *sk, int err); + +int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx); +void tls_update_rx_zc_capable(struct tls_context *tls_ctx); +void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); +void tls_sw_strparser_done(struct tls_context *tls_ctx); +int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); +int tls_sw_sendpage_locked(struct sock *sk, struct page *page, + int offset, size_t size, int flags); +int tls_sw_sendpage(struct sock *sk, struct page *page, + int offset, size_t size, int flags); +void tls_sw_cancel_work_tx(struct tls_context *tls_ctx); +void tls_sw_release_resources_tx(struct sock *sk); +void tls_sw_free_ctx_tx(struct tls_context *tls_ctx); +void tls_sw_free_resources_rx(struct sock *sk); +void tls_sw_release_resources_rx(struct sock *sk); +void tls_sw_free_ctx_rx(struct tls_context *tls_ctx); +int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int flags, int *addr_len); +bool tls_sw_sock_is_readable(struct sock *sk); +ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, + struct pipe_inode_info *pipe, + size_t len, unsigned int flags); + +int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); +int tls_device_sendpage(struct sock *sk, struct page *page, + int offset, size_t size, int flags); +int tls_tx_records(struct sock *sk, int flags); + +void tls_sw_write_space(struct sock *sk, struct tls_context *ctx); +void tls_device_write_space(struct sock *sk, struct tls_context *ctx); + +int tls_process_cmsg(struct sock *sk, struct msghdr *msg, + unsigned char *record_type); +int decrypt_skb(struct sock *sk, struct sk_buff *skb, + struct scatterlist *sgout); + +int tls_sw_fallback_init(struct sock *sk, + struct tls_offload_context_tx *offload_ctx, + struct tls_crypto_info *crypto_info); + +static inline struct tls_msg *tls_msg(struct sk_buff *skb) +{ + struct sk_skb_cb *scb = (struct sk_skb_cb *)skb->cb; + + return &scb->tls; +} + +#ifdef CONFIG_TLS_DEVICE +void tls_device_init(void); +void tls_device_cleanup(void); +int tls_set_device_offload(struct sock *sk, struct tls_context *ctx); +void tls_device_free_resources_tx(struct sock *sk); +int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx); +void tls_device_offload_cleanup_rx(struct sock *sk); +void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq); +int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx, + struct sk_buff *skb, struct strp_msg *rxm); +#else +static inline void tls_device_init(void) {} +static inline void tls_device_cleanup(void) {} + +static inline int +tls_set_device_offload(struct sock *sk, struct tls_context *ctx) +{ + return -EOPNOTSUPP; +} + +static inline void tls_device_free_resources_tx(struct sock *sk) {} + +static inline int +tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) +{ + return -EOPNOTSUPP; +} + +static inline void tls_device_offload_cleanup_rx(struct sock *sk) {} +static inline void +tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq) {} + +static inline int +tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx, + struct sk_buff *skb, struct strp_msg *rxm) +{ + return 0; +} +#endif + +int tls_push_sg(struct sock *sk, struct tls_context *ctx, + struct scatterlist *sg, u16 first_offset, + int flags); +int tls_push_partial_record(struct sock *sk, struct tls_context *ctx, + int flags); +void tls_free_partial_record(struct sock *sk, struct tls_context *ctx); + +static inline bool tls_is_partially_sent_record(struct tls_context *ctx) +{ + return !!ctx->partially_sent_record; +} + +static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx) +{ + return tls_ctx->pending_open_record_frags; +} + +static inline bool tls_bigint_increment(unsigned char *seq, int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + ++seq[i]; + if (seq[i] != 0) + break; + } + + return (i == -1); +} + +static inline void tls_bigint_subtract(unsigned char *seq, int n) +{ + u64 rcd_sn; + __be64 *p; + + BUILD_BUG_ON(TLS_MAX_REC_SEQ_SIZE != 8); + + p = (__be64 *)seq; + rcd_sn = be64_to_cpu(*p); + *p = cpu_to_be64(rcd_sn - n); +} + +static inline void +tls_advance_record_sn(struct sock *sk, struct tls_prot_info *prot, + struct cipher_context *ctx) +{ + if (tls_bigint_increment(ctx->rec_seq, prot->rec_seq_size)) + tls_err_abort(sk, -EBADMSG); + + if (prot->version != TLS_1_3_VERSION && + prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305) + tls_bigint_increment(ctx->iv + prot->salt_size, + prot->iv_size); +} + +static inline void +tls_xor_iv_with_seq(struct tls_prot_info *prot, char *iv, char *seq) +{ + int i; + + if (prot->version == TLS_1_3_VERSION || + prot->cipher_type == TLS_CIPHER_CHACHA20_POLY1305) { + for (i = 0; i < 8; i++) + iv[i + 4] ^= seq[i]; + } +} + +static inline void +tls_fill_prepend(struct tls_context *ctx, char *buf, size_t plaintext_len, + unsigned char record_type) +{ + struct tls_prot_info *prot = &ctx->prot_info; + size_t pkt_len, iv_size = prot->iv_size; + + pkt_len = plaintext_len + prot->tag_size; + if (prot->version != TLS_1_3_VERSION && + prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305) { + pkt_len += iv_size; + + memcpy(buf + TLS_NONCE_OFFSET, + ctx->tx.iv + prot->salt_size, iv_size); + } + + /* we cover nonce explicit here as well, so buf should be of + * size KTLS_DTLS_HEADER_SIZE + KTLS_DTLS_NONCE_EXPLICIT_SIZE + */ + buf[0] = prot->version == TLS_1_3_VERSION ? + TLS_RECORD_TYPE_DATA : record_type; + /* Note that VERSION must be TLS_1_2 for both TLS1.2 and TLS1.3 */ + buf[1] = TLS_1_2_VERSION_MINOR; + buf[2] = TLS_1_2_VERSION_MAJOR; + /* we can use IV for nonce explicit according to spec */ + buf[3] = pkt_len >> 8; + buf[4] = pkt_len & 0xFF; +} + +static inline +void tls_make_aad(char *buf, size_t size, char *record_sequence, + unsigned char record_type, struct tls_prot_info *prot) +{ + if (prot->version != TLS_1_3_VERSION) { + memcpy(buf, record_sequence, prot->rec_seq_size); + buf += 8; + } else { + size += prot->tag_size; + } + + buf[0] = prot->version == TLS_1_3_VERSION ? + TLS_RECORD_TYPE_DATA : record_type; + buf[1] = TLS_1_2_VERSION_MAJOR; + buf[2] = TLS_1_2_VERSION_MINOR; + buf[3] = size >> 8; + buf[4] = size & 0xFF; +} + +#endif diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index ec6f4b699a2b..227b92a3064a 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -38,6 +38,7 @@ #include #include +#include "tls.h" #include "trace.h" /* device_offload_lock is used to synchronize tls_dev_add @@ -562,7 +563,7 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) lock_sock(sk); if (unlikely(msg->msg_controllen)) { - rc = tls_proccess_cmsg(sk, msg, &record_type); + rc = tls_process_cmsg(sk, msg, &record_type); if (rc) goto out; } diff --git a/net/tls/tls_device_fallback.c b/net/tls/tls_device_fallback.c index 3bae29ae57ca..618cee704217 100644 --- a/net/tls/tls_device_fallback.c +++ b/net/tls/tls_device_fallback.c @@ -34,6 +34,8 @@ #include #include +#include "tls.h" + static void chain_to_walk(struct scatterlist *sg, struct scatter_walk *walk) { struct scatterlist *src = walk->sg; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 1b3efc96db0b..f3d9dbfa507e 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -45,6 +45,8 @@ #include #include +#include "tls.h" + MODULE_AUTHOR("Mellanox Technologies"); MODULE_DESCRIPTION("Transport Layer Security Support"); MODULE_LICENSE("Dual BSD/GPL"); @@ -164,8 +166,8 @@ static int tls_handle_open_record(struct sock *sk, int flags) return 0; } -int tls_proccess_cmsg(struct sock *sk, struct msghdr *msg, - unsigned char *record_type) +int tls_process_cmsg(struct sock *sk, struct msghdr *msg, + unsigned char *record_type) { struct cmsghdr *cmsg; int rc = -EINVAL; @@ -1003,6 +1005,23 @@ static void tls_update(struct sock *sk, struct proto *p, } } +static u16 tls_user_config(struct tls_context *ctx, bool tx) +{ + u16 config = tx ? ctx->tx_conf : ctx->rx_conf; + + switch (config) { + case TLS_BASE: + return TLS_CONF_BASE; + case TLS_SW: + return TLS_CONF_SW; + case TLS_HW: + return TLS_CONF_HW; + case TLS_HW_RECORD: + return TLS_CONF_HW_RECORD; + } + return 0; +} + static int tls_get_info(const struct sock *sk, struct sk_buff *skb) { u16 version, cipher_type; diff --git a/net/tls/tls_proc.c b/net/tls/tls_proc.c index 0c200000cc45..1246e52b48f6 100644 --- a/net/tls/tls_proc.c +++ b/net/tls/tls_proc.c @@ -6,6 +6,8 @@ #include #include +#include "tls.h" + #ifdef CONFIG_PROC_FS static const struct snmp_mib tls_mib_list[] = { SNMP_MIB_ITEM("TlsCurrTxSw", LINUX_MIB_TLSCURRTXSW), diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 21c76db8f9b3..1376f866734d 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -44,6 +44,8 @@ #include #include +#include "tls.h" + struct tls_decrypt_arg { bool zc; bool async; @@ -524,7 +526,8 @@ static int tls_do_encryption(struct sock *sk, memcpy(&rec->iv_data[iv_offset], tls_ctx->tx.iv, prot->iv_size + prot->salt_size); - xor_iv_with_seq(prot, rec->iv_data + iv_offset, tls_ctx->tx.rec_seq); + tls_xor_iv_with_seq(prot, rec->iv_data + iv_offset, + tls_ctx->tx.rec_seq); sge->offset += prot->prepend_size; sge->length -= prot->prepend_size; @@ -961,7 +964,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) lock_sock(sk); if (unlikely(msg->msg_controllen)) { - ret = tls_proccess_cmsg(sk, msg, &record_type); + ret = tls_process_cmsg(sk, msg, &record_type); if (ret) { if (ret == -EINPROGRESS) num_async++; @@ -1495,7 +1498,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, goto exit_free; memcpy(&dctx->iv[iv_offset], tls_ctx->rx.iv, prot->salt_size); } - xor_iv_with_seq(prot, &dctx->iv[iv_offset], tls_ctx->rx.rec_seq); + tls_xor_iv_with_seq(prot, &dctx->iv[iv_offset], tls_ctx->rx.rec_seq); /* Prepare AAD */ tls_make_aad(dctx->aad, rxm->full_len - prot->overhead_size + @@ -2267,12 +2270,23 @@ static void tx_work_handler(struct work_struct *work) mutex_unlock(&tls_ctx->tx_lock); } +static bool tls_is_tx_ready(struct tls_sw_context_tx *ctx) +{ + struct tls_rec *rec; + + rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); + if (!rec) + return false; + + return READ_ONCE(rec->tx_ready); +} + void tls_sw_write_space(struct sock *sk, struct tls_context *ctx) { struct tls_sw_context_tx *tx_ctx = tls_sw_ctx_tx(ctx); /* Schedule the transmission if tx list is ready */ - if (is_tx_ready(tx_ctx) && + if (tls_is_tx_ready(tx_ctx) && !test_and_set_bit(BIT_TX_SCHEDULED, &tx_ctx->tx_bitmask)) schedule_delayed_work(&tx_ctx->tx_work.work, 0); } diff --git a/net/tls/tls_toe.c b/net/tls/tls_toe.c index 7e1330f19165..825669e1ab47 100644 --- a/net/tls/tls_toe.c +++ b/net/tls/tls_toe.c @@ -38,6 +38,8 @@ #include #include +#include "tls.h" + static LIST_HEAD(device_list); static DEFINE_SPINLOCK(device_spinlock); -- cgit v1.2.3 From 6cda12864cb0f99810a5809e11e3ee5b102c9a47 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 3 Jul 2022 21:02:49 -0400 Subject: 9p: Drop kref usage An upcoming patch is going to require passing the client through p9_req_put() -> p9_req_free(), but that's awkward with the kref indirection - so this patch switches to using refcount_t directly. Link: https://lkml.kernel.org/r/20220704014243.153050-1-kent.overstreet@gmail.com Signed-off-by: Kent Overstreet Cc: Eric Van Hensbergen Cc: Latchesar Ionkov Signed-off-by: Dominique Martinet --- include/net/9p/client.h | 6 +++--- net/9p/client.c | 19 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) (limited to 'include/net') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 8f629f1df865..ad38325aaef0 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -77,7 +77,7 @@ enum p9_req_status_t { struct p9_req_t { int status; int t_err; - struct kref refcount; + refcount_t refcount; wait_queue_head_t wq; struct p9_fcall tc; struct p9_fcall rc; @@ -228,12 +228,12 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag); static inline void p9_req_get(struct p9_req_t *r) { - kref_get(&r->refcount); + refcount_inc(&r->refcount); } static inline int p9_req_try_get(struct p9_req_t *r) { - return kref_get_unless_zero(&r->refcount); + return refcount_inc_not_zero(&r->refcount); } int p9_req_put(struct p9_req_t *r); diff --git a/net/9p/client.c b/net/9p/client.c index dfe8beb864fc..3717d3f21a9f 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -305,7 +305,7 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size) * callback), so p9_client_cb eats the second ref there * as the pointer is duplicated directly by virtqueue_add_sgs() */ - refcount_set(&req->refcount.refcount, 2); + refcount_set(&req->refcount, 2); return req; @@ -370,18 +370,15 @@ static int p9_tag_remove(struct p9_client *c, struct p9_req_t *r) return p9_req_put(r); } -static void p9_req_free(struct kref *ref) -{ - struct p9_req_t *r = container_of(ref, struct p9_req_t, refcount); - - p9_fcall_fini(&r->tc); - p9_fcall_fini(&r->rc); - kmem_cache_free(p9_req_cache, r); -} - int p9_req_put(struct p9_req_t *r) { - return kref_put(&r->refcount, p9_req_free); + if (refcount_dec_and_test(&r->refcount)) { + p9_fcall_fini(&r->tc); + p9_fcall_fini(&r->rc); + kmem_cache_free(p9_req_cache, r); + return 1; + } + return 0; } EXPORT_SYMBOL(p9_req_put); -- cgit v1.2.3 From 8b11ff098af42b1fa57fc817daadd53c8b244a0c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 3 Jul 2022 21:08:18 -0400 Subject: 9p: Add client parameter to p9_req_put() This is to aid in adding mempools, in the next patch. Link: https://lkml.kernel.org/r/20220704014243.153050-2-kent.overstreet@gmail.com Signed-off-by: Kent Overstreet Cc: Eric Van Hensbergen Cc: Latchesar Ionkov Signed-off-by: Dominique Martinet --- include/net/9p/client.h | 2 +- net/9p/client.c | 12 ++++++------ net/9p/trans_fd.c | 12 ++++++------ net/9p/trans_rdma.c | 2 +- net/9p/trans_virtio.c | 4 ++-- net/9p/trans_xen.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include/net') diff --git a/include/net/9p/client.h b/include/net/9p/client.h index ad38325aaef0..78ebcf782ce5 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -236,7 +236,7 @@ static inline int p9_req_try_get(struct p9_req_t *r) return refcount_inc_not_zero(&r->refcount); } -int p9_req_put(struct p9_req_t *r); +int p9_req_put(struct p9_client *c, struct p9_req_t *r); /* We cannot have the real tracepoints in header files, * use a wrapper function */ diff --git a/net/9p/client.c b/net/9p/client.c index 3717d3f21a9f..0be19ab1f693 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -341,7 +341,7 @@ again: if (!p9_req_try_get(req)) goto again; if (req->tc.tag != tag) { - p9_req_put(req); + p9_req_put(c, req); goto again; } } @@ -367,10 +367,10 @@ static int p9_tag_remove(struct p9_client *c, struct p9_req_t *r) spin_lock_irqsave(&c->lock, flags); idr_remove(&c->reqs, tag); spin_unlock_irqrestore(&c->lock, flags); - return p9_req_put(r); + return p9_req_put(c, r); } -int p9_req_put(struct p9_req_t *r) +int p9_req_put(struct p9_client *c, struct p9_req_t *r) { if (refcount_dec_and_test(&r->refcount)) { p9_fcall_fini(&r->tc); @@ -423,7 +423,7 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status) wake_up(&req->wq); p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag); - p9_req_put(req); + p9_req_put(c, req); } EXPORT_SYMBOL(p9_client_cb); @@ -706,7 +706,7 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c, reterr: p9_tag_remove(c, req); /* We have to put also the 2nd reference as it won't be used */ - p9_req_put(req); + p9_req_put(c, req); return ERR_PTR(err); } @@ -743,7 +743,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) err = c->trans_mod->request(c, req); if (err < 0) { /* write won't happen */ - p9_req_put(req); + p9_req_put(c, req); if (err != -ERESTARTSYS && err != -EFAULT) c->status = Disconnected; goto recalc_sigpending; diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 8f8f95e39b03..007c3f45fe05 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -378,7 +378,7 @@ static void p9_read_work(struct work_struct *work) m->rc.sdata = NULL; m->rc.offset = 0; m->rc.capacity = 0; - p9_req_put(m->rreq); + p9_req_put(m->client, m->rreq); m->rreq = NULL; } @@ -492,7 +492,7 @@ static void p9_write_work(struct work_struct *work) m->wpos += err; if (m->wpos == m->wsize) { m->wpos = m->wsize = 0; - p9_req_put(m->wreq); + p9_req_put(m->client, m->wreq); m->wreq = NULL; } @@ -695,7 +695,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) if (req->status == REQ_STATUS_UNSENT) { list_del(&req->req_list); req->status = REQ_STATUS_FLSHD; - p9_req_put(req); + p9_req_put(client, req); ret = 0; } spin_unlock(&client->lock); @@ -722,7 +722,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) list_del(&req->req_list); req->status = REQ_STATUS_FLSHD; spin_unlock(&client->lock); - p9_req_put(req); + p9_req_put(client, req); return 0; } @@ -883,12 +883,12 @@ static void p9_conn_destroy(struct p9_conn *m) p9_mux_poll_stop(m); cancel_work_sync(&m->rq); if (m->rreq) { - p9_req_put(m->rreq); + p9_req_put(m->client, m->rreq); m->rreq = NULL; } cancel_work_sync(&m->wq); if (m->wreq) { - p9_req_put(m->wreq); + p9_req_put(m->client, m->wreq); m->wreq = NULL; } diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 88e563826674..d817d3745238 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -350,7 +350,7 @@ send_done(struct ib_cq *cq, struct ib_wc *wc) c->busa, c->req->tc.size, DMA_TO_DEVICE); up(&rdma->sq_sem); - p9_req_put(c->req); + p9_req_put(client, c->req); kfree(c); } diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b24a4fb0f0a2..147972bf2e79 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -199,7 +199,7 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) /* Reply won't come, so drop req ref */ static int p9_virtio_cancelled(struct p9_client *client, struct p9_req_t *req) { - p9_req_put(req); + p9_req_put(client, req); return 0; } @@ -523,7 +523,7 @@ err_out: kvfree(out_pages); if (!kicked) { /* reply won't come */ - p9_req_put(req); + p9_req_put(client, req); } return err; } diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index 833cd3792c51..227f89cc7237 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -163,7 +163,7 @@ again: ring->intf->out_prod = prod; spin_unlock_irqrestore(&ring->lock, flags); notify_remote_via_irq(ring->irq); - p9_req_put(p9_req); + p9_req_put(client, p9_req); return 0; } -- cgit v1.2.3 From f7657ff4a7097eaf5220776456b7d75eb09062cb Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 8 Jul 2022 10:14:08 -0700 Subject: mptcp: move MPTCPOPT_HMAC_LEN to net/mptcp.h Move macro MPTCPOPT_HMAC_LEN definition from net/mptcp/protocol.h to include/net/mptcp.h. Reviewed-by: Mat Martineau Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Signed-off-by: David S. Miller --- include/net/mptcp.h | 3 ++- net/mptcp/protocol.h | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 4d761ad530c9..ac9cf7271d46 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -39,6 +39,7 @@ struct mptcp_ext { infinite_map:1; }; +#define MPTCPOPT_HMAC_LEN 20 #define MPTCP_RM_IDS_MAX 8 struct mptcp_rm_list { @@ -89,7 +90,7 @@ struct mptcp_out_options { u32 nonce; u32 token; u64 thmac; - u8 hmac[20]; + u8 hmac[MPTCPOPT_HMAC_LEN]; }; }; #endif diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 480c5320b86e..07871e10e510 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -83,7 +83,6 @@ /* MPTCP MP_JOIN flags */ #define MPTCPOPT_BACKUP BIT(0) -#define MPTCPOPT_HMAC_LEN 20 #define MPTCPOPT_THMAC_LEN 8 /* MPTCP MP_CAPABLE flags */ -- cgit v1.2.3 From e22aa14866684f77b4f6b6cae98539e520ddb731 Mon Sep 17 00:00:00 2001 From: sewookseo Date: Thu, 7 Jul 2022 10:01:39 +0000 Subject: net: Find dst with sk's xfrm policy not ctl_sk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we set XFRM security policy by calling setsockopt with option IPV6_XFRM_POLICY, the policy will be stored in 'sock_policy' in 'sock' struct. However tcp_v6_send_response doesn't look up dst_entry with the actual socket but looks up with tcp control socket. This may cause a problem that a RST packet is sent without ESP encryption & peer's TCP socket can't receive it. This patch will make the function look up dest_entry with actual socket, if the socket has XFRM policy(sock_policy), so that the TCP response packet via this function can be encrypted, & aligned on the encrypted TCP socket. Tested: We encountered this problem when a TCP socket which is encrypted in ESP transport mode encryption, receives challenge ACK at SYN_SENT state. After receiving challenge ACK, TCP needs to send RST to establish the socket at next SYN try. But the RST was not encrypted & peer TCP socket still remains on ESTABLISHED state. So we verified this with test step as below. [Test step] 1. Making a TCP state mismatch between client(IDLE) & server(ESTABLISHED). 2. Client tries a new connection on the same TCP ports(src & dst). 3. Server will return challenge ACK instead of SYN,ACK. 4. Client will send RST to server to clear the SOCKET. 5. Client will retransmit SYN to server on the same TCP ports. [Expected result] The TCP connection should be established. Cc: Maciej Å»enczykowski Cc: Eric Dumazet Cc: Steffen Klassert Cc: Sehee Lee Signed-off-by: Sewook Seo Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/xfrm.h | 2 ++ net/ipv4/ip_output.c | 2 +- net/ipv4/tcp_ipv4.c | 2 ++ net/ipv6/tcp_ipv6.c | 5 ++++- 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 9287712ad977..67b799ef5f67 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1195,6 +1195,8 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk); static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) { + if (!sk_fullsock(osk)) + return 0; sk->sk_policy[0] = NULL; sk->sk_policy[1] = NULL; if (unlikely(osk->sk_policy[0] || osk->sk_policy[1])) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 5e32a2f86fbd..f7156845ddf7 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1700,7 +1700,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, tcp_hdr(skb)->source, tcp_hdr(skb)->dest, arg->uid); security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); - rt = ip_route_output_key(net, &fl4); + rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) return; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 68d0d8a008e2..228d36692d08 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -819,6 +819,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ctl_sk->sk_priority = (sk->sk_state == TCP_TIME_WAIT) ? inet_twsk(sk)->tw_priority : sk->sk_priority; transmit_time = tcp_transmit_time(sk); + xfrm_sk_clone_policy(ctl_sk, sk); } ip_send_unicast_reply(ctl_sk, skb, &TCP_SKB_CB(skb)->header.h4.opt, @@ -827,6 +828,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) transmit_time); ctl_sk->sk_mark = 0; + xfrm_sk_free_policy(ctl_sk); sock_net_set(ctl_sk, &init_net); __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); __TCP_INC_STATS(net, TCP_MIB_OUTRSTS); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c72448ba6dc9..70d4890d8d2f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -952,7 +952,10 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 * Underlying function will use this to retrieve the network * namespace */ - dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL); + if (sk && sk->sk_state != TCP_TIME_WAIT) + dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL); /*sk's xfrm_policy can be referred*/ + else + dst = ip6_dst_lookup_flow(net, ctl_sk, &fl6, NULL); if (!IS_ERR(dst)) { skb_dst_set(buff, dst); ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, -- cgit v1.2.3 From b038177636f83bbf87c2b238706474145dd2cd04 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Wed, 15 Jun 2022 12:43:55 +0200 Subject: netfilter: nf_flow_table: count pending offload workqueue tasks To improve hardware offload debuggability count pending 'add', 'del' and 'stats' flow_table offload workqueue tasks. Counters are incremented before scheduling new task and decremented when workqueue handler finishes executing. These counters allow user to diagnose congestion on hardware offload workqueues that can happen when either CPU is starved and workqueue jobs are executed at lower rate than new ones are added or when hardware/driver can't keep up with the rate. Implement the described counters as percpu counters inside new struct netns_ft which is stored inside struct net. Expose them via new procfs file '/proc/net/stats/nf_flowtable' that is similar to existing 'nf_conntrack' file. Signed-off-by: Vlad Buslov Signed-off-by: Oz Shlomo Signed-off-by: Pablo Neira Ayuso --- include/net/net_namespace.h | 6 +++ include/net/netfilter/nf_flow_table.h | 21 +++++++++ include/net/netns/flow_table.h | 14 ++++++ net/netfilter/Kconfig | 9 ++++ net/netfilter/Makefile | 1 + net/netfilter/nf_flow_table_core.c | 62 ++++++++++++++++++++++++++- net/netfilter/nf_flow_table_offload.c | 17 ++++++-- net/netfilter/nf_flow_table_procfs.c | 80 +++++++++++++++++++++++++++++++++++ 8 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 include/net/netns/flow_table.h create mode 100644 net/netfilter/nf_flow_table_procfs.c (limited to 'include/net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 20a2992901c2..8c3587d5c308 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -26,6 +26,9 @@ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #include #endif +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +#include +#endif #include #include #include @@ -142,6 +145,9 @@ struct net { #if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE) struct netns_nftables nft; #endif +#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) + struct netns_ft ft; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index 64daafd1fc41..d5326c44b453 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -335,4 +335,25 @@ static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) return 0; } +#define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \ + this_cpu_inc((net)->ft.stat->count) +#define NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count) \ + this_cpu_dec((net)->ft.stat->count) + +#ifdef CONFIG_NF_FLOW_TABLE_PROCFS +int nf_flow_table_init_proc(struct net *net); +void nf_flow_table_fini_proc(struct net *net); +#else +static inline int nf_flow_table_init_proc(struct net *net) +{ + return 0; +} + +static inline void nf_flow_table_fini_proc(struct net *net) +{ +} +#endif /* CONFIG_NF_FLOW_TABLE_PROCFS */ + #endif /* _NF_FLOW_TABLE_H */ diff --git a/include/net/netns/flow_table.h b/include/net/netns/flow_table.h new file mode 100644 index 000000000000..1c5fc657e267 --- /dev/null +++ b/include/net/netns/flow_table.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NETNS_FLOW_TABLE_H +#define __NETNS_FLOW_TABLE_H + +struct nf_flow_table_stat { + unsigned int count_wq_add; + unsigned int count_wq_del; + unsigned int count_wq_stats; +}; + +struct netns_ft { + struct nf_flow_table_stat __percpu *stat; +}; +#endif diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index ddc54b6d18ee..df6abbfe0079 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -734,6 +734,15 @@ config NF_FLOW_TABLE To compile it as a module, choose M here. +config NF_FLOW_TABLE_PROCFS + bool "Supply flow table statistics in procfs" + default y + depends on PROC_FS + depends on SYSCTL + help + This option enables for the flow table offload statistics + to be shown in procfs under net/netfilter/nf_flowtable. + config NETFILTER_XTABLES tristate "Netfilter Xtables support (required for ip_tables)" default m if NETFILTER_ADVANCED=n diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 238b6a620e88..06df49ea6329 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -128,6 +128,7 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \ nf_flow_table_offload.o +nf_flow_table-$(CONFIG_NF_FLOW_TABLE_PROCFS) += nf_flow_table_procfs.o obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index f2def06d1070..51c2b1570838 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -614,14 +614,74 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) } EXPORT_SYMBOL_GPL(nf_flow_table_free); +static int nf_flow_table_init_net(struct net *net) +{ + net->ft.stat = alloc_percpu(struct nf_flow_table_stat); + return net->ft.stat ? 0 : -ENOMEM; +} + +static void nf_flow_table_fini_net(struct net *net) +{ + free_percpu(net->ft.stat); +} + +static int nf_flow_table_pernet_init(struct net *net) +{ + int ret; + + ret = nf_flow_table_init_net(net); + if (ret < 0) + return ret; + + ret = nf_flow_table_init_proc(net); + if (ret < 0) + goto out_proc; + + return 0; + +out_proc: + nf_flow_table_fini_net(net); + return ret; +} + +static void nf_flow_table_pernet_exit(struct list_head *net_exit_list) +{ + struct net *net; + + list_for_each_entry(net, net_exit_list, exit_list) { + nf_flow_table_fini_proc(net); + nf_flow_table_fini_net(net); + } +} + +static struct pernet_operations nf_flow_table_net_ops = { + .init = nf_flow_table_pernet_init, + .exit_batch = nf_flow_table_pernet_exit, +}; + static int __init nf_flow_table_module_init(void) { - return nf_flow_table_offload_init(); + int ret; + + ret = register_pernet_subsys(&nf_flow_table_net_ops); + if (ret < 0) + return ret; + + ret = nf_flow_table_offload_init(); + if (ret) + goto out_offload; + + return 0; + +out_offload: + unregister_pernet_subsys(&nf_flow_table_net_ops); + return ret; } static void __exit nf_flow_table_module_exit(void) { nf_flow_table_offload_exit(); + unregister_pernet_subsys(&nf_flow_table_net_ops); } module_init(nf_flow_table_module_init); diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index 11b6e1942092..103b6cbf257f 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -967,17 +967,22 @@ static void flow_offload_work_stats(struct flow_offload_work *offload) static void flow_offload_work_handler(struct work_struct *work) { struct flow_offload_work *offload; + struct net *net; offload = container_of(work, struct flow_offload_work, work); + net = read_pnet(&offload->flowtable->net); switch (offload->cmd) { case FLOW_CLS_REPLACE: flow_offload_work_add(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_add); break; case FLOW_CLS_DESTROY: flow_offload_work_del(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_del); break; case FLOW_CLS_STATS: flow_offload_work_stats(offload); + NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count_wq_stats); break; default: WARN_ON_ONCE(1); @@ -989,12 +994,18 @@ static void flow_offload_work_handler(struct work_struct *work) static void flow_offload_queue_work(struct flow_offload_work *offload) { - if (offload->cmd == FLOW_CLS_REPLACE) + struct net *net = read_pnet(&offload->flowtable->net); + + if (offload->cmd == FLOW_CLS_REPLACE) { + NF_FLOW_TABLE_STAT_INC(net, count_wq_add); queue_work(nf_flow_offload_add_wq, &offload->work); - else if (offload->cmd == FLOW_CLS_DESTROY) + } else if (offload->cmd == FLOW_CLS_DESTROY) { + NF_FLOW_TABLE_STAT_INC(net, count_wq_del); queue_work(nf_flow_offload_del_wq, &offload->work); - else + } else { + NF_FLOW_TABLE_STAT_INC(net, count_wq_stats); queue_work(nf_flow_offload_stats_wq, &offload->work); + } } static struct flow_offload_work * diff --git a/net/netfilter/nf_flow_table_procfs.c b/net/netfilter/nf_flow_table_procfs.c new file mode 100644 index 000000000000..159b033a43e6 --- /dev/null +++ b/net/netfilter/nf_flow_table_procfs.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include + +static void *nf_flow_table_cpu_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos - 1; cpu < nr_cpu_ids; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu + 1; + return per_cpu_ptr(net->ft.stat, cpu); + } + + return NULL; +} + +static void *nf_flow_table_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + int cpu; + + for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu + 1; + return per_cpu_ptr(net->ft.stat, cpu); + } + (*pos)++; + return NULL; +} + +static void nf_flow_table_cpu_seq_stop(struct seq_file *seq, void *v) +{ +} + +static int nf_flow_table_cpu_seq_show(struct seq_file *seq, void *v) +{ + const struct nf_flow_table_stat *st = v; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "wq_add wq_del wq_stats\n"); + return 0; + } + + seq_printf(seq, "%8d %8d %8d\n", + st->count_wq_add, + st->count_wq_del, + st->count_wq_stats + ); + return 0; +} + +static const struct seq_operations nf_flow_table_cpu_seq_ops = { + .start = nf_flow_table_cpu_seq_start, + .next = nf_flow_table_cpu_seq_next, + .stop = nf_flow_table_cpu_seq_stop, + .show = nf_flow_table_cpu_seq_show, +}; + +int nf_flow_table_init_proc(struct net *net) +{ + struct proc_dir_entry *pde; + + pde = proc_create_net("nf_flowtable", 0444, net->proc_net_stat, + &nf_flow_table_cpu_seq_ops, + sizeof(struct seq_net_private)); + return pde ? 0 : -ENOMEM; +} + +void nf_flow_table_fini_proc(struct net *net) +{ + remove_proc_entry("nf_flowtable", net->proc_net_stat); +} -- cgit v1.2.3 From 6976890e8998afd8abbbd9fe27ed71387b24f57f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 22 Jun 2022 11:00:45 +0200 Subject: netfilter: nf_conntrack: add missing __rcu annotations Access to the hook pointers use correct helpers but the pointers lack the needed __rcu annotation. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nf_conntrack_sip.h | 2 +- include/net/netfilter/nf_conntrack_timeout.h | 2 +- net/netfilter/nf_conntrack_pptp.c | 2 +- net/netfilter/nf_conntrack_sip.c | 2 +- net/netfilter/nf_conntrack_timeout.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index c620521c42bc..dbc614dfe0d5 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -164,7 +164,7 @@ struct nf_nat_sip_hooks { unsigned int medialen, union nf_inet_addr *rtp_addr); }; -extern const struct nf_nat_sip_hooks *nf_nat_sip_hooks; +extern const struct nf_nat_sip_hooks __rcu *nf_nat_sip_hooks; int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, unsigned int *matchoff, diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h index fea258983d23..9fdaba911de6 100644 --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -105,7 +105,7 @@ struct nf_ct_timeout_hooks { void (*timeout_put)(struct nf_ct_timeout *timeout); }; -extern const struct nf_ct_timeout_hooks *nf_ct_timeout_hook; +extern const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook; #endif #endif /* _NF_CONNTRACK_TIMEOUT_H */ diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index f3fa367b455f..4c679638df06 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -45,7 +45,7 @@ MODULE_ALIAS_NFCT_HELPER("pptp"); static DEFINE_SPINLOCK(nf_pptp_lock); -const struct nf_nat_pptp_hook *nf_nat_pptp_hook; +const struct nf_nat_pptp_hook __rcu *nf_nat_pptp_hook; EXPORT_SYMBOL_GPL(nf_nat_pptp_hook); #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index b83dc9bf0a5d..a88b43624b27 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -60,7 +60,7 @@ module_param(sip_external_media, int, 0600); MODULE_PARM_DESC(sip_external_media, "Expect Media streams between external " "endpoints (default 0)"); -const struct nf_nat_sip_hooks *nf_nat_sip_hooks; +const struct nf_nat_sip_hooks __rcu *nf_nat_sip_hooks; EXPORT_SYMBOL_GPL(nf_nat_sip_hooks); static int string_len(const struct nf_conn *ct, const char *dptr, diff --git a/net/netfilter/nf_conntrack_timeout.c b/net/netfilter/nf_conntrack_timeout.c index 0f828d05ea60..821365ed5b2c 100644 --- a/net/netfilter/nf_conntrack_timeout.c +++ b/net/netfilter/nf_conntrack_timeout.c @@ -22,7 +22,7 @@ #include #include -const struct nf_ct_timeout_hooks *nf_ct_timeout_hook __read_mostly; +const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook __read_mostly; EXPORT_SYMBOL_GPL(nf_ct_timeout_hook); static int untimeout(struct nf_conn *ct, void *timeout) -- cgit v1.2.3 From 7278b3c1e4ebf6f9c4cda07600f19824857c81fe Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 23 Jun 2022 15:05:12 +0200 Subject: netfilter: nf_tables: add and use BE register load-store helpers Same as the existing ones, no conversions. This is just for sparse sake only so that we no longer mix be16/u16 and be32/u32 types. Alternative is to add __force __beX in various places, but this seems nicer. objdiff shows no changes. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 15 +++++++++++++++ net/bridge/netfilter/nft_meta_bridge.c | 2 +- net/netfilter/nft_tproxy.c | 6 +++--- 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 5c4e5a96a984..dd6ad0b67d7d 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -157,11 +157,26 @@ static inline void nft_reg_store16(u32 *dreg, u16 val) *(u16 *)dreg = val; } +static inline void nft_reg_store_be16(u32 *dreg, __be16 val) +{ + nft_reg_store16(dreg, (__force __u16)val); +} + static inline u16 nft_reg_load16(const u32 *sreg) { return *(u16 *)sreg; } +static inline __be16 nft_reg_load_be16(const u32 *sreg) +{ + return (__force __be16)nft_reg_load16(sreg); +} + +static inline __be32 nft_reg_load_be32(const u32 *sreg) +{ + return *(__force __be32 *)sreg; +} + static inline void nft_reg_store64(u32 *dreg, u64 val) { put_unaligned(val, (u64 *)dreg); diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c index 8c3eaba87ad2..c3ecd77e25cb 100644 --- a/net/bridge/netfilter/nft_meta_bridge.c +++ b/net/bridge/netfilter/nft_meta_bridge.c @@ -53,7 +53,7 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr, goto err; br_vlan_get_proto(br_dev, &p_proto); - nft_reg_store16(dest, htons(p_proto)); + nft_reg_store_be16(dest, htons(p_proto)); return; } default: diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c index 801f013971df..68b2eed742df 100644 --- a/net/netfilter/nft_tproxy.c +++ b/net/netfilter/nft_tproxy.c @@ -52,11 +52,11 @@ static void nft_tproxy_eval_v4(const struct nft_expr *expr, skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED); if (priv->sreg_addr) - taddr = regs->data[priv->sreg_addr]; + taddr = nft_reg_load_be32(®s->data[priv->sreg_addr]); taddr = nf_tproxy_laddr4(skb, taddr, iph->daddr); if (priv->sreg_port) - tport = nft_reg_load16(®s->data[priv->sreg_port]); + tport = nft_reg_load_be16(®s->data[priv->sreg_port]); if (!tport) tport = hp->dest; @@ -124,7 +124,7 @@ static void nft_tproxy_eval_v6(const struct nft_expr *expr, taddr = *nf_tproxy_laddr6(skb, &taddr, &iph->daddr); if (priv->sreg_port) - tport = nft_reg_load16(®s->data[priv->sreg_port]); + tport = nft_reg_load_be16(®s->data[priv->sreg_port]); if (!tport) tport = hp->dest; -- cgit v1.2.3 From 6b77205374fdeae4c9a585a7ca754673ef52f75b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 23 Jun 2022 15:05:14 +0200 Subject: netfilter: nf_tables: move nft_cmp_fast_mask to where its used ... and cast result to u32 so sparse won't complain anymore. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables_core.h | 10 ---------- net/netfilter/nft_cmp.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h index 0ea7c55cea4d..1223af68cd9a 100644 --- a/include/net/netfilter/nf_tables_core.h +++ b/include/net/netfilter/nf_tables_core.h @@ -56,16 +56,6 @@ struct nft_immediate_expr { u8 dlen; }; -/* Calculate the mask for the nft_cmp_fast expression. On big endian the - * mask needs to include the *upper* bytes when interpreting that data as - * something smaller than the full u32, therefore a cpu_to_le32 is done. - */ -static inline u32 nft_cmp_fast_mask(unsigned int len) -{ - return cpu_to_le32(~0U >> (sizeof_field(struct nft_cmp_fast_expr, - data) * BITS_PER_BYTE - len)); -} - extern const struct nft_expr_ops nft_cmp_fast_ops; extern const struct nft_expr_ops nft_cmp16_fast_ops; diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c index bec22584395f..777f09e4dc60 100644 --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c @@ -197,6 +197,18 @@ static const struct nft_expr_ops nft_cmp_ops = { .offload = nft_cmp_offload, }; +/* Calculate the mask for the nft_cmp_fast expression. On big endian the + * mask needs to include the *upper* bytes when interpreting that data as + * something smaller than the full u32, therefore a cpu_to_le32 is done. + */ +static u32 nft_cmp_fast_mask(unsigned int len) +{ + __le32 mask = cpu_to_le32(~0U >> (sizeof_field(struct nft_cmp_fast_expr, + data) * BITS_PER_BYTE - len)); + + return (__force u32)mask; +} + static int nft_cmp_fast_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) -- cgit v1.2.3 From 2b8bf3d6c99318eae669e3098c490ba6b508fd37 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 9 Jul 2022 16:37:53 +0200 Subject: net/fq_impl: Use the bitmap API to allocate bitmaps Use bitmap_zalloc()/bitmap_free() instead of hand-writing them. It is less verbose and it improves the semantic. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/c7bf099af07eb497b02d195906ee8c11fea3b3bd.1657377335.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- include/net/fq_impl.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h index a5f67a2c0c73..524b510f1c68 100644 --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h @@ -358,8 +358,7 @@ static int fq_init(struct fq *fq, int flows_cnt) if (!fq->flows) return -ENOMEM; - fq->flows_bitmap = kcalloc(BITS_TO_LONGS(fq->flows_cnt), sizeof(long), - GFP_KERNEL); + fq->flows_bitmap = bitmap_zalloc(fq->flows_cnt, GFP_KERNEL); if (!fq->flows_bitmap) { kvfree(fq->flows); fq->flows = NULL; @@ -383,7 +382,7 @@ static void fq_reset(struct fq *fq, kvfree(fq->flows); fq->flows = NULL; - kfree(fq->flows_bitmap); + bitmap_free(fq->flows_bitmap); fq->flows_bitmap = NULL; } -- cgit v1.2.3 From 868232f5cd382c37a5005deb7be0620c6f7bc08d Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 11 Jul 2022 01:14:02 -0700 Subject: devlink: Remove unused function devlink_rate_nodes_destroy The previous patch removed the last usage of the function devlink_rate_nodes_destroy(). Thus, remove this function from devlink API. Signed-off-by: Moshe Shemesh Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed Signed-off-by: Paolo Abeni --- include/net/devlink.h | 1 - net/core/devlink.c | 18 ------------------ 2 files changed, 19 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 2a2a2a0c93f7..0e163cc87d45 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1571,7 +1571,6 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, bool external); int devlink_rate_leaf_create(struct devlink_port *port, void *priv); void devlink_rate_leaf_destroy(struct devlink_port *devlink_port); -void devlink_rate_nodes_destroy(struct devlink *devlink); void devlink_port_linecard_set(struct devlink_port *devlink_port, struct devlink_linecard *linecard); struct devlink_linecard * diff --git a/net/core/devlink.c b/net/core/devlink.c index db61f3a341cb..1588e2246234 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10095,24 +10095,6 @@ void devl_rate_nodes_destroy(struct devlink *devlink) } EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy); -/** - * devlink_rate_nodes_destroy - destroy all devlink rate nodes on device - * - * @devlink: devlink instance - * - * Unset parent for all rate objects and destroy all rate nodes - * on specified device. - * - * Context: Takes and release devlink->lock . - */ -void devlink_rate_nodes_destroy(struct devlink *devlink) -{ - mutex_lock(&devlink->lock); - devl_rate_nodes_destroy(devlink); - mutex_unlock(&devlink->lock); -} -EXPORT_SYMBOL_GPL(devlink_rate_nodes_destroy); - /** * devlink_port_linecard_set - Link port with a linecard * -- cgit v1.2.3 From df539fc62b069ed2b2395d8d1c77f7758c5001a6 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Mon, 11 Jul 2022 01:14:05 -0700 Subject: devlink: Remove unused functions devlink_rate_leaf_create/destroy The previous patch removed the last usage of the functions devlink_rate_leaf_create() and devlink_rate_nodes_destroy(). Thus, remove these function from devlink API. Signed-off-by: Moshe Shemesh Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed Signed-off-by: Paolo Abeni --- include/net/devlink.h | 2 -- net/core/devlink.c | 42 +++++++----------------------------------- 2 files changed, 7 insertions(+), 37 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 0e163cc87d45..5150deb67fab 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1569,8 +1569,6 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 controller, u16 pf, u32 sf, bool external); -int devlink_rate_leaf_create(struct devlink_port *port, void *priv); -void devlink_rate_leaf_destroy(struct devlink_port *devlink_port); void devlink_port_linecard_set(struct devlink_port *devlink_port, struct devlink_linecard *linecard); struct devlink_linecard * diff --git a/net/core/devlink.c b/net/core/devlink.c index 1588e2246234..970e5c2a52bd 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10006,20 +10006,13 @@ int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv) } EXPORT_SYMBOL_GPL(devl_rate_leaf_create); -int -devlink_rate_leaf_create(struct devlink_port *devlink_port, void *priv) -{ - struct devlink *devlink = devlink_port->devlink; - int ret; - - mutex_lock(&devlink->lock); - ret = devl_rate_leaf_create(devlink_port, priv); - mutex_unlock(&devlink->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(devlink_rate_leaf_create); - +/** + * devl_rate_leaf_destroy - destroy devlink rate leaf + * + * @devlink_port: devlink port linked to the rate object + * + * Destroy the devlink rate object of type leaf on provided @devlink_port. + */ void devl_rate_leaf_destroy(struct devlink_port *devlink_port) { struct devlink_rate *devlink_rate = devlink_port->devlink_rate; @@ -10037,27 +10030,6 @@ void devl_rate_leaf_destroy(struct devlink_port *devlink_port) } EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy); -/** - * devlink_rate_leaf_destroy - destroy devlink rate leaf - * - * @devlink_port: devlink port linked to the rate object - * - * Context: Takes and release devlink->lock . - */ -void devlink_rate_leaf_destroy(struct devlink_port *devlink_port) -{ - struct devlink_rate *devlink_rate = devlink_port->devlink_rate; - struct devlink *devlink = devlink_port->devlink; - - if (!devlink_rate) - return; - - mutex_lock(&devlink->lock); - devl_rate_leaf_destroy(devlink_port); - mutex_unlock(&devlink->lock); -} -EXPORT_SYMBOL_GPL(devlink_rate_leaf_destroy); - /** * devl_rate_nodes_destroy - destroy all devlink rate nodes on device * @devlink: devlink instance -- cgit v1.2.3 From 5022e221c98a609e0e5b0a73852c7e3d32f1c545 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Mon, 11 Jul 2022 15:35:49 +0800 Subject: net: change the type of ip_route_input_rcu to static The type of ip_route_input_rcu should be static. Signed-off-by: Zhengchao Shao Link: https://lore.kernel.org/r/20220711073549.8947-1-shaozhengchao@huawei.com Signed-off-by: Paolo Abeni --- include/net/route.h | 4 ---- net/ipv4/route.c | 34 +++++++++++++++++----------------- 2 files changed, 17 insertions(+), 21 deletions(-) (limited to 'include/net') diff --git a/include/net/route.h b/include/net/route.h index 991a3985712d..651424ef09c9 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -201,10 +201,6 @@ int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct in_device *in_dev, u32 *itag); int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src, u8 tos, struct net_device *devin); -int ip_route_input_rcu(struct sk_buff *skb, __be32 dst, __be32 src, - u8 tos, struct net_device *devin, - struct fib_result *res); - int ip_route_use_hint(struct sk_buff *skb, __be32 dst, __be32 src, u8 tos, struct net_device *devin, const struct sk_buff *hint); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2d16bcc7d346..8f4a8f66d604 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2439,24 +2439,9 @@ martian_source: goto out; } -int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, - u8 tos, struct net_device *dev) -{ - struct fib_result res; - int err; - - tos &= IPTOS_RT_MASK; - rcu_read_lock(); - err = ip_route_input_rcu(skb, daddr, saddr, tos, dev, &res); - rcu_read_unlock(); - - return err; -} -EXPORT_SYMBOL(ip_route_input_noref); - /* called with rcu_read_lock held */ -int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, - u8 tos, struct net_device *dev, struct fib_result *res) +static int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, + u8 tos, struct net_device *dev, struct fib_result *res) { /* Multicast recognition logic is moved from route cache to here. * The problem was that too many Ethernet cards have broken/missing @@ -2505,6 +2490,21 @@ int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, return ip_route_input_slow(skb, daddr, saddr, tos, dev, res); } +int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, + u8 tos, struct net_device *dev) +{ + struct fib_result res; + int err; + + tos &= IPTOS_RT_MASK; + rcu_read_lock(); + err = ip_route_input_rcu(skb, daddr, saddr, tos, dev, &res); + rcu_read_unlock(); + + return err; +} +EXPORT_SYMBOL(ip_route_input_noref); + /* called with rcu_read_lock() */ static struct rtable *__mkroute_output(const struct fib_result *res, const struct flowi4 *fl4, int orig_oif, -- cgit v1.2.3 From 83d85bb069152b790caad905fa53e6d50cd3734d Mon Sep 17 00:00:00 2001 From: Maksym Glubokiy Date: Mon, 11 Jul 2022 18:09:07 +0300 Subject: net: extract port range fields from fl_flow_key So it can be used for port range filter offloading. Co-developed-by: Volodymyr Mytnyk Signed-off-by: Volodymyr Mytnyk Signed-off-by: Maksym Glubokiy Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 16 ++++++++++++++++ include/net/flow_offload.h | 6 ++++++ net/core/flow_offload.c | 7 +++++++ net/sched/cls_flower.c | 8 +------- 4 files changed, 30 insertions(+), 7 deletions(-) (limited to 'include/net') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index a4c6057c7097..0f9544a9bb9e 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -178,6 +178,22 @@ struct flow_dissector_key_ports { }; }; +/** + * struct flow_dissector_key_ports_range + * @tp: port number from packet + * @tp_min: min port number in range + * @tp_max: max port number in range + */ +struct flow_dissector_key_ports_range { + union { + struct flow_dissector_key_ports tp; + struct { + struct flow_dissector_key_ports tp_min; + struct flow_dissector_key_ports tp_max; + }; + }; +}; + /** * flow_dissector_key_icmp: * type: ICMP type diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h index 7ac313858037..a8d8512b7059 100644 --- a/include/net/flow_offload.h +++ b/include/net/flow_offload.h @@ -48,6 +48,10 @@ struct flow_match_ports { struct flow_dissector_key_ports *key, *mask; }; +struct flow_match_ports_range { + struct flow_dissector_key_ports_range *key, *mask; +}; + struct flow_match_icmp { struct flow_dissector_key_icmp *key, *mask; }; @@ -94,6 +98,8 @@ void flow_rule_match_ip(const struct flow_rule *rule, struct flow_match_ip *out); void flow_rule_match_ports(const struct flow_rule *rule, struct flow_match_ports *out); +void flow_rule_match_ports_range(const struct flow_rule *rule, + struct flow_match_ports_range *out); void flow_rule_match_tcp(const struct flow_rule *rule, struct flow_match_tcp *out); void flow_rule_match_icmp(const struct flow_rule *rule, diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c index 929f6379a279..0d3075d3c8fb 100644 --- a/net/core/flow_offload.c +++ b/net/core/flow_offload.c @@ -125,6 +125,13 @@ void flow_rule_match_ports(const struct flow_rule *rule, } EXPORT_SYMBOL(flow_rule_match_ports); +void flow_rule_match_ports_range(const struct flow_rule *rule, + struct flow_match_ports_range *out) +{ + FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS_RANGE, out); +} +EXPORT_SYMBOL(flow_rule_match_ports_range); + void flow_rule_match_tcp(const struct flow_rule *rule, struct flow_match_tcp *out) { diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index dcca70144dff..1a1e34480b7e 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -63,13 +63,7 @@ struct fl_flow_key { struct flow_dissector_key_ip ip; struct flow_dissector_key_ip enc_ip; struct flow_dissector_key_enc_opts enc_opts; - union { - struct flow_dissector_key_ports tp; - struct { - struct flow_dissector_key_ports tp_min; - struct flow_dissector_key_ports tp_max; - }; - } tp_range; + struct flow_dissector_key_ports_range tp_range; struct flow_dissector_key_ct ct; struct flow_dissector_key_hash hash; struct flow_dissector_key_num_of_vlans num_of_vlans; -- cgit v1.2.3 From 277cbb6bc4bd398133eb5327c5256482a2289fe1 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 Jul 2022 12:24:24 +0200 Subject: net: devlink: move unlocked function prototypes alongside the locked ones Maintain the same order as it is in devlink.c for function prototypes. The most of the locked variants would very likely soon be removed and the unlocked version would be the only one. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/net/devlink.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 5150deb67fab..b1b5c19a8316 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1521,15 +1521,6 @@ void devl_unlock(struct devlink *devlink); void devl_assert_locked(struct devlink *devlink); bool devl_lock_is_held(struct devlink *devlink); -int devl_port_register(struct devlink *devlink, - struct devlink_port *devlink_port, - unsigned int port_index); -void devl_port_unregister(struct devlink_port *devlink_port); - -int devl_rate_leaf_create(struct devlink_port *port, void *priv); -void devl_rate_leaf_destroy(struct devlink_port *devlink_port); -void devl_rate_nodes_destroy(struct devlink *devlink); - struct ib_device; struct net *devlink_net(const struct devlink *devlink); @@ -1551,9 +1542,13 @@ void devlink_set_features(struct devlink *devlink, u64 features); void devlink_register(struct devlink *devlink); void devlink_unregister(struct devlink *devlink); void devlink_free(struct devlink *devlink); +int devl_port_register(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index); int devlink_port_register(struct devlink *devlink, struct devlink_port *devlink_port, unsigned int port_index); +void devl_port_unregister(struct devlink_port *devlink_port); void devlink_port_unregister(struct devlink_port *devlink_port); void devlink_port_type_eth_set(struct devlink_port *devlink_port, struct net_device *netdev); @@ -1569,6 +1564,9 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 controller, u16 pf, u32 sf, bool external); +int devl_rate_leaf_create(struct devlink_port *port, void *priv); +void devl_rate_leaf_destroy(struct devlink_port *devlink_port); +void devl_rate_nodes_destroy(struct devlink *devlink); void devlink_port_linecard_set(struct devlink_port *devlink_port, struct devlink_linecard *linecard); struct devlink_linecard * -- cgit v1.2.3 From bc5c8260f4114951de3b4ec629650a722ca58a2b Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Wed, 13 Jul 2022 09:54:38 +0800 Subject: net/sched: remove return value of unregister_tcf_proto_ops Return value of unregister_tcf_proto_ops is unused, remove it. Signed-off-by: Zhengchao Shao Signed-off-by: David S. Miller --- include/net/pkt_cls.h | 2 +- net/sched/cls_api.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 8cf001aed858..d9d90e6925e1 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -23,7 +23,7 @@ struct tcf_walker { }; int register_tcf_proto_ops(struct tcf_proto_ops *ops); -int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); +void unregister_tcf_proto_ops(struct tcf_proto_ops *ops); struct tcf_block_ext_info { enum flow_block_binder_type binder_type; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 9bb4d3dcc994..c7a240232b8d 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -194,7 +194,7 @@ EXPORT_SYMBOL(register_tcf_proto_ops); static struct workqueue_struct *tc_filter_wq; -int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) +void unregister_tcf_proto_ops(struct tcf_proto_ops *ops) { struct tcf_proto_ops *t; int rc = -ENOENT; @@ -214,7 +214,8 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops) } } write_unlock(&cls_mod_lock); - return rc; + + WARN(rc, "unregister tc filter kind(%s) failed %d\n", ops->kind, rc); } EXPORT_SYMBOL(unregister_tcf_proto_ops); -- cgit v1.2.3 From 9d2f00fb0a0ce0d1127e54cac5217b6517ab0d54 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Wed, 29 Jun 2022 13:22:10 -0600 Subject: netfilter: nf_nat: in nf_nat_initialized(), use const struct nf_conn * nf_nat_initialized() doesn't modify passed struct nf_conn, so declare as const. This is helpful for code readability and makes it possible to call nf_nat_initialized() with a const struct nf_conn *. Signed-off-by: James Yonan Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_nat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 987111ae5240..e9eb01e99d2f 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h @@ -104,7 +104,7 @@ unsigned int nf_nat_inet_fn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state); -static inline int nf_nat_initialized(struct nf_conn *ct, +static inline int nf_nat_initialized(const struct nf_conn *ct, enum nf_nat_manip_type manip) { if (manip == NF_NAT_MANIP_SRC) -- cgit v1.2.3 From ca2e1a627035002cd33d9667431e80bad90c25fa Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 7 Jul 2022 15:08:42 +0200 Subject: xsk: Mark napi_id on sendmsg() When application runs in busy poll mode and does not receive a single packet but only sends them, it is currently impossible to get into napi_busy_loop() as napi_id is only marked on Rx side in xsk_rcv_check(). In there, napi_id is being taken from xdp_rxq_info carried by xdp_buff. From Tx perspective, we do not have access to it. What we have handy is the xsk pool. Xsk pool works on a pool of internal xdp_buff wrappers called xdp_buff_xsk. AF_XDP ZC enabled drivers call xp_set_rxq_info() so each of xdp_buff_xsk has a valid pointer to xdp_rxq_info of underlying queue. Therefore, on Tx side, napi_id can be pulled from xs->pool->heads[0].xdp.rxq->napi_id. Hide this pointer chase under helper function, xsk_pool_get_napi_id(). Do this only for sockets working in ZC mode as otherwise rxq pointers would not be initialized. Signed-off-by: Maciej Fijalkowski Signed-off-by: Daniel Borkmann Acked-by: Magnus Karlsson Link: https://lore.kernel.org/bpf/20220707130842.49408-1-maciej.fijalkowski@intel.com --- include/net/xdp_sock_drv.h | 14 ++++++++++++++ net/xdp/xsk.c | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h index 4aa031849668..4277b0dcee05 100644 --- a/include/net/xdp_sock_drv.h +++ b/include/net/xdp_sock_drv.h @@ -44,6 +44,15 @@ static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool, xp_set_rxq_info(pool, rxq); } +static inline unsigned int xsk_pool_get_napi_id(struct xsk_buff_pool *pool) +{ +#ifdef CONFIG_NET_RX_BUSY_POLL + return pool->heads[0].xdp.rxq->napi_id; +#else + return 0; +#endif +} + static inline void xsk_pool_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs) { @@ -198,6 +207,11 @@ static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool, { } +static inline unsigned int xsk_pool_get_napi_id(struct xsk_buff_pool *pool) +{ + return 0; +} + static inline void xsk_pool_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs) { diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 09002387987e..5b4ce6ba1bc7 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -639,8 +639,11 @@ static int __xsk_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len if (unlikely(need_wait)) return -EOPNOTSUPP; - if (sk_can_busy_loop(sk)) + if (sk_can_busy_loop(sk)) { + if (xs->zc) + __sk_mark_napi_id_once(sk, xsk_pool_get_napi_id(xs->pool)); sk_busy_loop(sk, 1); /* only support non-blocking sockets */ + } if (xs->zc && xsk_no_wakeup(sk)) return 0; -- cgit v1.2.3 From 9a7923668bc779dd601d94704b4dd895a2ef6a77 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 13 Jul 2022 16:18:51 +0200 Subject: net: devlink: make devlink_dpipe_headers_register() return void The return value is not used, so change the return value type to void. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | 6 ++---- include/net/devlink.h | 2 +- net/core/devlink.c | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index 5d494fabf93d..c2540292702d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -1266,10 +1266,8 @@ int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int err; - err = devlink_dpipe_headers_register(devlink, - &mlxsw_sp_dpipe_headers); - if (err) - return err; + devlink_dpipe_headers_register(devlink, &mlxsw_sp_dpipe_headers); + err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); if (err) goto err_erif_table_init; diff --git a/include/net/devlink.h b/include/net/devlink.h index b1b5c19a8316..88c701b375a2 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1590,7 +1590,7 @@ int devlink_dpipe_table_register(struct devlink *devlink, void *priv, bool counter_control_extern); void devlink_dpipe_table_unregister(struct devlink *devlink, const char *table_name); -int devlink_dpipe_headers_register(struct devlink *devlink, +void devlink_dpipe_headers_register(struct devlink *devlink, struct devlink_dpipe_headers *dpipe_headers); void devlink_dpipe_headers_unregister(struct devlink *devlink); bool devlink_dpipe_table_counter_enabled(struct devlink *devlink, diff --git a/net/core/devlink.c b/net/core/devlink.c index 2b2e454ebd78..c261bba9ab76 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10425,13 +10425,12 @@ EXPORT_SYMBOL_GPL(devlink_sb_unregister); * * Register the headers supported by hardware. */ -int devlink_dpipe_headers_register(struct devlink *devlink, - struct devlink_dpipe_headers *dpipe_headers) +void devlink_dpipe_headers_register(struct devlink *devlink, + struct devlink_dpipe_headers *dpipe_headers) { devl_lock(devlink); devlink->dpipe_headers = dpipe_headers; devl_unlock(devlink); - return 0; } EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register); -- cgit v1.2.3 From 577e5b8c3924539c7a09e3e00477534f39e61829 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 8 Jun 2022 12:01:12 +0300 Subject: wifi: cfg80211: add API to add/modify/remove a link station Add an API for adding/modifying/removing a link of a station. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 64 +++++++++++++++++ include/uapi/linux/nl80211.h | 8 +++ net/wireless/nl80211.c | 168 ++++++++++++++++++++++++++++++++++++++++--- net/wireless/rdev-ops.h | 48 +++++++++++++ net/wireless/trace.h | 97 +++++++++++++++++++++++++ 5 files changed, 377 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3bcdd20ace66..422764881269 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1456,6 +1456,61 @@ struct sta_txpwr { enum nl80211_tx_power_setting type; }; +/** + * struct link_station_parameters - link station parameters + * + * Used to change and create a new link station. + * + * @mld_mac: MAC address of the station + * @link_id: the link id (-1 for non-MLD station) + * @link_mac: MAC address of the link + * @supported_rates: supported rates in IEEE 802.11 format + * (or NULL for no change) + * @supported_rates_len: number of supported rates + * @ht_capa: HT capabilities of station + * @vht_capa: VHT capabilities of station + * @opmode_notif: operating mode field from Operating Mode Notification + * @opmode_notif_used: information if operating mode field is used + * @he_capa: HE capabilities of station + * @he_capa_len: the length of the HE capabilities + * @txpwr: transmit power for an associated station + * @txpwr_set: txpwr field is set + * @he_6ghz_capa: HE 6 GHz Band capabilities of station + * @eht_capa: EHT capabilities of station + * @eht_capa_len: the length of the EHT capabilities + */ +struct link_station_parameters { + const u8 *mld_mac; + int link_id; + const u8 *link_mac; + const u8 *supported_rates; + u8 supported_rates_len; + const struct ieee80211_ht_cap *ht_capa; + const struct ieee80211_vht_cap *vht_capa; + u8 opmode_notif; + bool opmode_notif_used; + const struct ieee80211_he_cap_elem *he_capa; + u8 he_capa_len; + struct sta_txpwr txpwr; + bool txpwr_set; + const struct ieee80211_he_6ghz_capa *he_6ghz_capa; + const struct ieee80211_eht_cap_elem *eht_capa; + u8 eht_capa_len; +}; + +/** + * struct link_station_del_parameters - link station deletion parameters + * + * Used to delete a link station entry (or all stations). + * + * @mld_mac: MAC address of the station + * @link_id: the link id + */ +struct link_station_del_parameters { + const u8 *mld_mac; + u32 link_id; +}; + /** * struct station_parameters - station parameters * @@ -4215,6 +4270,9 @@ struct mgmt_frame_regs { * radar channel. * The caller is expected to set chandef pointer to NULL in order to * disable background CAC/radar detection. + * @add_link_station: Add a link to a station. + * @mod_link_station: Modify a link of a station. + * @del_link_station: Remove a link of a station. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -4560,6 +4618,12 @@ struct cfg80211_ops { struct cfg80211_fils_aad *fils_aad); int (*set_radar_background)(struct wiphy *wiphy, struct cfg80211_chan_def *chandef); + int (*add_link_station)(struct wiphy *wiphy, struct net_device *dev, + struct link_station_parameters *params); + int (*mod_link_station)(struct wiphy *wiphy, struct net_device *dev, + struct link_station_parameters *params); + int (*del_link_station)(struct wiphy *wiphy, struct net_device *dev, + struct link_station_del_parameters *params); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7bb1ae59f3a5..37bfc934325a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1254,6 +1254,10 @@ * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links * in preparation for e.g. roaming to a regular (non-MLO) AP. * + * @NL80211_CMD_ADD_LINK_STA: Add a link to an MLD station + * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station + * @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1501,6 +1505,10 @@ enum nl80211_commands { NL80211_CMD_ADD_LINK, NL80211_CMD_REMOVE_LINK, + NL80211_CMD_ADD_LINK_STA, + NL80211_CMD_MODIFY_LINK_STA, + NL80211_CMD_REMOVE_LINK_STA, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 22c4cf6fbb57..3cf8e01e3f7e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6801,7 +6801,8 @@ static int nl80211_set_station_tdls(struct genl_info *info, } static int nl80211_parse_sta_txpower_setting(struct genl_info *info, - struct station_parameters *params) + struct sta_txpwr *txpwr, + bool *txpwr_set) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; int idx; @@ -6813,18 +6814,20 @@ static int nl80211_parse_sta_txpower_setting(struct genl_info *info, return -EOPNOTSUPP; idx = NL80211_ATTR_STA_TX_POWER_SETTING; - params->txpwr.type = nla_get_u8(info->attrs[idx]); + txpwr->type = nla_get_u8(info->attrs[idx]); - if (params->txpwr.type == NL80211_TX_POWER_LIMITED) { + if (txpwr->type == NL80211_TX_POWER_LIMITED) { idx = NL80211_ATTR_STA_TX_POWER; if (info->attrs[idx]) - params->txpwr.power = - nla_get_s16(info->attrs[idx]); + txpwr->power = nla_get_s16(info->attrs[idx]); else return -EINVAL; } - params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; + + *txpwr_set = true; + } else { + *txpwr_set = false; } return 0; @@ -6837,6 +6840,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) struct station_parameters params; u8 *mac_addr; int err; + bool txpwr_set; memset(¶ms, 0, sizeof(params)); @@ -6930,9 +6934,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) return -EOPNOTSUPP; - err = nl80211_parse_sta_txpower_setting(info, ¶ms); + err = nl80211_parse_sta_txpower_setting(info, ¶ms.txpwr, &txpwr_set); if (err) return err; + if (txpwr_set) + params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; /* Include parameters for TDLS peer (will check later) */ err = nl80211_set_station_tdls(info, ¶ms); @@ -6975,6 +6981,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) u8 *mac_addr = NULL; u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) | BIT(NL80211_STA_FLAG_ASSOCIATED); + bool txpwr_set; memset(¶ms, 0, sizeof(params)); @@ -7085,9 +7092,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) return -EOPNOTSUPP; - err = nl80211_parse_sta_txpower_setting(info, ¶ms); + err = nl80211_parse_sta_txpower_setting(info, ¶ms.txpwr, &txpwr_set); if (err) return err; + if (txpwr_set) + params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; err = nl80211_parse_sta_channel_info(info, ¶ms); if (err) @@ -15682,6 +15691,128 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) return 0; } +static int +nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info, + bool add) +{ + struct link_station_parameters params = {}; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + int err; + + if ((add && !rdev->ops->add_link_station) || + (!add && !rdev->ops->mod_link_station)) + return -EOPNOTSUPP; + + if (add && !info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (add && !info->attrs[NL80211_ATTR_MLD_ADDR]) + return -EINVAL; + + if (add && !info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MLD_ADDR]) + params.mld_mac = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + + if (info->attrs[NL80211_ATTR_MAC]) { + params.link_mac = nla_data(info->attrs[NL80211_ATTR_MAC]); + if (!is_valid_ether_addr(params.link_mac)) + return -EINVAL; + } + + if (!info->attrs[NL80211_ATTR_MLO_LINK_ID]) + return -EINVAL; + + params.link_id = nla_get_u8(info->attrs[NL80211_ATTR_MLO_LINK_ID]); + + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { + params.supported_rates = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.supported_rates_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + } + + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + + if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) + params.vht_capa = + nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + + if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) { + params.he_capa = + nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + params.he_capa_len = + nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + + if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) { + params.eht_capa = + nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); + params.eht_capa_len = + nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); + + if (!ieee80211_eht_capa_size_ok((const u8 *)params.he_capa, + (const u8 *)params.eht_capa, + params.eht_capa_len)) + return -EINVAL; + } + } + + if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]) + params.he_6ghz_capa = + nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]); + + if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { + params.opmode_notif_used = true; + params.opmode_notif = + nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); + } + + err = nl80211_parse_sta_txpower_setting(info, ¶ms.txpwr, + ¶ms.txpwr_set); + if (err) + return err; + + if (add) + return rdev_add_link_station(rdev, dev, ¶ms); + return rdev_mod_link_station(rdev, dev, ¶ms); +} + +static int +nl80211_add_link_station(struct sk_buff *skb, struct genl_info *info) +{ + return nl80211_add_mod_link_station(skb, info, true); +} + +static int +nl80211_modify_link_station(struct sk_buff *skb, struct genl_info *info) +{ + return nl80211_add_mod_link_station(skb, info, false); +} + +static int +nl80211_remove_link_station(struct sk_buff *skb, struct genl_info *info) +{ + struct link_station_del_parameters params = {}; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + + if (!rdev->ops->del_link_station) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_MLD_ADDR] || + !info->attrs[NL80211_ATTR_MLO_LINK_ID]) + return -EINVAL; + + params.mld_mac = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + params.link_id = nla_get_u8(info->attrs[NL80211_ATTR_MLO_LINK_ID]); + + return rdev_del_link_station(rdev, dev, ¶ms); +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -16832,6 +16963,27 @@ static const struct genl_small_ops nl80211_small_ops[] = { .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_MLO_VALID_LINK_ID), }, + { + .cmd = NL80211_CMD_ADD_LINK_STA, + .doit = nl80211_add_link_station, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), + }, + { + .cmd = NL80211_CMD_MODIFY_LINK_STA, + .doit = nl80211_modify_link_station, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), + }, + { + .cmd = NL80211_CMD_REMOVE_LINK_STA, + .doit = nl80211_remove_link_station, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), + }, }; static struct genl_family nl80211_fam __ro_after_init = { diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index a329ba036989..6221a996c19f 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1448,4 +1448,52 @@ rdev_del_intf_link(struct cfg80211_registered_device *rdev, trace_rdev_return_void(&rdev->wiphy); } +static inline int +rdev_add_link_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct link_station_parameters *params) +{ + int ret; + + if (!rdev->ops->add_link_station) + return -EOPNOTSUPP; + + trace_rdev_add_link_station(&rdev->wiphy, dev, params); + ret = rdev->ops->add_link_station(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + +static inline int +rdev_mod_link_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct link_station_parameters *params) +{ + int ret; + + if (!rdev->ops->mod_link_station) + return -EOPNOTSUPP; + + trace_rdev_mod_link_station(&rdev->wiphy, dev, params); + ret = rdev->ops->mod_link_station(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + +static inline int +rdev_del_link_station(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct link_station_del_parameters *params) +{ + int ret; + + if (!rdev->ops->del_link_station) + return -EOPNOTSUPP; + + trace_rdev_del_link_station(&rdev->wiphy, dev, params); + ret = rdev->ops->del_link_station(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 65f8b814ecd0..16d0fe53fcf2 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3775,6 +3775,103 @@ TRACE_EVENT(cfg80211_assoc_comeback, WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout) ); +DECLARE_EVENT_CLASS(link_station_add_mod, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct link_station_parameters *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __array(u8, mld_mac, 6) + __array(u8, link_mac, 6) + __field(u32, link_id) + __dynamic_array(u8, supported_rates, + params->supported_rates_len) + __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap)) + __array(u8, vht_capa, (int)sizeof(struct ieee80211_vht_cap)) + __field(u8, opmode_notif) + __field(bool, opmode_notif_used) + __dynamic_array(u8, he_capa, params->he_capa_len) + __array(u8, he_6ghz_capa, (int)sizeof(struct ieee80211_he_6ghz_capa)) + __dynamic_array(u8, eht_capa, params->eht_capa_len) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + memset(__entry->mld_mac, 0, 6); + memset(__entry->link_mac, 0, 6); + if (params->mld_mac) + memcpy(__entry->mld_mac, params->mld_mac, 6); + if (params->link_mac) + memcpy(__entry->link_mac, params->link_mac, 6); + __entry->link_id = params->link_id; + if (params->supported_rates && params->supported_rates_len) + memcpy(__get_dynamic_array(supported_rates), + params->supported_rates, + params->supported_rates_len); + memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap)); + if (params->ht_capa) + memcpy(__entry->ht_capa, params->ht_capa, + sizeof(struct ieee80211_ht_cap)); + memset(__entry->vht_capa, 0, sizeof(struct ieee80211_vht_cap)); + if (params->vht_capa) + memcpy(__entry->vht_capa, params->vht_capa, + sizeof(struct ieee80211_vht_cap)); + __entry->opmode_notif = params->opmode_notif; + __entry->opmode_notif_used = params->opmode_notif_used; + if (params->he_capa && params->he_capa_len) + memcpy(__get_dynamic_array(he_capa), params->he_capa, + params->he_capa_len); + memset(__entry->he_6ghz_capa, 0, sizeof(struct ieee80211_he_6ghz_capa)); + if (params->he_6ghz_capa) + memcpy(__entry->he_6ghz_capa, params->he_6ghz_capa, + sizeof(struct ieee80211_he_6ghz_capa)); + if (params->eht_capa && params->eht_capa_len) + memcpy(__get_dynamic_array(eht_capa), params->eht_capa, + params->eht_capa_len); + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + ", link mac: " MAC_PR_FMT ", link id: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(mld_mac), + MAC_PR_ARG(link_mac), __entry->link_id) +); + +DEFINE_EVENT(link_station_add_mod, rdev_add_link_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct link_station_parameters *params), + TP_ARGS(wiphy, netdev, params) +); + +DEFINE_EVENT(link_station_add_mod, rdev_mod_link_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct link_station_parameters *params), + TP_ARGS(wiphy, netdev, params) +); + +TRACE_EVENT(rdev_del_link_station, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct link_station_del_parameters *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __array(u8, mld_mac, 6) + __field(u32, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + memset(__entry->mld_mac, 0, 6); + if (params->mld_mac) + memcpy(__entry->mld_mac, params->mld_mac, 6); + __entry->link_id = params->link_id; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT + ", link id: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(mld_mac), + __entry->link_id) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From b95eb7f0eee479478eb1a7c0a42a80167708c1df Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 14 Jun 2022 13:49:16 +0300 Subject: wifi: cfg80211/mac80211: separate link params from station params Put the link_station_parameters structure in the station_parameters structure (and remove the station_parameters fields already existing in link_station_parameters). Now, for an MLD station, the default link is added together with the station. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 20 ++-- drivers/net/wireless/microchip/wilc1000/hif.c | 20 ++-- include/net/cfg80211.h | 28 +---- net/mac80211/cfg.c | 143 ++++++++++++++++--------- net/wireless/nl80211.c | 97 +++++++++-------- net/wireless/trace.h | 24 +++-- 6 files changed, 180 insertions(+), 152 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 1e2798dce18f..851ea58fb38e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1790,29 +1790,31 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, wmm_qos_info->qos_info = 0; config_len += sizeof(struct mwifiex_ie_types_qos_info); - if (params->ht_capa) { + if (params->link_sta_params.ht_capa) { ht_capab = (struct mwifiex_ie_types_htcap *)(pos + config_len); ht_capab->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ht_capab->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); - memcpy(&ht_capab->ht_cap, params->ht_capa, + memcpy(&ht_capab->ht_cap, params->link_sta_params.ht_capa, sizeof(struct ieee80211_ht_cap)); config_len += sizeof(struct mwifiex_ie_types_htcap); } - if (params->supported_rates && params->supported_rates_len) { + if (params->link_sta_params.supported_rates && + params->link_sta_params.supported_rates_len) { tlv_rates = (struct host_cmd_tlv_rates *)(pos + config_len); tlv_rates->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); tlv_rates->header.len = - cpu_to_le16(params->supported_rates_len); - memcpy(tlv_rates->rates, params->supported_rates, - params->supported_rates_len); + cpu_to_le16(params->link_sta_params.supported_rates_len); + memcpy(tlv_rates->rates, + params->link_sta_params.supported_rates, + params->link_sta_params.supported_rates_len); config_len += sizeof(struct host_cmd_tlv_rates) + - params->supported_rates_len; + params->link_sta_params.supported_rates_len; } if (params->ext_capab && params->ext_capab_len) { @@ -1826,14 +1828,14 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, config_len += sizeof(struct mwifiex_ie_types_extcap) + params->ext_capab_len; } - if (params->vht_capa) { + if (params->link_sta_params.vht_capa) { vht_capab = (struct mwifiex_ie_types_vhtcap *)(pos + config_len); vht_capab->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY); vht_capab->header.len = cpu_to_le16(sizeof(struct ieee80211_vht_cap)); - memcpy(&vht_capab->vht_cap, params->vht_capa, + memcpy(&vht_capab->vht_cap, params->link_sta_params.vht_capa, sizeof(struct ieee80211_vht_cap)); config_len += sizeof(struct mwifiex_ie_types_vhtcap); } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 4038a254465f..021e0db80bd2 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -816,15 +816,15 @@ static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac, put_unaligned_le16(params->aid, cur_byte); cur_byte += 2; - *cur_byte++ = params->supported_rates_len; - if (params->supported_rates_len > 0) - memcpy(cur_byte, params->supported_rates, - params->supported_rates_len); - cur_byte += params->supported_rates_len; + *cur_byte++ = params->link_sta_params.supported_rates_len; + if (params->link_sta_params.supported_rates_len > 0) + memcpy(cur_byte, params->link_sta_params.supported_rates, + params->link_sta_params.supported_rates_len); + cur_byte += params->link_sta_params.supported_rates_len; - if (params->ht_capa) { + if (params->link_sta_params.ht_capa) { *cur_byte++ = true; - memcpy(cur_byte, params->ht_capa, + memcpy(cur_byte, params->link_sta_params.ht_capa, sizeof(struct ieee80211_ht_cap)); } else { *cur_byte++ = false; @@ -1799,7 +1799,8 @@ int wilc_add_station(struct wilc_vif *vif, const u8 *mac, wid.id = WID_ADD_STA; wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.size = WILC_ADD_STA_LENGTH + + params->link_sta_params.supported_rates_len; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) return -ENOMEM; @@ -1884,7 +1885,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, wid.id = WID_EDIT_STA; wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.size = WILC_ADD_STA_LENGTH + + params->link_sta_params.supported_rates_len; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) return -ENOMEM; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 422764881269..c904cbd1c4d6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1433,7 +1433,6 @@ enum station_parameters_apply_mask { STATION_PARAM_APPLY_UAPSD = BIT(0), STATION_PARAM_APPLY_CAPABILITY = BIT(1), STATION_PARAM_APPLY_PLINK_STATE = BIT(2), - STATION_PARAM_APPLY_STA_TXPOWER = BIT(3), }; /** @@ -1517,9 +1516,6 @@ struct link_station_del_parameters { * Used to change and create a new station. * * @vlan: vlan interface station should belong to - * @supported_rates: supported rates in IEEE 802.11 format - * (or NULL for no change) - * @supported_rates_len: number of supported rates * @sta_flags_mask: station flags that changed * (bitmask of BIT(%NL80211_STA_FLAG_...)) * @sta_flags_set: station flags values @@ -1530,8 +1526,6 @@ struct link_station_del_parameters { * @peer_aid: mesh peer AID or zero for no change * @plink_action: plink action to take * @plink_state: set the peer link state for a station - * @ht_capa: HT capabilities of station - * @vht_capa: VHT capabilities of station * @uapsd_queues: bitmap of queues configured for uapsd. same format * as the AC bitmap in the QoS info field * @max_sp: max Service Period. same format as the MAX_SP in the @@ -1548,19 +1542,11 @@ struct link_station_del_parameters { * @supported_channels_len: number of supported channels * @supported_oper_classes: supported oper classes in IEEE 802.11 format * @supported_oper_classes_len: number of supported operating classes - * @opmode_notif: operating mode field from Operating Mode Notification - * @opmode_notif_used: information if operating mode field is used * @support_p2p_ps: information if station supports P2P PS mechanism - * @he_capa: HE capabilities of station - * @he_capa_len: the length of the HE capabilities * @airtime_weight: airtime scheduler weight for this station - * @txpwr: transmit power for an associated station - * @he_6ghz_capa: HE 6 GHz Band capabilities of station - * @eht_capa: EHT capabilities of station - * @eht_capa_len: the length of the EHT capabilities + * @link_sta_params: link related params. */ struct station_parameters { - const u8 *supported_rates; struct net_device *vlan; u32 sta_flags_mask, sta_flags_set; u32 sta_modify_mask; @@ -1568,11 +1554,8 @@ struct station_parameters { u16 aid; u16 vlan_id; u16 peer_aid; - u8 supported_rates_len; u8 plink_action; u8 plink_state; - const struct ieee80211_ht_cap *ht_capa; - const struct ieee80211_vht_cap *vht_capa; u8 uapsd_queues; u8 max_sp; enum nl80211_mesh_power_mode local_pm; @@ -1583,16 +1566,9 @@ struct station_parameters { u8 supported_channels_len; const u8 *supported_oper_classes; u8 supported_oper_classes_len; - u8 opmode_notif; - bool opmode_notif_used; int support_p2p_ps; - const struct ieee80211_he_cap_elem *he_capa; - u8 he_capa_len; u16 airtime_weight; - struct sta_txpwr txpwr; - const struct ieee80211_he_6ghz_capa *he_6ghz_capa; - const struct ieee80211_eht_cap_elem *eht_capa; - u8 eht_capa_len; + struct link_station_parameters link_sta_params; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 64801ab545c1..3eacf72279c2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1581,6 +1581,83 @@ static void sta_apply_mesh_params(struct ieee80211_local *local, #endif } +static int sta_link_apply_parameters(struct ieee80211_local *local, + struct sta_info *sta, + struct link_station_parameters *params) +{ + int ret = 0; + struct ieee80211_supported_band *sband; + struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 link_id = params->link_id < 0 ? 0 : params->link_id; + struct link_sta_info *link_sta = + rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&local->sta_mtx)); + + if (!link_sta) + return -EINVAL; + + sband = ieee80211_get_link_sband(sdata, link_id); + if (!sband) + return -EINVAL; + + if (params->link_mac) { + memcpy(link_sta->addr, params->link_mac, ETH_ALEN); + memcpy(link_sta->pub->addr, params->link_mac, ETH_ALEN); + } + + if (params->txpwr_set) { + link_sta->pub->txpwr.type = params->txpwr.type; + if (params->txpwr.type == NL80211_TX_POWER_LIMITED) + link_sta->pub->txpwr.power = params->txpwr.power; + ret = drv_sta_set_txpwr(local, sdata, sta); + if (ret) + return ret; + } + + if (params->supported_rates && + params->supported_rates_len) { + ieee80211_parse_bitrates(&sdata->vif.link_conf[link_id]->chandef, + sband, params->supported_rates, + params->supported_rates_len, + &link_sta->pub->supp_rates[sband->band]); + } + + if (params->ht_capa) + ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, + params->ht_capa, link_sta); + + /* VHT can override some HT caps such as the A-MSDU max length */ + if (params->vht_capa) + ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, + params->vht_capa, link_sta); + + if (params->he_capa) + ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, + (void *)params->he_capa, + params->he_capa_len, + (void *)params->he_6ghz_capa, + link_sta); + + if (params->eht_capa) + ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, + (u8 *)params->he_capa, + params->he_capa_len, + params->eht_capa, + params->eht_capa_len, + link_sta); + + if (params->opmode_notif_used) { + /* returned value is only needed for rc update, but the + * rc isn't initialized here yet, so ignore it + */ + __ieee80211_vht_handle_opmode(sdata, link_sta, + params->opmode_notif, + sband->band); + } + + return ret; +} + static int sta_apply_parameters(struct ieee80211_local *local, struct sta_info *sta, struct station_parameters *params) @@ -1588,9 +1665,11 @@ static int sta_apply_parameters(struct ieee80211_local *local, int ret = 0; struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 link_id = params->link_sta_params.link_id < 0 ? + 0 : params->link_sta_params.link_id; u32 mask, set; - sband = ieee80211_get_sband(sdata); + sband = ieee80211_get_link_sband(sdata, link_id); if (!sband) return -EINVAL; @@ -1721,56 +1800,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (params->listen_interval >= 0) sta->listen_interval = params->listen_interval; - if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) { - sta->sta.deflink.txpwr.type = params->txpwr.type; - if (params->txpwr.type == NL80211_TX_POWER_LIMITED) - sta->sta.deflink.txpwr.power = params->txpwr.power; - ret = drv_sta_set_txpwr(local, sdata, sta); - if (ret) - return ret; - } - - if (params->supported_rates && params->supported_rates_len) { - ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, - sband, params->supported_rates, - params->supported_rates_len, - &sta->sta.deflink.supp_rates[sband->band]); - } - - if (params->ht_capa) - ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - params->ht_capa, - &sta->deflink); - - /* VHT can override some HT caps such as the A-MSDU max length */ - if (params->vht_capa) - ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - params->vht_capa, - &sta->deflink); - - if (params->he_capa) - ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, - (void *)params->he_capa, - params->he_capa_len, - (void *)params->he_6ghz_capa, - &sta->deflink); - - if (params->eht_capa) - ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, - (u8 *)params->he_capa, - params->he_capa_len, - params->eht_capa, - params->eht_capa_len, - &sta->deflink); - - if (params->opmode_notif_used) { - /* returned value is only needed for rc update, but the - * rc isn't initialized here yet, so ignore it - */ - __ieee80211_vht_handle_opmode(sdata, &sta->deflink, - params->opmode_notif, - sband->band); - } + ret = sta_link_apply_parameters(local, sta, ¶ms->link_sta_params); + if (ret) + return ret; if (params->support_p2p_ps >= 0) sta->sta.support_p2p_ps = params->support_p2p_ps; @@ -1821,14 +1853,21 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; - sta = sta_info_alloc(sdata, mac, -1, GFP_KERNEL); + sta = sta_info_alloc(sdata, mac, params->link_sta_params.link_id, + GFP_KERNEL); if (!sta) return -ENOMEM; if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) sta->sta.tdls = true; + /* Though the mutex is not needed here (since the station is not + * visible yet), sta_apply_parameters (and inner functions) require + * the mutex due to other paths. + */ + mutex_lock(&local->sta_mtx); err = sta_apply_parameters(local, sta, params); + mutex_unlock(&local->sta_mtx); if (err) { sta_info_free(local, sta); return err; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3cf8e01e3f7e..5f6cbc2d73b4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6573,10 +6573,12 @@ int cfg80211_check_station_change(struct wiphy *wiphy, return -EINVAL; if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY) return -EINVAL; - if (params->supported_rates) + if (params->link_sta_params.supported_rates) return -EINVAL; - if (params->ext_capab || params->ht_capa || params->vht_capa || - params->he_capa || params->eht_capa) + if (params->ext_capab || params->link_sta_params.ht_capa || + params->link_sta_params.vht_capa || + params->link_sta_params.he_capa || + params->link_sta_params.eht_capa) return -EINVAL; } @@ -6624,7 +6626,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy, return -EINVAL; /* force (at least) rates when authorizing */ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) && - !params->supported_rates) + !params->link_sta_params.supported_rates) return -EINVAL; break; case CFG80211_STA_TDLS_PEER_ACTIVE: @@ -6648,7 +6650,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy, */ if (statype != CFG80211_STA_AP_CLIENT_UNASSOC && statype != CFG80211_STA_TDLS_PEER_SETUP) - params->opmode_notif_used = false; + params->link_sta_params.opmode_notif_used = false; return 0; } @@ -6769,26 +6771,26 @@ static int nl80211_set_station_tdls(struct genl_info *info, if (info->attrs[NL80211_ATTR_PEER_AID]) params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) - params->ht_capa = + params->link_sta_params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) - params->vht_capa = + params->link_sta_params.vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) { - params->he_capa = + params->link_sta_params.he_capa = nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); - params->he_capa_len = + params->link_sta_params.he_capa_len = nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]); if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) { - params->eht_capa = + params->link_sta_params.eht_capa = nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); - params->eht_capa_len = + params->link_sta_params.eht_capa_len = nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); - if (!ieee80211_eht_capa_size_ok((const u8 *)params->he_capa, - (const u8 *)params->eht_capa, - params->eht_capa_len)) + if (!ieee80211_eht_capa_size_ok((const u8 *)params->link_sta_params.he_capa, + (const u8 *)params->link_sta_params.eht_capa, + params->link_sta_params.eht_capa_len)) return -EINVAL; } } @@ -6840,7 +6842,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) struct station_parameters params; u8 *mac_addr; int err; - bool txpwr_set; memset(¶ms, 0, sizeof(params)); @@ -6876,9 +6877,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { - params.supported_rates = + params.link_sta_params.supported_rates = nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); - params.supported_rates_len = + params.link_sta_params.supported_rates_len = nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); } @@ -6916,13 +6917,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]); if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { - params.opmode_notif_used = true; - params.opmode_notif = + params.link_sta_params.opmode_notif_used = true; + params.link_sta_params.opmode_notif = nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); } if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]) - params.he_6ghz_capa = + params.link_sta_params.he_6ghz_capa = nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]); if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) @@ -6934,11 +6935,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) return -EOPNOTSUPP; - err = nl80211_parse_sta_txpower_setting(info, ¶ms.txpwr, &txpwr_set); + err = nl80211_parse_sta_txpower_setting(info, + ¶ms.link_sta_params.txpwr, + ¶ms.link_sta_params.txpwr_set); if (err) return err; - if (txpwr_set) - params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; /* Include parameters for TDLS peer (will check later) */ err = nl80211_set_station_tdls(info, ¶ms); @@ -6981,7 +6982,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) u8 *mac_addr = NULL; u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) | BIT(NL80211_STA_FLAG_ASSOCIATED); - bool txpwr_set; memset(¶ms, 0, sizeof(params)); @@ -7001,10 +7001,13 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_PEER_AID]) return -EINVAL; + params.link_sta_params.link_id = + nl80211_link_id_or_invalid(info->attrs); + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - params.supported_rates = + params.link_sta_params.supported_rates = nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); - params.supported_rates_len = + params.link_sta_params.supported_rates_len = nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); @@ -7043,39 +7046,39 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) - params.ht_capa = + params.link_sta_params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) - params.vht_capa = + params.link_sta_params.vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) { - params.he_capa = + params.link_sta_params.he_capa = nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); - params.he_capa_len = + params.link_sta_params.he_capa_len = nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]); if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) { - params.eht_capa = + params.link_sta_params.eht_capa = nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); - params.eht_capa_len = + params.link_sta_params.eht_capa_len = nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]); - if (!ieee80211_eht_capa_size_ok((const u8 *)params.he_capa, - (const u8 *)params.eht_capa, - params.eht_capa_len)) + if (!ieee80211_eht_capa_size_ok((const u8 *)params.link_sta_params.he_capa, + (const u8 *)params.link_sta_params.eht_capa, + params.link_sta_params.eht_capa_len)) return -EINVAL; } } if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]) - params.he_6ghz_capa = + params.link_sta_params.he_6ghz_capa = nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]); if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { - params.opmode_notif_used = true; - params.opmode_notif = + params.link_sta_params.opmode_notif_used = true; + params.link_sta_params.opmode_notif = nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); } @@ -7092,11 +7095,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) return -EOPNOTSUPP; - err = nl80211_parse_sta_txpower_setting(info, ¶ms.txpwr, &txpwr_set); + err = nl80211_parse_sta_txpower_setting(info, + ¶ms.link_sta_params.txpwr, + ¶ms.link_sta_params.txpwr_set); if (err) return err; - if (txpwr_set) - params.sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; err = nl80211_parse_sta_channel_info(info, ¶ms); if (err) @@ -7115,17 +7118,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) * error in this case. */ if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) { - params.ht_capa = NULL; - params.vht_capa = NULL; + params.link_sta_params.ht_capa = NULL; + params.link_sta_params.vht_capa = NULL; /* HE and EHT require WME */ - if (params.he_capa_len || params.he_6ghz_capa || - params.eht_capa_len) + if (params.link_sta_params.he_capa_len || + params.link_sta_params.he_6ghz_capa || + params.link_sta_params.eht_capa_len) return -EINVAL; } /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */ - if (params.he_6ghz_capa && (params.ht_capa || params.vht_capa)) + if (params.link_sta_params.he_6ghz_capa && + (params.link_sta_params.ht_capa || params.link_sta_params.vht_capa)) return -EINVAL; /* When you run into this, adjust the code below for the new flag */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 16d0fe53fcf2..e78bffbc6f95 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -738,7 +738,7 @@ DECLARE_EVENT_CLASS(station_add_change, __array(u8, vht_capa, (int)sizeof(struct ieee80211_vht_cap)) __array(char, vlan, IFNAMSIZ) __dynamic_array(u8, supported_rates, - params->supported_rates_len) + params->link_sta_params.supported_rates_len) __dynamic_array(u8, ext_capab, params->ext_capab_len) __dynamic_array(u8, supported_channels, params->supported_channels_len) @@ -758,20 +758,23 @@ DECLARE_EVENT_CLASS(station_add_change, __entry->plink_state = params->plink_state; __entry->uapsd_queues = params->uapsd_queues; memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap)); - if (params->ht_capa) - memcpy(__entry->ht_capa, params->ht_capa, + if (params->link_sta_params.ht_capa) + memcpy(__entry->ht_capa, + params->link_sta_params.ht_capa, sizeof(struct ieee80211_ht_cap)); memset(__entry->vht_capa, 0, sizeof(struct ieee80211_vht_cap)); - if (params->vht_capa) - memcpy(__entry->vht_capa, params->vht_capa, + if (params->link_sta_params.vht_capa) + memcpy(__entry->vht_capa, + params->link_sta_params.vht_capa, sizeof(struct ieee80211_vht_cap)); memset(__entry->vlan, 0, sizeof(__entry->vlan)); if (params->vlan) memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ); - if (params->supported_rates && params->supported_rates_len) + if (params->link_sta_params.supported_rates && + params->link_sta_params.supported_rates_len) memcpy(__get_dynamic_array(supported_rates), - params->supported_rates, - params->supported_rates_len); + params->link_sta_params.supported_rates, + params->link_sta_params.supported_rates_len); if (params->ext_capab && params->ext_capab_len) memcpy(__get_dynamic_array(ext_capab), params->ext_capab, @@ -788,8 +791,9 @@ DECLARE_EVENT_CLASS(station_add_change, params->supported_oper_classes_len); __entry->max_sp = params->max_sp; __entry->capability = params->capability; - __entry->opmode_notif = params->opmode_notif; - __entry->opmode_notif_used = params->opmode_notif_used; + __entry->opmode_notif = params->link_sta_params.opmode_notif; + __entry->opmode_notif_used = + params->link_sta_params.opmode_notif_used; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", station flags mask: %u, station flags set: %u, " -- cgit v1.2.3 From d8675a63518c6148827838058feb7f18403faed1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Jun 2022 22:36:37 +0200 Subject: wifi: mac80211: RCU-ify link/link_conf pointers Since links can be added and removed dynamically, we need to somehow protect the sdata->link[] and vif->link_conf[] array pointers from disappearing when accessing them without locks. RCU-ify the pointers to achieve this, which requires quite a bit of rework. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 14 ++- include/net/mac80211.h | 6 +- net/mac80211/cfg.c | 169 ++++++++++++++++++++++------------ net/mac80211/chan.c | 123 +++++++++++++------------ net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/driver-ops.h | 10 +- net/mac80211/ht.c | 24 ++++- net/mac80211/ibss.c | 8 +- net/mac80211/ieee80211_i.h | 21 +++-- net/mac80211/iface.c | 36 ++++---- net/mac80211/main.c | 9 +- net/mac80211/mesh.c | 7 +- net/mac80211/mlme.c | 30 +++--- net/mac80211/ocb.c | 4 +- net/mac80211/offchannel.c | 15 ++- net/mac80211/rx.c | 8 +- net/mac80211/sta_info.c | 3 +- net/mac80211/tdls.c | 3 +- net/mac80211/trace.h | 19 ++-- net/mac80211/tx.c | 88 +++++++++--------- net/mac80211/util.c | 34 ++++--- net/mac80211/vht.c | 62 +++++++++---- 22 files changed, 420 insertions(+), 275 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4f22f3df161c..6bad95eeb709 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1477,9 +1477,10 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, int i; for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { - struct ieee80211_bss_conf *conf = vif->link_conf[i]; + struct ieee80211_bss_conf *conf; struct ieee80211_chanctx_conf *chanctx; + conf = rcu_dereference(vif->link_conf[i]); if (!conf) continue; @@ -1917,7 +1918,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, { struct mac80211_hwsim_link_data *link_data = arg; u32 link_id = link_data->link_id; - struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id]; + struct ieee80211_bss_conf *link_conf; struct mac80211_hwsim_data *data = container_of(link_data, struct mac80211_hwsim_data, link_data[link_id]); @@ -1931,6 +1932,10 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, hwsim_check_magic(vif); + link_conf = rcu_dereference(vif->link_conf[link_id]); + if (!link_conf) + return; + if (vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_MESH_POINT && vif->type != NL80211_IFTYPE_ADHOC && @@ -2155,12 +2160,11 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 link_id, - u64 changed) + struct ieee80211_bss_conf *info, + u32 link_id, u64 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct mac80211_hwsim_data *data = hw->priv; - struct ieee80211_bss_conf *info = vif->link_conf[link_id]; struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; hwsim_check_magic(vif); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1c005a30313f..044ed417b06f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1789,7 +1789,7 @@ struct ieee80211_vif { enum nl80211_iftype type; struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; - struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; u16 valid_links; u8 addr[ETH_ALEN] __aligned(2); bool p2p; @@ -4082,7 +4082,9 @@ struct ieee80211_ops { u64 changed); void (*link_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, u64 changed); + struct ieee80211_bss_conf *info, + unsigned int link_id, + u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 85032dcaa595..3d66e40af7a9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -39,7 +39,7 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, memcpy(sdata->vif.bss_conf.mu_group.position, params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, WLAN_USER_POSITION_LEN); - ieee80211_link_info_change_notify(sdata, 0, + ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_MU_GROUPS); /* don't care about endianness - just check for 0 */ memcpy(&membership, params->vht_mumimo_groups, @@ -841,8 +841,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata) { - ieee80211_link_release_channel(sdata->link[0]); - ret = ieee80211_link_use_channel(sdata->link[0], + ieee80211_link_release_channel(&sdata->deflink); + ret = ieee80211_link_use_channel(&sdata->deflink, chandef, IEEE80211_CHANCTX_EXCLUSIVE); } @@ -1008,6 +1008,7 @@ ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst, } static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, struct cfg80211_beacon_data *params, const struct ieee80211_csa_settings *csa, const struct ieee80211_color_change_settings *cca) @@ -1017,9 +1018,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, int new_head_len, new_tail_len; int size, err; u32 changed = BSS_CHANGED_BEACON; - struct ieee80211_link_data *link = sdata->link[params->link_id]; - struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[params->link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1153,8 +1152,14 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, int i, err; int prev_beacon_int; unsigned int link_id = params->beacon.link_id; - struct ieee80211_link_data *link = sdata->link[link_id]; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_link_data *link; + struct ieee80211_bss_conf *link_conf; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + return -ENOLINK; + + link_conf = link->conf; old = sdata_dereference(link->u.ap.beacon, sdata); if (old) @@ -1264,7 +1269,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) link_conf->beacon_tx_rate = params->beacon_rate; - err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL, NULL); + err = ieee80211_assign_beacon(sdata, link, ¶ms->beacon, NULL, NULL); if (err < 0) goto error; changed |= err; @@ -1300,7 +1305,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ieee80211_recalc_dtim(local, sdata); ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID); - ieee80211_link_info_change_notify(sdata, link_id, changed); + ieee80211_link_info_change_notify(sdata, link, changed); netif_carrier_on(dev); list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) @@ -1320,25 +1325,30 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_link_data *link; struct beacon_data *old; int err; - struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[params->link_id]; + struct ieee80211_bss_conf *link_conf; sdata_assert_lock(sdata); + link = sdata_dereference(sdata->link[params->link_id], sdata); + if (!link) + return -ENOLINK; + + link_conf = link->conf; + /* don't allow changing the beacon while a countdown is in place - offset * of channel switch counter may change */ if (link_conf->csa_active || link_conf->color_change_active) return -EBUSY; - old = sdata_dereference(sdata->link[params->link_id]->u.ap.beacon, - sdata); + old = sdata_dereference(link->u.ap.beacon, sdata); if (!old) return -ENOENT; - err = ieee80211_assign_beacon(sdata, params, NULL, NULL); + err = ieee80211_assign_beacon(sdata, link, params, NULL, NULL); if (err < 0) return err; @@ -1348,7 +1358,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, err |= BSS_CHANGED_HE_BSS_COLOR; } - ieee80211_link_info_change_notify(sdata, params->link_id, err); + ieee80211_link_info_change_notify(sdata, link, err); return 0; } @@ -1373,8 +1383,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, struct fils_discovery_data *old_fils_discovery; struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp; struct cfg80211_chan_def chandef; - struct ieee80211_link_data *link = sdata->link[link_id]; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_link_data *link = + sdata_dereference(sdata->link[link_id], sdata); + struct ieee80211_bss_conf *link_conf = link->conf; sdata_assert_lock(sdata); @@ -1431,7 +1442,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, sdata->beacon_rate_set = false; sdata->vif.cfg.ssid_len = 0; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_link_info_change_notify(sdata, link_id, + ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_BEACON_ENABLED); if (sdata->wdev.cac_started) { @@ -1589,14 +1600,16 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; u32 link_id = params->link_id < 0 ? 0 : params->link_id; + struct ieee80211_link_data *link = + sdata_dereference(sdata->link[link_id], sdata); struct link_sta_info *link_sta = rcu_dereference_protected(sta->link[link_id], lockdep_is_held(&local->sta_mtx)); - if (!link_sta) + if (!link || !link_sta) return -EINVAL; - sband = ieee80211_get_link_sband(sdata, link_id); + sband = ieee80211_get_link_sband(link); if (!sband) return -EINVAL; @@ -1616,7 +1629,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, if (params->supported_rates && params->supported_rates_len) { - ieee80211_parse_bitrates(&sdata->vif.link_conf[link_id]->chandef, + ieee80211_parse_bitrates(&link->conf->chandef, sband, params->supported_rates, params->supported_rates_len, &link_sta->pub->supp_rates[sband->band]); @@ -1667,9 +1680,14 @@ static int sta_apply_parameters(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata = sta->sdata; u32 link_id = params->link_sta_params.link_id < 0 ? 0 : params->link_sta_params.link_id; + struct ieee80211_link_data *link; u32 mask, set; - sband = ieee80211_get_link_sband(sdata, link_id); + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + return -ENOLINK; + + sband = ieee80211_get_link_sband(link); if (!sband) return -EINVAL; @@ -1987,7 +2005,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, } } - err = sta_apply_parameters(local, sta, params); + /* we use sta_info_get_bss() so this might be different */ + if (sdata != sta->sdata) { + mutex_lock_nested(&sta->sdata->wdev.mtx, 1); + err = sta_apply_parameters(local, sta, params); + mutex_unlock(&sta->sdata->wdev.mtx); + } else { + err = sta_apply_parameters(local, sta, params); + } if (err) goto out_err; @@ -2374,7 +2399,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) { conf->ht_opmode = nconf->ht_opmode; sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_HT); } if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) conf->dot11MeshHWMPactivePathToRootTimeout = @@ -2426,7 +2452,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef, IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) @@ -2441,7 +2467,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) ieee80211_stop_mesh(sdata); mutex_lock(&sdata->local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); kfree(sdata->u.mesh.ie); mutex_unlock(&sdata->local->mtx); @@ -2529,7 +2555,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, changed |= BSS_CHANGED_P2P_PS; } - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); return 0; } @@ -2570,7 +2596,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_QOS); return 0; } @@ -2719,7 +2746,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(int) * NUM_NL80211_BANDS); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MCAST_RATE); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_MCAST_RATE); return 0; } @@ -2934,7 +2962,7 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy, #endif int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_link_data *link, enum ieee80211_smps_mode smps_mode) { const u8 *ap; @@ -2948,8 +2976,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) return -EINVAL; - old_req = sdata->link[link_id]->u.mgd.req_smps; - sdata->link[link_id]->u.mgd.req_smps = smps_mode; + old_req = link->u.mgd.req_smps; + link->u.mgd.req_smps = smps_mode; if (old_req == smps_mode && smps_mode != IEEE80211_SMPS_AUTOMATIC) @@ -2961,10 +2989,10 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, * the new value until we associate. */ if (!sdata->u.mgd.associated || - sdata->vif.link_conf[link_id]->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) + link->conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; - ap = sdata->link[link_id]->u.mgd.bssid; + ap = link->u.mgd.bssid; rcu_read_lock(); list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { @@ -2988,7 +3016,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, err = ieee80211_send_smps_action(sdata, smps_mode, ap, ap); if (err) - sdata->link[link_id]->u.mgd.req_smps = old_req; + link->u.mgd.req_smps = old_req; else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found) ieee80211_teardown_tdls_peers(sdata); @@ -3018,10 +3046,14 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, /* no change, but if automatic follow powersave */ sdata_lock(sdata); for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - if (!sdata->link[link_id]) + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + + if (!link) continue; - __ieee80211_request_smps_mgd(sdata, link_id, - sdata->link[link_id]->u.mgd.req_smps); + __ieee80211_request_smps_mgd(sdata, link, + link->u.mgd.req_smps); } sdata_unlock(sdata); @@ -3060,7 +3092,8 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_CQM); return 0; } @@ -3085,7 +3118,8 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_CQM); return 0; } @@ -3177,7 +3211,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; - err = ieee80211_link_use_channel(sdata->link[0], chandef, + err = ieee80211_link_use_channel(&sdata->deflink, chandef, IEEE80211_CHANCTX_SHARED); if (err) goto out_unlock; @@ -3206,7 +3240,7 @@ static void ieee80211_end_cac(struct wiphy *wiphy, cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work); if (sdata->wdev.cac_started) { - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); sdata->wdev.cac_started = false; } } @@ -3353,7 +3387,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, if (!sdata->deflink.u.ap.next_beacon) return -EINVAL; - err = ieee80211_assign_beacon(sdata, + err = ieee80211_assign_beacon(sdata, &sdata->deflink, sdata->deflink.u.ap.next_beacon, NULL, NULL); ieee80211_free_next_beacon(&sdata->deflink); @@ -3410,7 +3444,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (sdata->deflink.reserved_ready) return 0; - return ieee80211_link_use_reserved_context(sdata->link[0]); + return ieee80211_link_use_reserved_context(&sdata->deflink); } if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, @@ -3423,7 +3457,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (err) return err; - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); if (sdata->deflink.csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -3522,7 +3556,9 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, csa.n_counter_offsets_presp = params->n_counter_offsets_presp; csa.count = params->count; - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); + err = ieee80211_assign_beacon(sdata, &sdata->deflink, + ¶ms->beacon_csa, &csa, + NULL); if (err < 0) { ieee80211_free_next_beacon(&sdata->deflink); return err; @@ -3675,7 +3711,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - err = ieee80211_link_reserve_chanctx(sdata->link[0], ¶ms->chandef, + err = ieee80211_link_reserve_chanctx(&sdata->deflink, ¶ms->chandef, chanctx->mode, params->radar_required); if (err) @@ -3684,7 +3720,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, /* if reservation is invalid then this will fail */ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); if (err) { - ieee80211_link_unreserve_chanctx(sdata->link[0]); + ieee80211_link_unreserve_chanctx(&sdata->deflink); goto out; } @@ -3694,7 +3730,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, err = ieee80211_set_csa_beacon(sdata, params, &changed); if (err) { - ieee80211_link_unreserve_chanctx(sdata->link[0]); + ieee80211_link_unreserve_chanctx(&sdata->deflink); goto out; } @@ -3711,7 +3747,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->count, params->block_tx); if (changed) { - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + changed); drv_channel_switch_beacon(sdata, ¶ms->chandef); } else { /* if the beacon didn't change, we can finalize immediately */ @@ -3950,12 +3987,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_link_data *link; int ret = -ENODATA; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); + link = rcu_dereference(sdata->link[link_id]); + if (!link) { + ret = -ENOLINK; + goto out; + } + + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); if (chanctx_conf) { - *chandef = sdata->vif.link_conf[link_id]->chandef; + *chandef = link->conf->chandef; ret = 0; } else if (local->open_count > 0 && local->open_count == local->monitors && @@ -3966,6 +4010,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, *chandef = local->_oper_chandef; ret = 0; } +out: rcu_read_unlock(); return ret; @@ -4009,13 +4054,15 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_link_data *link; int ret; u32 changed = 0; - ret = ieee80211_link_change_bandwidth(sdata->link[link_id], chandef, - &changed); + link = sdata_dereference(sdata->link[link_id], sdata); + + ret = ieee80211_link_change_bandwidth(link, chandef, &changed); if (ret == 0) - ieee80211_link_info_change_notify(sdata, link_id, changed); + ieee80211_link_info_change_notify(sdata, link, changed); return ret; } @@ -4358,7 +4405,7 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, if (!sdata->deflink.u.ap.next_beacon) return -EINVAL; - ret = ieee80211_assign_beacon(sdata, + ret = ieee80211_assign_beacon(sdata, &sdata->deflink, sdata->deflink.u.ap.next_beacon, NULL, NULL); ieee80211_free_next_beacon(&sdata->deflink); @@ -4401,7 +4448,8 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, params->counter_offset_presp; color_change.count = params->count; - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, + err = ieee80211_assign_beacon(sdata, &sdata->deflink, + ¶ms->beacon_color_change, NULL, &color_change); if (err < 0) { ieee80211_free_next_beacon(&sdata->deflink); @@ -4424,7 +4472,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.he_bss_color.enabled = enable; changed |= BSS_CHANGED_HE_BSS_COLOR; - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) { struct ieee80211_sub_if_data *child; @@ -4434,7 +4482,8 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) { child->vif.bss_conf.he_bss_color.color = color; child->vif.bss_conf.he_bss_color.enabled = enable; - ieee80211_link_info_change_notify(child, 0, + ieee80211_link_info_change_notify(child, + &child->deflink, BSS_CHANGED_HE_BSS_COLOR); } } diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 6853b563fb6c..8d384956fde5 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -67,14 +67,12 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) } static struct ieee80211_chanctx * -ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata, - unsigned int link_id) +ieee80211_link_get_chanctx(struct ieee80211_link_data *link) { - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; - struct ieee80211_local *local __maybe_unused = sdata->local; + struct ieee80211_local *local __maybe_unused = link->sdata->local; struct ieee80211_chanctx_conf *conf; - conf = rcu_dereference_protected(link_conf->chanctx_conf, + conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return NULL; @@ -82,12 +80,6 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata, return container_of(conf, struct ieee80211_chanctx, conf); } -static struct ieee80211_chanctx * -ieee80211_link_get_chanctx(struct ieee80211_link_data *link) -{ - return ieee80211_vif_get_chanctx(link->sdata, link->link_id); -} - static const struct cfg80211_chan_def * ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, @@ -122,8 +114,7 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { - struct ieee80211_bss_conf *link_conf = - link->sdata->vif.link_conf[link->link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; if (link->reserved_chanctx) continue; @@ -254,7 +245,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; struct sta_info *sta; - rcu_read_lock(); list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { if (sdata != sta->sdata && !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) @@ -262,7 +252,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id)); } - rcu_read_unlock(); return max_bw; } @@ -275,10 +264,11 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, struct ieee80211_vif *vif = &sdata->vif; int link_id; + rcu_read_lock(); for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link_id]; + rcu_dereference(sdata->vif.link_conf[link_id]); if (!link_conf) continue; @@ -319,6 +309,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, max_bw = max(max_bw, width); } + rcu_read_unlock(); return max_bw; } @@ -345,7 +336,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, /* use the configured bandwidth in case of monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == conf) + rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf) max_bw = max(max_bw, conf->def.width); rcu_read_unlock(); @@ -419,7 +410,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link_id]; + rcu_dereference(sdata->vif.link_conf[link_id]); struct link_sta_info *link_sta; if (!link_conf) @@ -572,8 +563,11 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local) unsigned int link_id; for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - if (sdata->link[link_id] && - sdata->link[link_id]->radar_required) { + struct ieee80211_link_data *link; + + link = rcu_dereference(sdata->link[link_id]); + + if (link && link->radar_required) { rcu_read_unlock(); return true; } @@ -602,15 +596,15 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link_id]; + struct ieee80211_link_data *link; - if (!link_conf) + link = rcu_dereference(sdata->link[link_id]); + if (!link) continue; - if (rcu_access_pointer(link_conf->chanctx_conf) != conf) + if (rcu_access_pointer(link->conf->chanctx_conf) != conf) continue; - if (!sdata->link[link_id]->radar_required) + if (!link->radar_required) continue; required = true; break; @@ -774,7 +768,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link_id]; + rcu_dereference(sdata->vif.link_conf[link_id]); if (!link_conf) continue; @@ -850,7 +844,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) return -ENOTSUPP; - conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, + conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { @@ -872,7 +866,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, } out: - rcu_assign_pointer(sdata->vif.link_conf[link_id]->chanctx_conf, conf); + rcu_assign_pointer(link->conf->chanctx_conf, conf); sdata->vif.cfg.idle = !conf; @@ -931,14 +925,14 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, } for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { - struct ieee80211_link_data *link = sdata->link[link_id]; - struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link_id]; + struct ieee80211_link_data *link; - if (!link_conf) + link = rcu_dereference(sdata->link[link_id]); + + if (!link) continue; - if (rcu_access_pointer(link_conf->chanctx_conf) != &chanctx->conf) + if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf) continue; switch (link->smps_mode) { @@ -968,7 +962,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, /* Disable SMPS for the monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == &chanctx->conf) + rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; rcu_read_unlock(); @@ -998,7 +992,7 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, { struct ieee80211_sub_if_data *sdata = link->sdata; unsigned int link_id = link->link_id; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_sub_if_data *vlan; struct ieee80211_chanctx_conf *conf; @@ -1021,9 +1015,17 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, if (clear) conf = NULL; - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.link_conf[link_id]->chanctx_conf, - conf); + rcu_read_lock(); + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { + struct ieee80211_bss_conf *vlan_conf; + + vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]); + if (WARN_ON(!vlan_conf)) + continue; + + rcu_assign_pointer(vlan_conf->chanctx_conf, conf); + } + rcu_read_unlock(); } void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, @@ -1210,21 +1212,29 @@ ieee80211_link_update_chandef(struct ieee80211_link_data *link, unsigned int link_id = link->link_id; struct ieee80211_sub_if_data *vlan; - sdata->vif.link_conf[link_id]->chandef = *chandef; + link->conf->chandef = *chandef; if (sdata->vif.type != NL80211_IFTYPE_AP) return; - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - vlan->vif.link_conf[link_id]->chandef = *chandef; + rcu_read_lock(); + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { + struct ieee80211_bss_conf *vlan_conf; + + vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]); + if (WARN_ON(!vlan_conf)) + continue; + + vlan_conf->chandef = *chandef; + } + rcu_read_unlock(); } static int ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_local *local = sdata->local; struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; @@ -1296,7 +1306,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) ieee80211_recalc_radar_chanctx(local, new_ctx); if (changed) - ieee80211_link_info_change_notify(sdata, link_id, changed); + ieee80211_link_info_change_notify(sdata, link, changed); out: ieee80211_link_chanctx_reservation_complete(link); @@ -1307,13 +1317,12 @@ static int ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct cfg80211_chan_def *chandef; int err; - old_ctx = ieee80211_vif_get_chanctx(sdata, link_id); + old_ctx = ieee80211_link_get_chanctx(link); new_ctx = link->reserved_chanctx; if (WARN_ON(!link->reserved_ready)) @@ -1625,8 +1634,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { struct ieee80211_sub_if_data *sdata = link->sdata; - struct ieee80211_bss_conf *link_conf = - sdata->vif.link_conf[link->link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; u32 changed = 0; if (!ieee80211_link_has_in_place_reservation(link)) @@ -1649,7 +1657,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_link_update_chandef(link, &link->reserved_chandef); if (changed) ieee80211_link_info_change_notify(sdata, - link->link_id, + link, changed); ieee80211_recalc_txpower(sdata, false); @@ -1746,8 +1754,7 @@ err: static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1786,7 +1793,6 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link, enum ieee80211_chanctx_mode mode) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *ctx; u8 radar_detect_width = 0; @@ -1806,7 +1812,7 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link, if (ret > 0) radar_detect_width = BIT(chandef->width); - sdata->link[link_id]->radar_required = ret; + link->radar_required = ret; ret = ieee80211_check_combinations(sdata, chandef, mode, radar_detect_width); @@ -1910,8 +1916,7 @@ int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, u32 *changed) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1997,7 +2002,8 @@ void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = link->sdata; unsigned int link_id = link->link_id; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; + struct ieee80211_bss_conf *ap_conf; struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *ap; struct ieee80211_chanctx_conf *conf; @@ -2009,9 +2015,12 @@ void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(ap->vif.link_conf[link_id]->chanctx_conf, + rcu_read_lock(); + ap_conf = rcu_dereference(ap->vif.link_conf[link_id]); + conf = rcu_dereference_protected(ap_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); rcu_assign_pointer(link_conf->chanctx_conf, conf); + rcu_read_unlock(); mutex_unlock(&local->chanctx_mtx); } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ead917501d6c..1e5b041a5cea 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -256,7 +256,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; sdata_lock(sdata); - err = __ieee80211_request_smps_mgd(sdata, 0, smps_mode); + err = __ieee80211_request_smps_mgd(sdata, &sdata->deflink, smps_mode); sdata_unlock(sdata); return err; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index db38c8cc9d8f..ee3ac1a01bb0 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -167,6 +167,7 @@ static inline void drv_vif_cfg_changed(struct ieee80211_local *local, static inline void drv_link_info_changed(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *info, int link_id, u64 changed) { might_sleep(); @@ -189,13 +190,13 @@ static inline void drv_link_info_changed(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_link_info_changed(local, sdata, link_id, changed); + trace_drv_link_info_changed(local, sdata, info, link_id, changed); if (local->ops->link_info_changed) local->ops->link_info_changed(&local->hw, &sdata->vif, - link_id, changed); + info, link_id, changed); else if (local->ops->bss_info_changed) local->ops->bss_info_changed(&local->hw, &sdata->vif, - &sdata->vif.bss_conf, changed); + info, changed); trace_drv_return_void(local); } @@ -995,8 +996,7 @@ static inline int drv_start_ap(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_start_ap(local, sdata, sdata->vif.link_conf[link_id], - link_id); + trace_drv_start_ap(local, sdata, link_id); if (local->ops->start_ap) ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id); trace_drv_return_int(local, ret); diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 2eb3a409b70f..ea7ce87b7ec4 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -140,12 +140,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, const struct ieee80211_ht_cap *ht_cap_ie, struct link_sta_info *link_sta) { + struct ieee80211_bss_conf *link_conf; struct sta_info *sta = link_sta->sta; struct ieee80211_sta_ht_cap ht_cap, own_cap; u8 ampdu_info, tx_mcs_set_cap; int i, max_tx_streams; bool changed; enum ieee80211_sta_rx_bandwidth bw; + enum nl80211_chan_width width; memset(&ht_cap, 0, sizeof(ht_cap)); @@ -248,7 +250,14 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap)); - switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) { + rcu_read_lock(); + link_conf = rcu_dereference(sdata->vif.link_conf[link_sta->link_id]); + if (WARN_ON(!link_conf)) + width = NL80211_CHAN_WIDTH_20_NOHT; + else + width = link_conf->chandef.width; + + switch (width) { default: WARN_ON_ONCE(1); fallthrough; @@ -264,6 +273,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; break; } + rcu_read_unlock(); link_sta->pub->bandwidth = bw; @@ -547,7 +557,7 @@ void ieee80211_request_smps_mgd_work(struct work_struct *work) u.mgd.request_smps_work); sdata_lock(link->sdata); - __ieee80211_request_smps_mgd(link->sdata, link->link_id, + __ieee80211_request_smps_mgd(link->sdata, link, link->u.mgd.driver_smps_mode); sdata_unlock(link->sdata); } @@ -556,19 +566,23 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - struct ieee80211_link_data *link = sdata->link[link_id]; + struct ieee80211_link_data *link; if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION)) return; + rcu_read_lock(); + link = rcu_dereference(sdata->link[link_id]); if (WARN_ON(!link)) - return; + goto out; if (link->u.mgd.driver_smps_mode == smps_mode) - return; + goto out; link->u.mgd.driver_smps_mode = smps_mode; ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work); +out: + rcu_read_unlock(); } /* this might change ... don't want non-open drivers using it */ EXPORT_SYMBOL_GPL(ieee80211_request_smps); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index d30a82f1620b..393c7595bfa4 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -300,7 +300,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, radar_required = err; mutex_lock(&local->mtx); - if (ieee80211_link_use_channel(sdata->link[0], &chandef, + if (ieee80211_link_use_channel(&sdata->deflink, &chandef, ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE)) { @@ -370,7 +370,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, RCU_INIT_POINTER(ifibss->presp, NULL); kfree_rcu(presp, rcu_head); mutex_lock(&local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", err); @@ -722,7 +722,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_IBSS); drv_leave_ibss(local, sdata); mutex_lock(&local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); } @@ -1848,7 +1848,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | IEEE80211_HT_PARAM_RIFS_MODE; changed |= BSS_CHANGED_HT | BSS_CHANGED_MCAST_RATE; - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 604825dde4fd..f6791b47f78f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -961,6 +961,8 @@ struct ieee80211_link_data { struct ieee80211_link_data_managed mgd; struct ieee80211_link_data_ap ap; } u; + + struct ieee80211_bss_conf *conf; }; struct ieee80211_sub_if_data { @@ -1045,7 +1047,7 @@ struct ieee80211_sub_if_data { } u; struct ieee80211_link_data deflink; - struct ieee80211_link_data *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_link_data __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; #ifdef CONFIG_MAC80211_DEBUGFS struct { @@ -1544,16 +1546,14 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) } static inline struct ieee80211_supported_band * -ieee80211_get_link_sband(struct ieee80211_sub_if_data *sdata, u32 link_id) +ieee80211_get_link_sband(struct ieee80211_link_data *link) { - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = link->sdata->local; struct ieee80211_chanctx_conf *chanctx_conf; enum nl80211_band band; rcu_read_lock(); - chanctx_conf = - rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); - + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return NULL; @@ -1721,7 +1721,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, u64 changed); void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, - int link_id, u64 changed); + struct ieee80211_link_data *link, + u64 changed); void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); @@ -2002,7 +2003,7 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta); void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_link_data *link, struct ieee80211_mgmt *mgmt); u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, struct link_sta_info *sta, @@ -2277,10 +2278,10 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band band, u32 *basic_rates); int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_link_data *link, enum ieee80211_smps_mode smps_mode); void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, - unsigned int link_id); + struct ieee80211_link_data *link); void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d5e904bff624..55b0a1fa92ab 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -80,7 +80,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, { if (__ieee80211_recalc_txpower(sdata) || (update_bss && ieee80211_sdata_running(sdata))) - ieee80211_link_info_change_notify(sdata, 0, + ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_TXPOWER); } @@ -480,7 +480,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do chandef = sdata->vif.bss_conf.chandef; WARN_ON(local->suspended); mutex_lock(&local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -1031,11 +1031,12 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, if (link_id < 0) link_id = 0; - sdata->vif.link_conf[link_id] = link_conf; - sdata->link[link_id] = link; + rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf); + rcu_assign_pointer(sdata->link[link_id], link); link->sdata = sdata; link->link_id = link_id; + link->conf = link_conf; INIT_WORK(&link->csa_finalize_work, ieee80211_csa_finalize_work); @@ -1128,7 +1129,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) mutex_unlock(&local->iflist_mtx); mutex_lock(&local->mtx); - ret = ieee80211_link_use_channel(sdata->link[0], &local->monitor_chandef, + ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef, IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); if (ret) { @@ -1173,7 +1174,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) synchronize_net(); mutex_lock(&local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); drv_remove_interface(local, sdata); @@ -1279,7 +1280,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) case NL80211_IFTYPE_AP_VLAN: /* no need to tell driver, but set carrier and chanctx */ if (sdata->bss->active) { - ieee80211_link_vlan_copy_chanctx(sdata->link[0]); + ieee80211_link_vlan_copy_chanctx(&sdata->deflink); netif_carrier_on(dev); ieee80211_set_vif_encap_ops(sdata); } else { @@ -1351,7 +1352,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_NAN) changed |= ieee80211_reset_erp_info(sdata); - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + changed); switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: @@ -1535,7 +1537,8 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, break; } case WLAN_VHT_ACTION_GROUPID_MGMT: - ieee80211_process_mu_groups(sdata, 0, mgmt); + ieee80211_process_mu_groups(sdata, &sdata->deflink, + mgmt); break; default: WARN_ON(1); @@ -1689,7 +1692,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, recalc_smps); - ieee80211_recalc_smps(sdata, 0); + ieee80211_recalc_smps(sdata, &sdata->deflink); } /* @@ -2364,6 +2367,7 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, struct { struct ieee80211_link_data data; struct ieee80211_bss_conf conf; + struct rcu_head rcu_head; } *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link; struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]; struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -2394,15 +2398,15 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, /* link them into data structures */ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { WARN_ON(!use_deflink && - sdata->link[link_id] == &sdata->deflink); + rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink); link = links[link_id]; ieee80211_link_init(sdata, link_id, &link->data, &link->conf); } for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { - sdata->link[link_id] = NULL; - sdata->vif.link_conf[link_id] = NULL; + RCU_INIT_POINTER(sdata->link[link_id], NULL); + RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL); } sdata->vif.valid_links = new_links; @@ -2426,20 +2430,20 @@ int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, /* now use this to free the old links */ memset(links, 0, sizeof(links)); for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { - if (sdata->link[link_id] == &sdata->deflink) + if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink) continue; /* * we must have allocated the data through this path so * we know we can free both at the same time */ - links[link_id] = container_of(sdata->link[link_id], + links[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]), typeof(*links[link_id]), data); } free: for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) - kfree(links[link_id]); + kfree_rcu(links[link_id], rcu_head); if (use_deflink) ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c34f06039dda..191f4d35ef60 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -246,9 +246,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS; /* FIXME: should be for each link */ - trace_drv_link_info_changed(local, sdata, 0, changed); + trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf, + 0, changed); if (local->ops->link_info_changed) local->ops->link_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, 0, ch); } @@ -272,7 +274,8 @@ void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, } void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, - int link_id, u64 changed) + struct ieee80211_link_data *link, + u64 changed) { struct ieee80211_local *local = sdata->local; @@ -284,7 +287,7 @@ void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, if (!check_sdata_in_driver(sdata)) return; - drv_link_info_changed(local, sdata, link_id, changed); + drv_link_info_changed(local, sdata, link->conf, link->link_id, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6160211a7eee..ba4e0921fa5d 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1056,7 +1056,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) } ieee80211_recalc_dtim(local, sdata); - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); netif_carrier_on(sdata->dev); return 0; @@ -1080,7 +1080,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BEACON_ENABLED); /* remove beacon */ bcn = sdata_dereference(ifmsh->beacon, sdata); @@ -1578,7 +1579,7 @@ static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) if (ieee80211_mesh_rebuild_beacon(sdata)) return; - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); } void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4175247c325e..52a41416b8bb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1836,7 +1836,8 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) if (sdata->vif.bss_conf.ps != ps_allowed) { sdata->vif.bss_conf.ps = ps_allowed; - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_PS); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_PS); } } @@ -2032,7 +2033,8 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) { if (__ieee80211_sta_handle_tspec_ac_params(sdata)) - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_QOS); } static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) @@ -2338,7 +2340,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local); mutex_unlock(&local->iflist_mtx); - ieee80211_recalc_smps(sdata, 0); + ieee80211_recalc_smps(sdata, &sdata->deflink); ieee80211_recalc_ps_vif(sdata); netif_carrier_on(sdata->dev); @@ -2921,7 +2923,8 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, auth_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; mutex_lock(&sdata->local->mtx); ieee80211_link_release_channel(&sdata->deflink); @@ -2950,7 +2953,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, assoc_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; sdata->vif.bss_conf.mu_mimo_owner = false; @@ -4392,7 +4396,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, elems->pwr_constr_elem, elems->cisco_dtpc_elem); - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + changed); free: kfree(elems); } @@ -5702,9 +5707,10 @@ skip_rates: * tell driver about BSSID, basic rates and timing * this was set up above, before setting the channel */ - ieee80211_link_info_change_notify(sdata, 0, - BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | - BSS_CHANGED_BEACON_INT); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID | + BSS_CHANGED_BASIC_RATES | + BSS_CHANGED_BEACON_INT); if (assoc) sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH); @@ -5870,7 +5876,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; mutex_lock(&sdata->local->mtx); ieee80211_link_release_channel(&sdata->deflink); @@ -6217,7 +6224,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, return 0; err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; err_free: kfree(assoc_data); diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 0fd29d9c496c..2ca2164a3098 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -186,7 +186,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef, IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) @@ -229,7 +229,7 @@ int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); mutex_lock(&sdata->local->mtx); - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); skb_queue_purge(&sdata->skb_queue); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index aff5d3c39902..be79ae68754e 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -119,7 +119,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) &sdata->state); sdata->vif.bss_conf.enable_beacon = false; ieee80211_link_info_change_notify( - sdata, 0, BSS_CHANGED_BEACON_ENABLED); + sdata, &sdata->deflink, + BSS_CHANGED_BEACON_ENABLED); } if (sdata->vif.type == NL80211_IFTYPE_STATION && @@ -156,7 +157,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) &sdata->state)) { sdata->vif.bss_conf.enable_beacon = true; ieee80211_link_info_change_notify( - sdata, 0, BSS_CHANGED_BEACON_ENABLED); + sdata, &sdata->deflink, + BSS_CHANGED_BEACON_ENABLED); } } mutex_unlock(&local->iflist_mtx); @@ -848,14 +850,17 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, rcu_read_lock(); /* Check all the links first */ for (i = 0; i < ARRAY_SIZE(sdata->vif.link_conf); i++) { - if (!sdata->vif.link_conf[i]) + struct ieee80211_bss_conf *conf; + + conf = rcu_dereference(sdata->vif.link_conf[i]); + if (!conf) continue; - chanctx_conf = rcu_dereference(sdata->vif.link_conf[i]->chanctx_conf); + chanctx_conf = rcu_dereference(conf->chanctx_conf); if (!chanctx_conf) continue; - if (ether_addr_equal(sdata->vif.link_conf[i]->addr, mgmt->sa)) + if (ether_addr_equal(conf->addr, mgmt->sa)) break; chanctx_conf = NULL; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b7dff3ef9748..c70156e49d0d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -4156,9 +4156,13 @@ static bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata, return false; for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { - if (!sdata->vif.link_conf[link_id]) + struct ieee80211_bss_conf *conf; + + conf = rcu_dereference(sdata->vif.link_conf[link_id]); + + if (!conf) continue; - if (ether_addr_equal(sdata->vif.link_conf[link_id]->addr, addr)) { + if (ether_addr_equal(conf->addr, addr)) { if (out_link_id) *out_link_id = link_id; return true; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a4fa0ce7bd92..20aad688c9c9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -731,7 +731,8 @@ ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata) if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) { sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps; - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_P2P_PS); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_P2P_PS); } } diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c531fa17f426..71883ffd7061 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1336,7 +1336,8 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, return; sdata->vif.bss_conf.ht_operation_mode = opmode; - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_HT); } int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index f96e7cdca4c2..6aa06fba5b50 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -446,9 +446,10 @@ TRACE_EVENT(drv_vif_cfg_changed, TRACE_EVENT(drv_link_info_changed, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *link_conf, int link_id, u64 changed), - TP_ARGS(local, sdata, link_id, changed), + TP_ARGS(local, sdata, link_conf, link_id, changed), TP_STRUCT__entry( LOCAL_ENTRY @@ -481,8 +482,6 @@ TRACE_EVENT(drv_link_info_changed, ), TP_fast_assign( - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; - LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; @@ -1752,10 +1751,9 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TRACE_EVENT(drv_start_ap, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info, unsigned int link_id), - TP_ARGS(local, sdata, info, link_id), + TP_ARGS(local, sdata, link_id), TP_STRUCT__entry( LOCAL_ENTRY @@ -1768,15 +1766,20 @@ TRACE_EVENT(drv_start_ap, ), TP_fast_assign( + struct ieee80211_bss_conf *info = + sdata_dereference(sdata->vif.link_conf[link_id], sdata); + LOCAL_ASSIGN; VIF_ASSIGN; __entry->link_id = link_id; - __entry->dtimper = info->dtim_period; - __entry->bcnint = info->beacon_int; + if (info) { + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + __entry->hidden_ssid = info->hidden_ssid; + } memcpy(__get_dynamic_array(ssid), sdata->vif.cfg.ssid, sdata->vif.cfg.ssid_len); - __entry->hidden_ssid = info->hidden_ssid; ), TP_printk( diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6cd3aeba870f..4a7a714de79e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4598,13 +4598,14 @@ void ieee80211_tx_pending(struct tasklet_struct *t) /* functions for drivers to get certain frames */ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, struct ps_data *ps, struct sk_buff *skb, - bool is_template, unsigned int link_id) + bool is_template) { u8 *pos, *tim; int aid0 = 0; int i, have_bits = 0, n1, n2; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ @@ -4664,8 +4665,9 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, } static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, struct ps_data *ps, struct sk_buff *skb, - bool is_template, unsigned int link_id) + bool is_template) { struct ieee80211_local *local = sdata->local; @@ -4677,12 +4679,10 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, - link_id); + __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template); } else { spin_lock_bh(&local->tim_lock); - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, - link_id); + __ieee80211_beacon_add_tim(sdata, link, ps, skb, is_template); spin_unlock_bh(&local->tim_lock); } @@ -4691,7 +4691,7 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, struct beacon_data *beacon, - unsigned int link_id) + struct ieee80211_link_data *link) { u8 *beacon_data, count, max_count = 1; struct probe_resp *resp; @@ -4716,20 +4716,17 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, return; } - rcu_read_lock(); - resp = rcu_dereference(sdata->link[link_id]->u.ap.probe_resp); + resp = rcu_dereference(link->u.ap.probe_resp); bcn_offsets = beacon->cntdwn_counter_offsets; count = beacon->cntdwn_current_counter; - if (sdata->vif.link_conf[link_id]->csa_active) + if (link->conf->csa_active) max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; for (i = 0; i < max_count; ++i) { if (bcn_offsets[i]) { - if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len)) { - rcu_read_unlock(); + if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len)) return; - } beacon_data[bcn_offsets[i]] = count; } @@ -4739,7 +4736,6 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, resp->data[resp_offsets[i]] = count; } } - rcu_read_unlock(); } static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon) @@ -4863,14 +4859,14 @@ EXPORT_SYMBOL(ieee80211_beacon_cntdwn_is_complete); static int ieee80211_beacon_protect(struct sk_buff *skb, struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id) + struct ieee80211_link_data *link) { ieee80211_tx_result res; struct ieee80211_tx_data tx; struct sk_buff *check_skb; memset(&tx, 0, sizeof(tx)); - tx.key = rcu_dereference(sdata->link[link_id]->default_beacon_key); + tx.key = rcu_dereference(link->default_beacon_key); if (!tx.key) return 0; tx.local = local; @@ -4890,12 +4886,12 @@ static int ieee80211_beacon_protect(struct sk_buff *skb, static void ieee80211_beacon_get_finish(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_link_data *link, struct ieee80211_mutable_offsets *offs, struct beacon_data *beacon, struct sk_buff *skb, struct ieee80211_chanctx_conf *chanctx_conf, - u16 csa_off_base, - unsigned int link_id) + u16 csa_off_base) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -4926,7 +4922,7 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw, memset(&txrc, 0, sizeof(txrc)); txrc.hw = hw; txrc.sband = local->hw.wiphy->bands[band]; - txrc.bss_conf = sdata->vif.link_conf[link_id]; + txrc.bss_conf = link->conf; txrc.skb = skb; txrc.reported_rate.idx = -1; if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) @@ -4958,11 +4954,11 @@ ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon) static struct sk_buff * ieee80211_beacon_get_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_link_data *link, struct ieee80211_mutable_offsets *offs, bool is_template, struct beacon_data *beacon, - struct ieee80211_chanctx_conf *chanctx_conf, - unsigned int link_id) + struct ieee80211_chanctx_conf *chanctx_conf) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -4975,7 +4971,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (!is_template) ieee80211_beacon_update_cntdwn(vif); - ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); + ieee80211_set_beacon_cntdwn(sdata, beacon, link); } /* headroom, head length, @@ -4991,7 +4987,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template, link_id); + ieee80211_beacon_add_tim(sdata, link, &ap->ps, skb, is_template); if (offs) { offs->tim_offset = beacon->head_len; @@ -5010,11 +5006,11 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (beacon->tail) skb_put_data(skb, beacon->tail, beacon->tail_len); - if (ieee80211_beacon_protect(skb, local, sdata, link_id) < 0) + if (ieee80211_beacon_protect(skb, local, sdata, link) < 0) return NULL; - ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, - csa_off_base, link_id); + ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb, + chanctx_conf, csa_off_base); return skb; } @@ -5030,12 +5026,16 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, struct sk_buff *skb = NULL; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_link_data *link; rcu_read_lock(); sdata = vif_to_sdata(vif); + link = rcu_dereference(sdata->link[link_id]); + if (!link) + goto out; chanctx_conf = - rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); + rcu_dereference(link->conf->chanctx_conf); if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; @@ -5044,12 +5044,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, memset(offs, 0, sizeof(*offs)); if (sdata->vif.type == NL80211_IFTYPE_AP) { - beacon = rcu_dereference(sdata->link[link_id]->u.ap.beacon); + beacon = rcu_dereference(link->u.ap.beacon); if (!beacon) goto out; - skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, - beacon, chanctx_conf, link_id); + skb = ieee80211_beacon_get_ap(hw, vif, link, offs, is_template, + beacon, chanctx_conf); } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; @@ -5062,7 +5062,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!is_template) __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); + ieee80211_set_beacon_cntdwn(sdata, beacon, link); } skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + @@ -5076,8 +5076,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); - ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0, link_id); + ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb, + chanctx_conf, 0); } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -5094,7 +5094,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, */ __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); + ieee80211_set_beacon_cntdwn(sdata, beacon, link); } if (ifmsh->sync_ops) @@ -5109,8 +5109,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template, - link_id); + ieee80211_beacon_add_tim(sdata, link, &ifmsh->ps, skb, + is_template); if (offs) { offs->tim_offset = beacon->head_len; @@ -5118,8 +5118,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, } skb_put_data(skb, beacon->tail, beacon->tail_len); - ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0, link_id); + ieee80211_beacon_get_finish(hw, vif, link, offs, beacon, skb, + chanctx_conf, 0); } else { WARN_ON(1); goto out; @@ -5616,11 +5616,17 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, link = IEEE80211_LINK_UNSPECIFIED; } else { /* otherwise must be addressed from a link */ + rcu_read_lock(); for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { - if (memcmp(sdata->vif.link_conf[link]->addr, - hdr->addr2, ETH_ALEN) == 0) + struct ieee80211_bss_conf *link_conf; + + link_conf = rcu_dereference(sdata->vif.link_conf[link]); + if (!link_conf) + continue; + if (memcmp(link_conf->addr, hdr->addr2, ETH_ALEN) == 0) break; } + rcu_read_unlock(); if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf))) link = ffs(sdata->vif.valid_links) - 1; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 645f75b0f89f..3e29ef1f81ad 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1702,7 +1702,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, sdata->vif.type != NL80211_IFTYPE_NAN) { sdata->vif.bss_conf.qos = enable_qos; if (bss_notify) - ieee80211_link_info_change_notify(sdata, 0, + ieee80211_link_info_change_notify(sdata, + &sdata->deflink, BSS_CHANGED_QOS); } } @@ -2259,7 +2260,7 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) static void ieee80211_assign_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id) + struct ieee80211_link_data *link) { struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -2268,11 +2269,11 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, return; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, + conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_assign_vif_chanctx(local, sdata, link_id, ctx); + drv_assign_vif_chanctx(local, sdata, link->link_id, ctx); } mutex_unlock(&local->chanctx_mtx); } @@ -2478,7 +2479,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata && ieee80211_sdata_running(sdata)) - ieee80211_assign_chanctx(local, sdata, 0); + ieee80211_assign_chanctx(local, sdata, &sdata->deflink); } /* reconfigure hardware */ @@ -2488,16 +2489,23 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { - unsigned int link; + unsigned int link_id; u32 changed; if (!ieee80211_sdata_running(sdata)) continue; - for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { - if (sdata->vif.link_conf[link]) + sdata_lock(sdata); + for (link_id = 0; + link_id < ARRAY_SIZE(sdata->vif.link_conf); + link_id++) { + struct ieee80211_link_data *link; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (link) ieee80211_assign_chanctx(local, sdata, link); } + sdata_unlock(sdata); switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: @@ -2807,7 +2815,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif) EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, - unsigned int link_id) + struct ieee80211_link_data *link) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *chanctx_conf; @@ -2815,7 +2823,7 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, + chanctx_conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); /* @@ -3984,7 +3992,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) if (sdata->wdev.cac_started) { chandef = sdata->vif.bss_conf.chandef; - ieee80211_link_release_channel(sdata->link[0]); + ieee80211_link_release_channel(&sdata->deflink); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -4430,13 +4438,11 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, !list_empty(&ctx->assigned_links)); list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { - struct ieee80211_sub_if_data *sdata = link->sdata; - if (!link->radar_required) continue; radar_detect |= - BIT(sdata->vif.link_conf[link->link_id]->chandef.width); + BIT(link->conf->chandef.width); } return radar_detect; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index fa14627b499a..c804890dc623 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -341,39 +341,50 @@ ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta) { unsigned int link_id = link_sta->link_id; struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata; - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; u32 cap_width; if (he_cap->has_he) { + struct ieee80211_bss_conf *link_conf; + enum ieee80211_sta_rx_bandwidth ret; u8 info; + rcu_read_lock(); + link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); + if (eht_cap->has_eht && link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { info = eht_cap->eht_cap_elem.phy_cap_info[0]; - if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) - return IEEE80211_STA_RX_BW_320; + if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) { + ret = IEEE80211_STA_RX_BW_320; + goto out; + } } info = he_cap->he_cap_elem.phy_cap_info[0]; if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ) { if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) - return IEEE80211_STA_RX_BW_40; + ret = IEEE80211_STA_RX_BW_40; else - return IEEE80211_STA_RX_BW_20; + ret = IEEE80211_STA_RX_BW_20; + goto out; } if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G || info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return IEEE80211_STA_RX_BW_160; + ret = IEEE80211_STA_RX_BW_160; else if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) - return IEEE80211_STA_RX_BW_80; + ret = IEEE80211_STA_RX_BW_80; + else + ret = IEEE80211_STA_RX_BW_20; +out: + rcu_read_unlock(); - return IEEE80211_STA_RX_BW_20; + return ret; } if (!vht_cap->vht_supported) @@ -481,11 +492,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta) { struct sta_info *sta = link_sta->sta; - struct ieee80211_bss_conf *link_conf = - sta->sdata->vif.link_conf[link_sta->link_id]; - enum nl80211_chan_width bss_width = link_conf->chandef.width; + struct ieee80211_bss_conf *link_conf; + enum nl80211_chan_width bss_width; enum ieee80211_sta_rx_bandwidth bw; + rcu_read_lock(); + link_conf = rcu_dereference(sta->sdata->vif.link_conf[link_sta->link_id]); + if (WARN_ON(!link_conf)) + bss_width = NL80211_CHAN_WIDTH_20_NOHT; + else + bss_width = link_conf->chandef.width; + rcu_read_unlock(); + bw = ieee80211_sta_cap_rx_bw(link_sta); bw = min(bw, link_sta->cur_max_bandwidth); @@ -659,10 +677,10 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, } void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_link_data *link, struct ieee80211_mgmt *mgmt) { - struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_bss_conf *link_conf = link->conf; if (!link_conf->mu_mimo_owner) return; @@ -680,19 +698,25 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.vht_group_notif.position, WLAN_USER_POSITION_LEN); - ieee80211_link_info_change_notify(sdata, link_id, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, link, + BSS_CHANGED_MU_GROUPS); } void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, const u8 *membership, const u8 *position) { - struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id]; + struct ieee80211_bss_conf *link_conf; - if (WARN_ON_ONCE(!link_conf->mu_mimo_owner)) - return; + rcu_read_lock(); + link_conf = rcu_dereference(vif->link_conf[link_id]); - memcpy(link_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); - memcpy(link_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); + if (!WARN_ON_ONCE(!link_conf || !link_conf->mu_mimo_owner)) { + memcpy(link_conf->mu_group.membership, membership, + WLAN_MEMBERSHIP_LEN); + memcpy(link_conf->mu_group.position, position, + WLAN_USER_POSITION_LEN); + } + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); -- cgit v1.2.3 From 23cc6d8c37cdbe3b2b74a922f3311ecb2a5aea6c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2022 10:17:23 +0200 Subject: wifi: cfg80211: make cfg80211_auth_request::key_idx signed We might assign -1 to it in some cases when key is NULL, which means the key_idx isn't used but can lead to a warning from static checkers such as smatch. Make the struct member signed simply to avoid that, we only need a range of -1..3 anyway. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c904cbd1c4d6..a4e2cb2378b8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2773,7 +2773,8 @@ struct cfg80211_auth_request { size_t ie_len; enum nl80211_auth_type auth_type; const u8 *key; - u8 key_len, key_idx; + u8 key_len; + s8 key_idx; const u8 *auth_data; size_t auth_data_len; s8 link_id; -- cgit v1.2.3 From 3fbddae46e5fc3f1630c7cf561d88e4ad21c7105 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 14:42:12 +0200 Subject: wifi: mac80211: provide link ID in link_conf It might be useful to drivers to be able to pass only the link_conf pointer, rather than both the pointer and the link_id; add the link_id to the link_conf to facility that. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/iface.c | 1 + 2 files changed, 3 insertions(+) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 044ed417b06f..877b3eca6db4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -516,6 +516,7 @@ struct ieee80211_fils_discovery { * to that BSS) that can change during the lifetime of the BSS. * * @addr: (link) address used locally + * @link_id: link ID, or 0 for non-MLO * @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE * @uora_exists: is the UORA element advertised by AP * @ack_enabled: indicates support to receive a multi-TID that solicits either @@ -639,6 +640,7 @@ struct ieee80211_fils_discovery { */ struct ieee80211_bss_conf { const u8 *bssid; + unsigned int link_id; u8 addr[ETH_ALEN] __aligned(2); u8 htc_trig_based_pkt_ext; bool uora_exists; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fbb9c9c291b9..312a812bec84 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -390,6 +390,7 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, link->sdata = sdata; link->link_id = link_id; link->conf = link_conf; + link_conf->link_id = link_id; INIT_WORK(&link->csa_finalize_work, ieee80211_csa_finalize_work); -- cgit v1.2.3 From a3b8008dc1421a6f1d0d92cfc1352d729f6756c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:02:16 +0200 Subject: wifi: mac80211: move ps setting to vif config This really shouldn't be in a per-link config, we don't want to let anyone control it that way (if anything, link powersave could be forced through APIs to activate/deactivate a link), and we don't support powersave in software with devices that can do MLO. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/silabs/wfx/sta.c | 6 +++--- drivers/net/wireless/ti/wlcore/main.c | 4 ++-- include/net/mac80211.h | 6 +++--- net/mac80211/main.c | 1 + net/mac80211/mlme.c | 7 +++---- net/mac80211/trace.h | 4 ++-- 13 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3d111d6447f0..b18f32261d15 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6252,7 +6252,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_PS) { - arvif->ps = vif->bss_conf.ps; + arvif->ps = vif->cfg.ps; ret = ath10k_config_ps(ar); if (ret) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 17dbc7d9cf29..1cf1e1f18dba 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3292,7 +3292,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_PS && ar->ab->hw_params.supports_sta_ps) { - arvif->ps = vif->bss_conf.ps; + arvif->ps = vif->cfg.ps; ret = ath11k_mac_config_ps(ar); if (ret) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index ace8641909bd..dc59cafd29e3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -385,7 +385,7 @@ static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable) list_for_each_entry(tmp, &wcn->vif_list, list) { vif = wcn36xx_priv_to_vif(tmp); if (enable && !wcn->sw_scan) { - if (vif->bss_conf.ps) /* ps allowed ? */ + if (vif->cfg.ps) /* ps allowed ? */ wcn36xx_pmc_enter_bmps_state(wcn, vif); } else { wcn36xx_pmc_exit_bmps_state(wcn, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index b49f265a421f..f5744162d0d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -359,7 +359,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - if (!vif->bss_conf.ps || !mvmvif->pm_enabled) + if (!vif->cfg.ps || !mvmvif->pm_enabled) return; if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p && @@ -890,7 +890,7 @@ static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled || mvm->ps_disabled || - !vif->bss_conf.ps || + !vif->cfg.ps || iwl_mvm_vif_low_latency(mvmvif)); return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 303975f9e2b5..a79043f30775 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1861,7 +1861,7 @@ static bool rs_tpc_allowed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int index = rate->index; bool cam = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && - !vif->bss_conf.ps); + !vif->cfg.ps); IWL_DEBUG_RATE(mvm, "cam: %d sta_ps_disabled %d\n", cam, sta_ps_disabled); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index d3da54e6670b..389f8c61939d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -193,7 +193,7 @@ int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif) */ } req = { .bss_idx = mvif->idx, - .ps_state = vif->bss_conf.ps ? 2 : 0, + .ps_state = vif->cfg.ps ? 2 : 0, }; if (vif->type != NL80211_IFTYPE_STATION) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 3b5b475b0875..976686075dd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -972,7 +972,7 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) .ps = { .tag = cpu_to_le16(UNI_BSS_INFO_PS), .len = cpu_to_le16(sizeof(struct ps_tlv)), - .ps_state = vif->bss_conf.ps ? 2 : 0, + .ps_state = vif->cfg.ps ? 2 : 0, }, }; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 0378144795ca..47fd887ce6fe 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -175,7 +175,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) /* It is useless to enable PS if channels are the same. */ if (enable_ps) *enable_ps = false; - if (vif->cfg.assoc && vif->bss_conf.ps) + if (vif->cfg.assoc && vif->cfg.ps) dev_info(wvif->wdev->dev, "ignoring requested PS mode"); return -1; } @@ -188,8 +188,8 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) return 30; } if (enable_ps) - *enable_ps = vif->bss_conf.ps; - if (vif->cfg.assoc && vif->bss_conf.ps) + *enable_ps = vif->cfg.ps; + if (vif->cfg.assoc && vif->cfg.ps) return conf->dynamic_ps_timeout; else return -1; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index a1923ef52d55..d1200080f165 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4481,7 +4481,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_PS) { - if ((bss_conf->ps) && + if (vif->cfg.ps && test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { int ps_mode; @@ -4501,7 +4501,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (ret < 0) wl1271_warning("enter %s ps failed %d", ps_mode_str, ret); - } else if (!bss_conf->ps && + } else if (!vif->cfg.ps && test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { wl1271_debug(DEBUG_PSM, "auto ps disabled"); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 877b3eca6db4..fba06d7bc7eb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -578,8 +578,6 @@ struct ieee80211_fils_discovery { * @cqm_rssi_high: Connection quality monitor RSSI upper threshold. * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis * @qos: This is a QoS-enabled BSS. - * @ps: power-save mode (STA only). This flag is NOT affected by - * offchannel/dynamic_ps operations. * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. * @txpower: TX power in dBm. INT_MIN means not configured. * @txpower_type: TX power adjustment used to control per packet Transmit @@ -673,7 +671,6 @@ struct ieee80211_bss_conf { struct cfg80211_chan_def chandef; struct ieee80211_mu_group_data mu_group; bool qos; - bool ps; bool hidden_ssid; int txpower; enum nl80211_tx_power_setting txpower_type; @@ -1715,6 +1712,8 @@ enum ieee80211_offload_flags { * @assoc: association status * @ibss_joined: indicates whether this station is part of an IBSS or not * @ibss_creator: indicates if a new IBSS network is being created + * @ps: power-save mode (STA only). This flag is NOT affected by + * offchannel/dynamic_ps operations. * @aid: association ID number, valid only when @assoc is true * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * may filter ARP queries targeted for other addresses than listed here. @@ -1734,6 +1733,7 @@ struct ieee80211_vif_cfg { /* association related data */ bool assoc, ibss_joined; bool ibss_creator; + bool ps; u16 aid; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 191f4d35ef60..1258e506377e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -202,6 +202,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) #define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\ BSS_CHANGED_IDLE |\ + BSS_CHANGED_PS |\ BSS_CHANGED_IBSS |\ BSS_CHANGED_ARP_FILTER |\ BSS_CHANGED_SSID) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 299381d19760..f8be05804e59 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1869,10 +1869,9 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) { bool ps_allowed = ieee80211_powersave_allowed(sdata); - if (sdata->vif.bss_conf.ps != ps_allowed) { - sdata->vif.bss_conf.ps = ps_allowed; - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - BSS_CHANGED_PS); + if (sdata->vif.cfg.ps != ps_allowed) { + sdata->vif.cfg.ps = ps_allowed; + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_PS); } } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 6aa06fba5b50..751f08b47d0c 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -413,6 +413,7 @@ TRACE_EVENT(drv_vif_cfg_changed, __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(int, s1g) __field(bool, idle) + __field(bool, ps) ), TP_fast_assign( @@ -423,6 +424,7 @@ TRACE_EVENT(drv_vif_cfg_changed, __entry->assoc = sdata->vif.cfg.assoc; __entry->ibss_joined = sdata->vif.cfg.ibss_joined; __entry->ibss_creator = sdata->vif.cfg.ibss_creator; + __entry->ps = sdata->vif.cfg.ps; __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; memcpy(__get_dynamic_array(arp_addr_list), @@ -475,7 +477,6 @@ TRACE_EVENT(drv_link_info_changed, __field(u32, channel_cfreq1) __field(u32, channel_cfreq1_offset) __field(bool, qos) - __field(bool, ps) __field(bool, hidden_ssid) __field(int, txpower) __field(u8, p2p_oppps_ctwindow) @@ -506,7 +507,6 @@ TRACE_EVENT(drv_link_info_changed, __entry->channel_cfreq1 = link_conf->chandef.center_freq1; __entry->channel_cfreq1_offset = link_conf->chandef.freq1_offset; __entry->qos = link_conf->qos; - __entry->ps = link_conf->ps; __entry->hidden_ssid = link_conf->hidden_ssid; __entry->txpower = link_conf->txpower; __entry->p2p_oppps_ctwindow = link_conf->p2p_noa_attr.oppps_ctwindow; -- cgit v1.2.3 From b3e2130bf5f6c66831707cd51a8b13007137ac37 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 15:40:11 +0200 Subject: wifi: mac80211: change QoS settings API to take link into account Take the link into account in the QoS settings (EDCA parameters) APIs. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 3 +- drivers/net/wireless/ath/ath11k/mac.c | 3 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 3 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 +- drivers/net/wireless/ath/ath9k/main.c | 3 +- drivers/net/wireless/ath/carl9170/main.c | 3 +- drivers/net/wireless/broadcom/b43/main.c | 3 +- drivers/net/wireless/broadcom/b43legacy/main.c | 3 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 3 +- drivers/net/wireless/intel/iwlegacy/common.c | 3 +- drivers/net/wireless/intel/iwlegacy/common.h | 3 +- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/intersil/p54/main.c | 3 +- drivers/net/wireless/mac80211_hwsim.c | 8 ++-- drivers/net/wireless/marvell/mwl8k.c | 5 +- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 3 +- drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 3 +- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 3 +- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 5 +- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 5 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 3 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 3 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 +- drivers/net/wireless/realtek/rtlwifi/core.c | 3 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 3 +- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 +- drivers/net/wireless/silabs/wfx/sta.c | 3 +- drivers/net/wireless/silabs/wfx/sta.h | 3 +- drivers/net/wireless/st/cw1200/sta.c | 3 +- drivers/net/wireless/st/cw1200/sta.h | 3 +- drivers/net/wireless/ti/wl1251/main.c | 3 +- drivers/net/wireless/ti/wlcore/main.c | 3 +- include/net/mac80211.h | 3 +- net/mac80211/cfg.c | 7 +-- net/mac80211/driver-ops.c | 8 ++-- net/mac80211/driver-ops.h | 2 +- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 5 +- net/mac80211/iface.c | 2 +- net/mac80211/mlme.c | 55 ++++++++++++---------- net/mac80211/tdls.c | 2 +- net/mac80211/trace.h | 9 ++-- net/mac80211/util.c | 18 +++---- 55 files changed, 158 insertions(+), 104 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b18f32261d15..ac54396418c9 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7814,7 +7814,8 @@ exit: } static int ath10k_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { struct ath10k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1cf1e1f18dba..ec7b3a3629f3 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4822,7 +4822,8 @@ exit: } static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { struct ath11k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 8da232e81518..acd0e1dafb7f 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -572,7 +572,8 @@ ath5k_get_stats(struct ieee80211_hw *hw, static int -ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 14d713e03872..61875c45366b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1369,7 +1369,8 @@ static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, } static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c3d5d9795424..d2c20c332c7a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1712,7 +1712,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } static int ath9k_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 3d881028bd00..1540e9827f48 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1365,7 +1365,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, } static int carl9170_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *param) { struct ar9170 *ar = hw->priv; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 6b4188066f0b..008ee1f98af4 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3783,7 +3783,8 @@ static void b43_qos_init(struct b43_wldev *dev) } static int b43_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 _queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 532013184389..cbc21c7c3138 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -2505,7 +2505,8 @@ static void b43legacy_op_tx(struct ieee80211_hw *hw, } static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 61d7404aded4..a4034d44609b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -787,7 +787,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw, } static int -brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct brcms_info *wl = hw->priv; diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 6f007e63f0c2..9aa3359a9adc 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -4480,7 +4480,8 @@ il_clear_isr_stats(struct il_priv *il) } int -il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct il_priv *il = hw->priv; diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index d1383b4f0f05..69687fcf963f 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -1683,7 +1683,8 @@ struct il_cfg { ***************************/ int il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params); int il_mac_tx_last_beacon(struct ieee80211_hw *hw); void il_set_rxon_hwcrypto(struct il_priv *il, int hw_decrypt); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index e8bd4f0e3d2d..f4070fddc8c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2018 - 2019 Intel Corporation + * Copyright (C) 2018 - 2019, 2022 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -1153,7 +1153,8 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, } static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index eaffc3163bd1..3de558f286a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3349,7 +3349,8 @@ static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, } static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 115be1f3f33d..0f76d43fda33 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, } static int p54_conf_tx(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f437d8a65268..5da7a097d518 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2340,10 +2340,10 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, return 0; } -static int mac80211_hwsim_conf_tx( - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, - const struct ieee80211_tx_queue_params *params) +static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) { wiphy_dbg(hw->wiphy, "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n", diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 293bec9bb8dd..c1bf8998109c 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5365,7 +5365,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, } static int mwl8k_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mwl8k_priv *priv = hw->priv; @@ -6050,7 +6051,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) goto fail; for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { - rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); + rc = mwl8k_conf_tx(hw, NULL, 0, i, &priv->wmm_params[i]); if (rc) goto fail; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 088c0a4cf774..051715ed90dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -527,7 +527,8 @@ mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } static int -mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt7603_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 277c22a4d049..bf1696eb568a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -494,7 +494,8 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) } static int -mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 74ad418f5a70..50eaeff11af3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -156,7 +156,8 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params); void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index a0e2d042751b..604ddcc21123 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -487,7 +487,8 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, EXPORT_SYMBOL_GPL(mt76x02_set_key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct mt76x02_dev *dev = hw->priv; u8 cw_min = 5, cw_max = 10, qid; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index fbeac9aa2af6..25323a155a88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -478,7 +478,8 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) } static int -mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 63583605d1cd..1d0daa0c90be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -567,7 +567,8 @@ out: } static int -mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, +mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index a122f1dd38f6..118d43707853 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -368,7 +368,8 @@ void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev); void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params); void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb); void mt7601u_tx_stat(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index f1fa0442a57f..51d977ffc52f 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -258,7 +258,8 @@ void mt7601u_tx_stat(struct work_struct *work) } int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct mt7601u_dev *dev = hw->priv; u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index dec6ffdf07c4..273c5eac3362 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -1654,7 +1654,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) * IEEE80211 stack callback functions. */ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1667,7 +1668,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, if (queue != 0) return -EINVAL; - if (rt2x00mac_conf_tx(hw, vif, queue, params)) + if (rt2x00mac_conf_tx(hw, vif, link_id, queue, params)) return -EINVAL; /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index cbdaf7992f98..18102fbe36d6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -10395,7 +10395,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); int rt2800_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue_idx, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -10411,7 +10412,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 1139405c0ebb..e1761f467b94 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -245,7 +245,8 @@ void rt2800_get_key_seq(struct ieee80211_hw *hw, struct ieee80211_key_seq *seq); int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); int rt2800_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue_idx, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue_idx, const struct ieee80211_tx_queue_params *params); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 918e0477bb7d..f7ef2ca38794 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1481,7 +1481,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u64 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 6205d22765c7..c0ab2e6a29ad 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -665,7 +665,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue_idx, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 82cfc2aadc2b..d92f9eb07dc9 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -2799,7 +2799,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) * IEEE80211 stack callback functions. */ static int rt61pci_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue_idx, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2815,7 +2816,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 5ff2c740c3ea..e3269fd7c59e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -2218,7 +2218,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * IEEE80211 stack callback functions. */ static int rt73usb_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue_idx, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2234,7 +2235,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index f66cc9083972..cdfe08078c57 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1424,7 +1424,8 @@ static void rtl8187se_conf_ac_parm(struct ieee80211_hw *dev, u8 queue) } static int rtl8180_conf_tx(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rtl8180_priv *priv = dev->priv; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index edc84f9dc984..c0f6e9c6d03e 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1338,7 +1338,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, } static int rtl8187_conf_tx(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 65c4cb1e030c..33a1d9143038 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5957,7 +5957,8 @@ exit: } static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *param) { struct rtl8xxxu_priv *priv = hw->priv; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 8537cc6d7a89..519b2643f9f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -982,7 +982,8 @@ static int _rtl_get_hal_qnum(u16 queue) *for rtl819x BE = 0, BK = 1, VI = 2, VO = 3 */ static int rtl_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *param) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index ba60ca7ecdbf..bb7291665d37 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -443,7 +443,8 @@ static int rtw_ops_start_ap(struct ieee80211_hw *hw, } static int rtw_ops_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { struct rtw_dev *rtwdev = hw->priv; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 20fb4c550010..f40569c8575c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -427,7 +427,8 @@ static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, } static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { struct rtw89_dev *rtwdev = hw->priv; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 1dff3d263382..bf39c4bda26f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -895,7 +895,8 @@ static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, * Return: 0 on success, negative error code on failure. */ static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rsi_hw *adapter = hw->priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 47fd887ce6fe..89402afe4fe6 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -216,7 +216,8 @@ int wfx_update_pm(struct wfx_vif *wvif) } int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct wfx_dev *wdev = hw->priv; struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index 93ea992de1d7..6558c5698cc8 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -36,7 +36,8 @@ void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params); void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed); int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index a3f6942df0c1..26d3614519b1 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -606,7 +606,8 @@ void cw1200_configure_filter(struct ieee80211_hw *dev, } int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct cw1200_common *priv = dev->priv; int ret = 0; diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index 05e3ab7ccef1..a49f187c7049 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -28,7 +28,8 @@ void cw1200_configure_filter(struct ieee80211_hw *dev, unsigned int *total_flags, u64 multicast); int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params); int cw1200_get_stats(struct ieee80211_hw *dev, struct ieee80211_low_level_stats *stats); int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index d76558964420..9144ef5538a8 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1282,7 +1282,8 @@ static struct ieee80211_channel wl1251_channels[] = { }; static int wl1251_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { enum wl1251_acx_ps_scheme ps_scheme; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d1200080f165..1edec9f3c0d8 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4864,7 +4864,8 @@ out: } static int wl1271_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct wl1271 *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fba06d7bc7eb..7cf8d58eb5f0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4174,7 +4174,8 @@ struct ieee80211_ops { struct ieee80211_sta *sta, struct station_info *sinfo); int (*conf_tx)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 ac, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params); u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index aa3a1568c7fc..fa3b6cc2cafa 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2570,6 +2570,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_link_data *link = &sdata->deflink; struct ieee80211_tx_queue_params p; if (!local->ops->conf_tx) @@ -2592,15 +2593,15 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, ieee80211_regulatory_limit_wmm_params(sdata, &p, params->ac); - sdata->tx_conf[params->ac] = p; - if (drv_conf_tx(local, sdata, params->ac, &p)) { + link->tx_conf[params->ac] = p; + if (drv_conf_tx(local, link, params->ac, &p)) { wiphy_debug(local->hw.wiphy, "failed to set TX queue parameters for AC %d\n", params->ac); return -EINVAL; } - ieee80211_link_info_change_notify(sdata, &sdata->deflink, + ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_QOS); return 0; diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index 48322e45e7dd..9b61dc7889c2 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2015 Intel Deutschland GmbH + * Copyright (C) 2022 Intel Corporation */ #include #include "ieee80211_i.h" @@ -180,9 +181,10 @@ void drv_sta_rc_update(struct ieee80211_local *local, } int drv_conf_tx(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, u16 ac, + struct ieee80211_link_data *link, u16 ac, const struct ieee80211_tx_queue_params *params) { + struct ieee80211_sub_if_data *sdata = link->sdata; int ret = -EOPNOTSUPP; might_sleep(); @@ -201,10 +203,10 @@ int drv_conf_tx(struct ieee80211_local *local, return -EINVAL; } - trace_drv_conf_tx(local, sdata, ac, params); + trace_drv_conf_tx(local, sdata, link->link_id, ac, params); if (local->ops->conf_tx) ret = local->ops->conf_tx(&local->hw, &sdata->vif, - ac, params); + link->link_id, ac, params); trace_drv_return_int(local, ret); return ret; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ee3ac1a01bb0..eb16a354338c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -590,7 +590,7 @@ static inline void drv_sta_statistics(struct ieee80211_local *local, } int drv_conf_tx(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, u16 ac, + struct ieee80211_link_data *link, u16 ac, const struct ieee80211_tx_queue_params *params); u64 drv_get_tsf(struct ieee80211_local *local, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 561abcf4def9..0a1d51c60530 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -356,7 +356,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - ieee80211_set_wmm_default(sdata, true, false); + ieee80211_set_wmm_default(&sdata->deflink, true, false); sdata->vif.cfg.ibss_joined = true; sdata->vif.cfg.ibss_creator = creator; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 05996df627ea..699dabaa9f0d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -969,6 +969,8 @@ struct ieee80211_link_data { struct ieee80211_link_data_ap ap; } u; + struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; + struct ieee80211_bss_conf *conf; }; @@ -1012,7 +1014,6 @@ struct ieee80211_sub_if_data { bool control_port_over_nl80211; atomic_t num_tx_queued; - struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; struct mac80211_qos_map __rcu *qos_map; /* used to reconfigure hardware SM PS */ @@ -2101,7 +2102,7 @@ int ieee80211_frame_duration(enum nl80211_band band, size_t len, void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_queue_params *qparam, int ac); -void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, +void ieee80211_set_wmm_default(struct ieee80211_link_data *link, bool bss_notify, bool enable_qos); void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct sk_buff *skb); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 312a812bec84..f29764936c99 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1539,7 +1539,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) * doesn't start up with sane defaults. * Enable QoS for anything but station interfaces. */ - ieee80211_set_wmm_default(sdata, true, + ieee80211_set_wmm_default(&sdata->deflink, true, sdata->vif.type != NL80211_IFTYPE_STATION); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5400b3e567fa..44f76a8fa80b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2018,10 +2018,11 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) switch (tx_tspec->action) { case TX_TSPEC_ACTION_STOP_DOWNGRADE: /* take the original parameters */ - if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac])) - sdata_err(sdata, - "failed to set TX queue parameters for queue %d\n", - ac); + if (drv_conf_tx(local, &sdata->deflink, ac, + &sdata->deflink.tx_conf[ac])) + link_err(&sdata->deflink, + "failed to set TX queue parameters for queue %d\n", + ac); tx_tspec->action = TX_TSPEC_ACTION_NONE; tx_tspec->downgraded = false; ret = true; @@ -2047,11 +2048,11 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) */ if (non_acm_ac >= IEEE80211_NUM_ACS) non_acm_ac = IEEE80211_AC_BK; - if (drv_conf_tx(local, sdata, ac, - &sdata->tx_conf[non_acm_ac])) - sdata_err(sdata, - "failed to set TX queue parameters for queue %d\n", - ac); + if (drv_conf_tx(local, &sdata->deflink, ac, + &sdata->deflink.tx_conf[non_acm_ac])) + link_err(&sdata->deflink, + "failed to set TX queue parameters for queue %d\n", + ac); tx_tspec->action = TX_TSPEC_ACTION_NONE; ret = true; schedule_delayed_work(&ifmgd->tx_tspec_wk, @@ -2085,10 +2086,11 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) /* MLME */ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, const u8 *wmm_param, size_t wmm_param_len, const struct ieee80211_mu_edca_param_set *mu_edca) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS]; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; size_t left; @@ -2117,11 +2119,11 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local, * the driver about it. */ mu_edca_count = mu_edca ? mu_edca->mu_qos_info & 0x0f : -1; - if (count == sdata->deflink.u.mgd.wmm_last_param_set && - mu_edca_count == sdata->deflink.u.mgd.mu_edca_last_param_set) + if (count == link->u.mgd.wmm_last_param_set && + mu_edca_count == link->u.mgd.mu_edca_last_param_set) return false; - sdata->deflink.u.mgd.wmm_last_param_set = count; - sdata->deflink.u.mgd.mu_edca_last_param_set = mu_edca_count; + link->u.mgd.wmm_last_param_set = count; + link->u.mgd.mu_edca_last_param_set = mu_edca_count; pos = wmm_param + 8; left = wmm_param_len - 8; @@ -2219,16 +2221,16 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local, params[ac].aifs, params[ac].cw_min, params[ac].cw_max, params[ac].txop, params[ac].uapsd, ifmgd->tx_tspec[ac].downgraded); - sdata->tx_conf[ac] = params[ac]; + link->tx_conf[ac] = params[ac]; if (!ifmgd->tx_tspec[ac].downgraded && - drv_conf_tx(local, sdata, ac, ¶ms[ac])) - sdata_err(sdata, - "failed to set TX queue parameters for AC %d\n", - ac); + drv_conf_tx(local, link, ac, ¶ms[ac])) + link_err(link, + "failed to set TX queue parameters for AC %d\n", + ac); } /* enable WMM or activate new settings */ - sdata->vif.bss_conf.qos = true; + link->conf->qos = true; return true; } @@ -2508,7 +2510,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, changed); /* disassociated - set to defaults now */ - ieee80211_set_wmm_default(sdata, false, false); + ieee80211_set_wmm_default(&sdata->deflink, false, false); del_timer_sync(&sdata->u.mgd.conn_mon_timer); del_timer_sync(&sdata->u.mgd.bcn_mon_timer); @@ -3766,12 +3768,13 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sdata->deflink.u.mgd.mu_edca_last_param_set = -1; if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { - ieee80211_set_wmm_default(sdata, false, false); - } else if (!ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, + ieee80211_set_wmm_default(&sdata->deflink, false, false); + } else if (!ieee80211_sta_wmm_params(local, &sdata->deflink, + elems->wmm_param, elems->wmm_param_len, elems->mu_edca_param_set)) { /* still enable QoS since we might have HT/VHT */ - ieee80211_set_wmm_default(sdata, false, true); + ieee80211_set_wmm_default(&sdata->deflink, false, true); /* set the disable-WMM flag in this case to disable * tracking WMM parameter changes in the beacon if * the parameters weren't actually valid. Doing so @@ -3938,7 +3941,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, /* get uapsd queues configuration */ uapsd_queues = 0; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (sdata->tx_conf[ac].uapsd) + if (sdata->deflink.tx_conf[ac].uapsd) uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; info.success = 1; @@ -4363,7 +4366,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, elems, true); if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && - ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, + ieee80211_sta_wmm_params(local, &sdata->deflink, elems->wmm_param, elems->wmm_param_len, elems->mu_edca_param_set)) changed |= BSS_CHANGED_QOS; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 30f2b340017c..e7bdcdb488e2 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -293,7 +293,7 @@ static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, * doesn't support it, as mandated by 802.11-2012 section 10.22.4 */ for (i = 0; i < IEEE80211_NUM_ACS; i++) { - txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)]; + txq = &sdata->deflink.tx_conf[ieee80211_ac_from_wmm(i)]; wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs, txq->acm, i); wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 751f08b47d0c..b6f12ac91849 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1003,13 +1003,15 @@ DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update, TRACE_EVENT(drv_conf_tx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params), - TP_ARGS(local, sdata, ac, params), + TP_ARGS(local, sdata, link_id, ac, params), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY + __field(unsigned int, link_id) __field(u16, ac) __field(u16, txop) __field(u16, cw_min) @@ -1021,6 +1023,7 @@ TRACE_EVENT(drv_conf_tx, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; + __entry->link_id = link_id; __entry->ac = ac; __entry->txop = params->txop; __entry->cw_max = params->cw_max; @@ -1030,8 +1033,8 @@ TRACE_EVENT(drv_conf_tx, ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " AC:%d", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac + LOCAL_PR_FMT VIF_PR_FMT " link_id: %d, AC:%d", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, __entry->ac ) ); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f06514087511..2b2c8e1472f3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1596,9 +1596,10 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } -void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, +void ieee80211_set_wmm_default(struct ieee80211_link_data *link, bool bss_notify, bool enable_qos) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; struct ieee80211_chanctx_conf *chanctx_conf; @@ -1616,7 +1617,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, memset(&qparam, 0, sizeof(qparam)); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + chanctx_conf = rcu_dereference(link->conf->chanctx_conf); use_11b = (chanctx_conf && chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); @@ -1693,17 +1694,16 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, qparam.uapsd = false; - sdata->tx_conf[ac] = qparam; - drv_conf_tx(local, sdata, ac, &qparam); + link->tx_conf[ac] = qparam; + drv_conf_tx(local, link, ac, &qparam); } if (sdata->vif.type != NL80211_IFTYPE_MONITOR && sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_NAN) { - sdata->vif.bss_conf.qos = enable_qos; + link->conf->qos = enable_qos; if (bss_notify) - ieee80211_link_info_change_notify(sdata, - &sdata->deflink, + ieee80211_link_info_change_notify(sdata, link, BSS_CHANGED_QOS); } } @@ -2520,8 +2520,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) fallthrough; case NL80211_IFTYPE_AP: /* AP stations are handled later */ for (i = 0; i < IEEE80211_NUM_ACS; i++) - drv_conf_tx(local, sdata, i, - &sdata->tx_conf[i]); + drv_conf_tx(local, &sdata->deflink, i, + &sdata->deflink.tx_conf[i]); break; } -- cgit v1.2.3 From b65567b03c9502e67bed6707cb53a4c730c2bee2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jun 2022 16:08:39 +0200 Subject: wifi: mac80211: mlme: track AP (MLD) address separately To prepare a bit more for MLO in the client code, track the AP's address (for now only the BSSID, but will track the AP MLD's address later) separately from the per-link BSSID. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/mlme.c | 30 ++++++++++++++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7cf8d58eb5f0..36eba96a1012 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1728,6 +1728,8 @@ enum ieee80211_offload_flags { * @idle: This interface is idle. There's also a global idle flag in the * hardware config which may be more appropriate depending on what * your driver/device needs to do. + * @ap_addr: AP MLD address, or BSSID for non-MLO connections + * (station mode only) */ struct ieee80211_vif_cfg { /* association related data */ @@ -1742,6 +1744,7 @@ struct ieee80211_vif_cfg { size_t ssid_len; bool s1g; bool idle; + u8 ap_addr[ETH_ALEN] __aligned(2); }; /** diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7eab15920a70..a2e8fe9b43ab 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1808,7 +1808,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) return false; rcu_read_lock(); - sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); if (sta) authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); rcu_read_unlock(); @@ -2313,6 +2313,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.associated = true; sdata->deflink.u.mgd.bss = cbss; memcpy(sdata->deflink.u.mgd.bssid, cbss->bssid, ETH_ALEN); + memcpy(sdata->vif.cfg.ap_addr, cbss->bssid, ETH_ALEN); ieee80211_check_rate_mask(sdata); @@ -2463,6 +2464,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* clear bssid only after building the needed mgmt frames */ eth_zero_addr(sdata->deflink.u.mgd.bssid); + eth_zero_addr(sdata->vif.cfg.ap_addr); sdata->vif.cfg.ssid_len = 0; /* remove AP and TDLS peers */ @@ -2653,7 +2655,7 @@ static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata, static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u8 *dst = sdata->deflink.u.mgd.bssid; + u8 *dst = sdata->vif.cfg.ap_addr; u8 unicast_limit = max(1, max_probe_tries - 3); struct sta_info *sta; @@ -2882,13 +2884,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) if (ifmgd->connection_loss) { sdata_info(sdata, "Connection to AP %pM lost\n", - sdata->deflink.u.mgd.bssid); + sdata->vif.cfg.ap_addr); __ieee80211_disconnect(sdata); ifmgd->connection_loss = false; } else if (ifmgd->driver_disconnect) { sdata_info(sdata, "Driver requested disconnection from AP %pM\n", - sdata->deflink.u.mgd.bssid); + sdata->vif.cfg.ap_addr); __ieee80211_disconnect(sdata); ifmgd->driver_disconnect = false; } else { @@ -3042,7 +3044,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, } static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, - const u8 *bssid) + const u8 *ap_addr) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sta_info *sta; @@ -3056,14 +3058,14 @@ static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, /* move station state to auth */ mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(sdata, ap_addr); if (!sta) { - WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); + WARN_ONCE(1, "%s: STA %pM not found", sdata->name, ap_addr); result = false; goto out; } if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { - sdata_info(sdata, "failed moving %pM to auth\n", bssid); + sdata_info(sdata, "failed moving %pM to auth\n", ap_addr); result = false; goto out; } @@ -4402,7 +4404,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, erp_valid, erp_value); mutex_lock(&local->sta_mtx); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); changed |= ieee80211_recalc_twt_req(sdata, sta, elems); @@ -4885,7 +4887,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) !sdata->deflink.u.mgd.csa_waiting_bcn) return; - sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); + sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); if (!sta) return; @@ -4981,7 +4983,7 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) .bssid = bssid, }; - memcpy(bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); + memcpy(bssid, sdata->vif.cfg.ap_addr, ETH_ALEN); ieee80211_mgd_deauth(sdata, &req); } @@ -5909,7 +5911,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "disconnect from AP %pM for new auth to %pM\n", - sdata->deflink.u.mgd.bssid, req->bss->bssid); + sdata->vif.cfg.ap_addr, req->bss->bssid); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_UNSPECIFIED, false, frame_buf); @@ -5986,7 +5988,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "disconnect from AP %pM for new assoc to %pM\n", - sdata->deflink.u.mgd.bssid, req->bss->bssid); + sdata->vif.cfg.ap_addr, req->bss->bssid); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_UNSPECIFIED, false, frame_buf); @@ -6344,7 +6346,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } if (ifmgd->associated && - ether_addr_equal(sdata->deflink.u.mgd.bssid, req->bssid)) { + ether_addr_equal(sdata->vif.cfg.ap_addr, req->bssid)) { sdata_info(sdata, "deauthenticating from %pM by local choice (Reason: %u=%s)\n", req->bssid, req->reason_code, -- cgit v1.2.3 From 8f6e0dfc2245d8ca1a3335a06a1219c56df04bb8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 16:19:18 +0200 Subject: wifi: cfg80211: remove BSS pointer from cfg80211_disassoc_request The race described by the comment in mac80211 hasn't existed since the locking rework to use the same lock and for MLO we need to pass the AP MLD address, so just pass the BSSID or AP MLD address instead of the BSS struct pointer, and adjust all the code accordingly. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 6 +++--- net/mac80211/mlme.c | 14 +++++--------- net/wireless/core.h | 2 +- net/wireless/mlme.c | 8 +++----- net/wireless/trace.h | 5 +---- 5 files changed, 13 insertions(+), 22 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a4e2cb2378b8..d0be08483fa6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2886,7 +2886,7 @@ struct cfg80211_assoc_request { * This structure provides information needed to complete IEEE 802.11 * deauthentication. * - * @bssid: the BSSID of the BSS to deauthenticate from + * @bssid: the BSSID or AP MLD address to deauthenticate from * @ie: Extra IEs to add to Deauthentication frame or %NULL * @ie_len: Length of ie buffer in octets * @reason_code: The reason code for the deauthentication @@ -2907,7 +2907,7 @@ struct cfg80211_deauth_request { * This structure provides information needed to complete IEEE 802.11 * disassociation. * - * @bss: the BSS to disassociate from + * @ap_addr: the BSSID or AP MLD address to disassociate from * @ie: Extra IEs to add to Disassociation frame or %NULL * @ie_len: Length of ie buffer in octets * @reason_code: The reason code for the disassociation @@ -2915,7 +2915,7 @@ struct cfg80211_deauth_request { * Disassociation frame is to be transmitted. */ struct cfg80211_disassoc_request { - struct cfg80211_bss *bss; + const u8 *ap_addr; const u8 *ie; size_t ie_len; u16 reason_code; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b71de89d9734..a2b4536c3a24 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6426,18 +6426,14 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, { u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; - /* - * cfg80211 should catch this ... but it's racy since - * we can receive a disassoc frame, process it, hand it - * to cfg80211 while that's in a locked section already - * trying to tell us that the user wants to disconnect. - */ - if (sdata->deflink.u.mgd.bss != req->bss) - return -ENOLINK; + if (!sdata->u.mgd.associated || + memcmp(sdata->vif.cfg.ap_addr, req->ap_addr, ETH_ALEN)) + return -ENOTCONN; sdata_info(sdata, "disassociating from %pM by local choice (Reason: %u=%s)\n", - req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); + req->ap_addr, req->reason_code, + ieee80211_get_reason_code_string(req->reason_code)); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, req->reason_code, !req->local_state_change, diff --git a/net/wireless/core.h b/net/wireless/core.h index fd723fa5e2d7..e72ca6eefafb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -372,7 +372,7 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, const u8 *ie, int ie_len, u16 reason, bool local_state_change); int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *bssid, + struct net_device *dev, const u8 *ap_addr, const u8 *ie, int ie_len, u16 reason, bool local_state_change); void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 935537c64ed8..4a35b3559daa 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -370,7 +370,7 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, } int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *bssid, + struct net_device *dev, const u8 *ap_addr, const u8 *ie, int ie_len, u16 reason, bool local_state_change) { @@ -380,6 +380,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, .local_state_change = local_state_change, .ie = ie, .ie_len = ie_len, + .ap_addr = ap_addr, }; int err; @@ -388,10 +389,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, if (!wdev->connected) return -ENOTCONN; - if (ether_addr_equal(wdev->links[0].client.current_bss->pub.bssid, - bssid)) - req.bss = &wdev->links[0].client.current_bss->pub; - else + if (memcmp(wdev->u.client.connected_addr, ap_addr, ETH_ALEN)) return -ENOTCONN; err = rdev_disassoc(rdev, dev, &req); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index c50e8a04199e..4316d3dc31ea 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1318,10 +1318,7 @@ TRACE_EVENT(rdev_disassoc, TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; - if (req->bss) - MAC_ASSIGN(bssid, req->bss->bssid); - else - eth_zero_addr(__entry->bssid); + MAC_ASSIGN(bssid, req->ap_addr); __entry->reason_code = req->reason_code; __entry->local_state_change = req->local_state_change; ), -- cgit v1.2.3 From f662d2f4e22e5d5a9215e9c881875a4769494ef6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jun 2022 22:09:50 +0200 Subject: wifi: cfg80211: prepare association failure APIs for MLO For MLO, we need the ability to report back multiple BSS structures to release, as well as the AP MLD address (if attempting to make an MLO connection). Unify cfg80211_assoc_timeout() and cfg80211_abandon_assoc() into a new cfg80211_assoc_failure() that gets a structure parameter with the necessary data. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 29 +++++++++++++++++------------ net/mac80211/mlme.c | 28 +++++++++++++++++++++++----- net/wireless/mlme.c | 36 +++++++++++++++++++----------------- net/wireless/trace.h | 19 ++++++++++++++++--- 4 files changed, 75 insertions(+), 37 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d0be08483fa6..fbbe1796b85f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6900,24 +6900,29 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, const u8 *req_ies, size_t req_ies_len); /** - * cfg80211_assoc_timeout - notification of timed out association - * @dev: network device - * @bss: The BSS entry with which association timed out. - * - * This function may sleep. The caller must hold the corresponding wdev's mutex. - */ -void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss); + * struct cfg80211_assoc_failure - association failure data + * @ap_mld_addr: AP MLD address, or %NULL + * @bss: list of BSSes, must use entry 0 for non-MLO connections + * (@ap_mld_addr is %NULL) + * @timeout: indicates the association failed due to timeout, otherwise + * the association was abandoned for a reason reported through some + * other API (e.g. deauth RX) + */ +struct cfg80211_assoc_failure { + const u8 *ap_mld_addr; + struct cfg80211_bss *bss[IEEE80211_MLD_MAX_NUM_LINKS]; + bool timeout; +}; /** - * cfg80211_abandon_assoc - notify cfg80211 of abandoned association attempt + * cfg80211_assoc_failure - notification of association failure * @dev: network device - * @bss: The BSS entry with which association was abandoned. + * @data: data describing the association failure * - * Call this whenever - for reasons reported through other API, like deauth RX, - * an association attempt was abandoned. * This function may sleep. The caller must hold the corresponding wdev's mutex. */ -void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss); +void cfg80211_assoc_failure(struct net_device *dev, + struct cfg80211_assoc_failure *data); /** * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a2b4536c3a24..e1c4a4dcfc70 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3027,8 +3027,13 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); - if (abandon) - cfg80211_abandon_assoc(sdata->dev, assoc_data->bss); + if (abandon) { + struct cfg80211_assoc_failure data = { + .bss[0] = assoc_data->bss, + }; + + cfg80211_assoc_failure(sdata->dev, &data); + } } kfree(assoc_data); @@ -3956,8 +3961,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } else { if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { /* oops -- internal error -- send timeout for now */ + struct cfg80211_assoc_failure data = { + .timeout = true, + .bss[0] = cbss, + }; ieee80211_destroy_assoc_data(sdata, false, false); - cfg80211_assoc_timeout(sdata->dev, cbss); + cfg80211_assoc_failure(sdata->dev, &data); goto notify_driver; } event.u.mlme.status = MLME_SUCCESS; @@ -4833,9 +4842,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) .u.mlme.data = ASSOC_EVENT, .u.mlme.status = MLME_TIMEOUT, }; + struct cfg80211_assoc_failure data = { + .bss[0] = bss, + .timeout = true, + }; ieee80211_destroy_assoc_data(sdata, false, false); - cfg80211_assoc_timeout(sdata->dev, bss); + cfg80211_assoc_failure(sdata->dev, &data); drv_event_callback(sdata->local, sdata, &event); } } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) @@ -6468,8 +6481,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) sdata_lock(sdata); if (ifmgd->assoc_data) { struct cfg80211_bss *bss = ifmgd->assoc_data->bss; + struct cfg80211_assoc_failure data = { + .bss[0] = bss, + .timeout = true, + }; + ieee80211_destroy_assoc_data(sdata, false, false); - cfg80211_assoc_timeout(sdata->dev, bss); + cfg80211_assoc_failure(sdata->dev, &data); } if (ifmgd->auth_data) ieee80211_destroy_auth_data(sdata, false); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4a35b3559daa..aefe8b26f0d7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -154,33 +154,35 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) } EXPORT_SYMBOL(cfg80211_auth_timeout); -void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss) +void cfg80211_assoc_failure(struct net_device *dev, + struct cfg80211_assoc_failure *data) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + const u8 *addr = data->ap_mld_addr ?: data->bss[0]->bssid; + int i; - trace_cfg80211_send_assoc_timeout(dev, bss->bssid); - - nl80211_send_assoc_timeout(rdev, dev, bss->bssid, GFP_KERNEL); - cfg80211_sme_assoc_timeout(wdev); + trace_cfg80211_send_assoc_failure(dev, data); - cfg80211_unhold_bss(bss_from_pub(bss)); - cfg80211_put_bss(wiphy, bss); -} -EXPORT_SYMBOL(cfg80211_assoc_timeout); + if (data->timeout) { + nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); + cfg80211_sme_assoc_timeout(wdev); + } else { + cfg80211_sme_abandon_assoc(wdev); + } -void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct wiphy *wiphy = wdev->wiphy; + for (i = 0; i < ARRAY_SIZE(data->bss); i++) { + struct cfg80211_bss *bss = data->bss[i]; - cfg80211_sme_abandon_assoc(wdev); + if (!bss) + continue; - cfg80211_unhold_bss(bss_from_pub(bss)); - cfg80211_put_bss(wiphy, bss); + cfg80211_unhold_bss(bss_from_pub(bss)); + cfg80211_put_bss(wiphy, bss); + } } -EXPORT_SYMBOL(cfg80211_abandon_assoc); +EXPORT_SYMBOL(cfg80211_assoc_failure); void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len, bool reconnect) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 4316d3dc31ea..19efb9539533 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2969,9 +2969,22 @@ DEFINE_EVENT(netdev_mac_evt, cfg80211_send_auth_timeout, TP_ARGS(netdev, mac) ); -DEFINE_EVENT(netdev_mac_evt, cfg80211_send_assoc_timeout, - TP_PROTO(struct net_device *netdev, const u8 *mac), - TP_ARGS(netdev, mac) +TRACE_EVENT(cfg80211_send_assoc_failure, + TP_PROTO(struct net_device *netdev, + struct cfg80211_assoc_failure *data), + TP_ARGS(netdev, data), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(ap_addr) + __field(bool, timeout) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(ap_addr, data->ap_mld_addr ?: data->bss[0]->bssid); + __entry->timeout = data->timeout; + ), + TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT ", timeout: %d", + NETDEV_PR_ARG, MAC_PR_ARG(ap_addr), __entry->timeout) ); TRACE_EVENT(cfg80211_michael_mic_failure, -- cgit v1.2.3 From e69dac88a155bd626170bb0bb43f83fb564392f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 11:25:38 +0200 Subject: wifi: cfg80211: adjust assoc comeback for MLO We only report the BSSID to userspace, so change the argument from BSS struct pointer to AP address, which we'll use to carry either the BSSID or AP MLD address. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++-- net/mac80211/mlme.c | 2 +- net/wireless/nl80211.c | 6 +++--- net/wireless/trace.h | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fbbe1796b85f..1d8cecf035d1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -8592,13 +8592,13 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, * cfg80211_assoc_comeback - notification of association that was * temporarly rejected with a comeback * @netdev: network device - * @bss: the bss entry with which association is in progress. + * @ap_addr: AP (MLD) address that rejected the assocation * @timeout: timeout interval value TUs. * * this function may sleep. the caller must hold the corresponding wdev's mutex. */ void cfg80211_assoc_comeback(struct net_device *netdev, - struct cfg80211_bss *bss, u32 timeout); + const u8 *ap_addr, u32 timeout); /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ac37cf74ab74..91f07b67f2f0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3944,7 +3944,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { u32 tu, ms; - cfg80211_assoc_comeback(sdata->dev, assoc_data->bss, + cfg80211_assoc_comeback(sdata->dev, assoc_data->bss->bssid, le32_to_cpu(elems->timeout_int->value)); tu = le32_to_cpu(elems->timeout_int->value); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 886d964242ae..6c3b47a7960f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18036,7 +18036,7 @@ static void nl80211_send_remain_on_chan_event( } void cfg80211_assoc_comeback(struct net_device *netdev, - struct cfg80211_bss *bss, u32 timeout) + const u8 *ap_addr, u32 timeout) { struct wireless_dev *wdev = netdev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -18044,7 +18044,7 @@ void cfg80211_assoc_comeback(struct net_device *netdev, struct sk_buff *msg; void *hdr; - trace_cfg80211_assoc_comeback(wdev, bss->bssid, timeout); + trace_cfg80211_assoc_comeback(wdev, ap_addr, timeout); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) @@ -18058,7 +18058,7 @@ void cfg80211_assoc_comeback(struct net_device *netdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->bssid) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ap_addr) || nla_put_u32(msg, NL80211_ATTR_TIMEOUT, timeout)) goto nla_put_failure; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 19efb9539533..94d107cab72c 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3764,20 +3764,20 @@ TRACE_EVENT(cfg80211_bss_color_notify, ); TRACE_EVENT(cfg80211_assoc_comeback, - TP_PROTO(struct wireless_dev *wdev, const u8 *bssid, u32 timeout), - TP_ARGS(wdev, bssid, timeout), + TP_PROTO(struct wireless_dev *wdev, const u8 *ap_addr, u32 timeout), + TP_ARGS(wdev, ap_addr, timeout), TP_STRUCT__entry( WDEV_ENTRY - MAC_ENTRY(bssid) + MAC_ENTRY(ap_addr) __field(u32, timeout) ), TP_fast_assign( WDEV_ASSIGN; - MAC_ASSIGN(bssid, bssid); + MAC_ASSIGN(ap_addr, ap_addr); __entry->timeout = timeout; ), TP_printk(WDEV_PR_FMT ", " MAC_PR_FMT ", timeout: %u TUs", - WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout) + WDEV_PR_ARG, MAC_PR_ARG(ap_addr), __entry->timeout) ); DECLARE_EVENT_CLASS(link_station_add_mod, -- cgit v1.2.3 From cd47c0f57ae6607cfa3d161e341cbdd283bc444f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 16:25:37 +0200 Subject: wifi: cfg80211: put cfg80211_rx_assoc_resp() arguments into a struct For MLO we'll need a lot more arguments, including all the BSS pointers and link addresses, so move the data to a struct to be able to extend it more easily later. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 24 +++++++++++++++++------- net/mac80211/mlme.c | 17 ++++++++++++----- net/wireless/mlme.c | 32 +++++++++++++++----------------- net/wireless/nl80211.c | 12 ++++++------ net/wireless/nl80211.h | 4 +--- 5 files changed, 51 insertions(+), 38 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1d8cecf035d1..2628e8f98a13 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6877,16 +6877,29 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr); /** - * cfg80211_rx_assoc_resp - notification of processed association response - * @dev: network device + * struct cfg80211_rx_assoc_resp - association response data * @bss: the BSS that association was requested with, ownership of the pointer - * moves to cfg80211 in this call + * moves to cfg80211 in the call to cfg80211_rx_assoc_resp() * @buf: (Re)Association Response frame (header + body) * @len: length of the frame data * @uapsd_queues: bitmap of queues configured for uapsd. Same format * as the AC bitmap in the QoS info field * @req_ies: information elements from the (Re)Association Request frame * @req_ies_len: length of req_ies data + */ +struct cfg80211_rx_assoc_resp { + struct cfg80211_bss *bss; + const u8 *buf; + size_t len; + const u8 *req_ies; + size_t req_ies_len; + int uapsd_queues; +}; + +/** + * cfg80211_rx_assoc_resp - notification of processed association response + * @dev: network device + * @data: association response data, &struct cfg80211_rx_assoc_resp * * After being asked to associate via cfg80211_ops::assoc() the driver must * call either this function or cfg80211_auth_timeout(). @@ -6894,10 +6907,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr); * This function may sleep. The caller must hold the corresponding wdev's mutex. */ void cfg80211_rx_assoc_resp(struct net_device *dev, - struct cfg80211_bss *bss, - const u8 *buf, size_t len, - int uapsd_queues, - const u8 *req_ies, size_t req_ies_len); + struct cfg80211_rx_assoc_resp *data); /** * struct cfg80211_assoc_failure - association failure data diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 91f07b67f2f0..ecbd70a1fbb7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3878,7 +3878,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; u16 capab_info, status_code, aid; struct ieee802_11_elems *elems; - int ac, uapsd_queues = -1; + int ac; u8 *pos; bool reassoc; struct cfg80211_bss *cbss; @@ -3887,6 +3887,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, .u.mlme.data = ASSOC_EVENT, }; struct ieee80211_prep_tx_info info = {}; + struct cfg80211_rx_assoc_resp resp = { + .uapsd_queues = -1, + }; sdata_assert_lock(sdata); @@ -3984,16 +3987,20 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_destroy_assoc_data(sdata, ASSOC_SUCCESS); /* get uapsd queues configuration */ - uapsd_queues = 0; + resp.uapsd_queues = 0; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) if (sdata->deflink.tx_conf[ac].uapsd) - uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; + resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; info.success = 1; } - cfg80211_rx_assoc_resp(sdata->dev, cbss, (u8 *)mgmt, len, uapsd_queues, - ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); + resp.bss = cbss; + resp.buf = (u8 *)mgmt; + resp.len = len; + resp.req_ies = ifmgd->assoc_req_ies; + resp.req_ies_len = ifmgd->assoc_req_ies_len; + cfg80211_rx_assoc_resp(sdata->dev, &resp); notify_driver: drv_mgd_complete_tx(sdata->local, sdata, &info); kfree(elems); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index aefe8b26f0d7..a6ad696f131b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -21,36 +21,35 @@ #include "rdev-ops.h" -void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, - const u8 *buf, size_t len, int uapsd_queues, - const u8 *req_ies, size_t req_ies_len) +void cfg80211_rx_assoc_resp(struct net_device *dev, + struct cfg80211_rx_assoc_resp *data) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)data->buf; struct cfg80211_connect_resp_params cr; const u8 *resp_ie = mgmt->u.assoc_resp.variable; - size_t resp_ie_len = len - offsetof(struct ieee80211_mgmt, - u.assoc_resp.variable); + size_t resp_ie_len = data->len - offsetof(struct ieee80211_mgmt, + u.assoc_resp.variable); - if (bss->channel->band == NL80211_BAND_S1GHZ) { + if (data->bss->channel->band == NL80211_BAND_S1GHZ) { resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable; - resp_ie_len = len - offsetof(struct ieee80211_mgmt, - u.s1g_assoc_resp.variable); + resp_ie_len = data->len - offsetof(struct ieee80211_mgmt, + u.s1g_assoc_resp.variable); } memset(&cr, 0, sizeof(cr)); cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); cr.links[0].bssid = mgmt->bssid; - cr.links[0].bss = bss; - cr.req_ie = req_ies; - cr.req_ie_len = req_ies_len; + cr.links[0].bss = data->bss; + cr.req_ie = data->req_ies; + cr.req_ie_len = data->req_ies_len; cr.resp_ie = resp_ie; cr.resp_ie_len = resp_ie_len; cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; - trace_cfg80211_send_rx_assoc(dev, bss); + trace_cfg80211_send_rx_assoc(dev, data->bss); /* * This is a bit of a hack, we don't notify userspace of @@ -59,13 +58,12 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, * frame instead of reassoc. */ if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) { - cfg80211_unhold_bss(bss_from_pub(bss)); - cfg80211_put_bss(wiphy, bss); + cfg80211_unhold_bss(bss_from_pub(data->bss)); + cfg80211_put_bss(wiphy, data->bss); return; } - nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues, - req_ies, req_ies_len); + nl80211_send_rx_assoc(rdev, dev, data); /* update current_bss etc., consumes the bss reference */ __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6c3b47a7960f..11cad2d46d0e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -17432,13 +17432,13 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, } void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, - size_t len, gfp_t gfp, int uapsd_queues, - const u8 *req_ies, size_t req_ies_len) + struct net_device *netdev, + struct cfg80211_rx_assoc_resp *data) { - nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_ASSOCIATE, gfp, uapsd_queues, - req_ies, req_ies_len, false); + nl80211_send_mlme_event(rdev, netdev, data->buf, data->len, + NL80211_CMD_ASSOCIATE, GFP_KERNEL, + data->uapsd_queues, + data->req_ies, data->req_ies_len, false); } void nl80211_send_deauth(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index d642e3be4ee7..a7e8e0917c1c 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -60,9 +60,7 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len, gfp_t gfp, - int uapsd_queues, - const u8 *req_ies, size_t req_ies_len); + struct cfg80211_rx_assoc_resp *data); void nl80211_send_deauth(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, -- cgit v1.2.3 From 5cd212cb6415aa604ada17d5150847fd65d27337 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Jun 2022 17:17:05 +0200 Subject: wifi: cfg80211: extend cfg80211_rx_assoc_resp() for MLO Extend the cfg80211_rx_assoc_resp() to cover multiple BSSes, the AP MLD address and local link addresses for MLO. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 9 ++++++- net/mac80211/mlme.c | 2 +- net/wireless/mlme.c | 64 +++++++++++++++++++++++++++++++++----------------- net/wireless/trace.h | 16 ++++++------- 4 files changed, 59 insertions(+), 32 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2628e8f98a13..2fe3eff11a8b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6886,14 +6886,21 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr); * as the AC bitmap in the QoS info field * @req_ies: information elements from the (Re)Association Request frame * @req_ies_len: length of req_ies data + * @ap_mld_addr: AP MLD address (in case of MLO) + * @links: per-link information indexed by link ID, use links[0] for + * non-MLO connections */ struct cfg80211_rx_assoc_resp { - struct cfg80211_bss *bss; const u8 *buf; size_t len; const u8 *req_ies; size_t req_ies_len; int uapsd_queues; + const u8 *ap_mld_addr; + struct { + const u8 *addr; + struct cfg80211_bss *bss; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; }; /** diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ecbd70a1fbb7..29c1fe8b9f4a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3995,7 +3995,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, info.success = 1; } - resp.bss = cbss; + resp.links[0].bss = cbss; resp.buf = (u8 *)mgmt; resp.len = len; resp.req_ies = ifmgd->assoc_req_ies; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index a6ad696f131b..80f11a29cb86 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -28,28 +28,41 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)data->buf; - struct cfg80211_connect_resp_params cr; - const u8 *resp_ie = mgmt->u.assoc_resp.variable; - size_t resp_ie_len = data->len - offsetof(struct ieee80211_mgmt, - u.assoc_resp.variable); - - if (data->bss->channel->band == NL80211_BAND_S1GHZ) { - resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable; - resp_ie_len = data->len - offsetof(struct ieee80211_mgmt, - u.s1g_assoc_resp.variable); - } + struct cfg80211_connect_resp_params cr = { + .timeout_reason = NL80211_TIMEOUT_UNSPECIFIED, + .req_ie = data->req_ies, + .req_ie_len = data->req_ies_len, + .resp_ie = mgmt->u.assoc_resp.variable, + .resp_ie_len = data->len - + offsetof(struct ieee80211_mgmt, + u.assoc_resp.variable), + .status = le16_to_cpu(mgmt->u.assoc_resp.status_code), + .ap_mld_addr = data->ap_mld_addr, + }; + unsigned int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) { + cr.links[link_id].bss = data->links[link_id].bss; + if (!cr.links[link_id].bss) + continue; + cr.links[link_id].bssid = data->links[link_id].bss->bssid; + cr.links[link_id].addr = data->links[link_id].addr; + /* need to have local link addresses for MLO connections */ + WARN_ON(cr.ap_mld_addr && !cr.links[link_id].addr); + + if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) { + WARN_ON(link_id); + cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable; + cr.resp_ie_len = data->len - + offsetof(struct ieee80211_mgmt, + u.s1g_assoc_resp.variable); + } - memset(&cr, 0, sizeof(cr)); - cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); - cr.links[0].bssid = mgmt->bssid; - cr.links[0].bss = data->bss; - cr.req_ie = data->req_ies; - cr.req_ie_len = data->req_ies_len; - cr.resp_ie = resp_ie; - cr.resp_ie_len = resp_ie_len; - cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; + if (cr.ap_mld_addr) + cr.valid_links |= BIT(link_id); + } - trace_cfg80211_send_rx_assoc(dev, data->bss); + trace_cfg80211_send_rx_assoc(dev, data); /* * This is a bit of a hack, we don't notify userspace of @@ -58,8 +71,15 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, * frame instead of reassoc. */ if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) { - cfg80211_unhold_bss(bss_from_pub(data->bss)); - cfg80211_put_bss(wiphy, data->bss); + for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) { + struct cfg80211_bss *bss = data->links[link_id].bss; + + if (!bss) + continue; + + cfg80211_unhold_bss(bss_from_pub(bss)); + cfg80211_put_bss(wiphy, bss); + } return; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 94d107cab72c..dac66ad5937d 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2887,20 +2887,20 @@ DEFINE_EVENT(netdev_evt_only, cfg80211_send_rx_auth, ); TRACE_EVENT(cfg80211_send_rx_assoc, - TP_PROTO(struct net_device *netdev, struct cfg80211_bss *bss), - TP_ARGS(netdev, bss), + TP_PROTO(struct net_device *netdev, + struct cfg80211_rx_assoc_resp *data), + TP_ARGS(netdev, data), TP_STRUCT__entry( NETDEV_ENTRY - MAC_ENTRY(bssid) - CHAN_ENTRY + MAC_ENTRY(ap_addr) ), TP_fast_assign( NETDEV_ASSIGN; - MAC_ASSIGN(bssid, bss->bssid); - CHAN_ASSIGN(bss->channel); + MAC_ASSIGN(ap_addr, + data->ap_mld_addr ?: data->links[0].bss->bssid); ), - TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", " CHAN_PR_FMT, - NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) + TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, + NETDEV_PR_ARG, MAC_PR_ARG(ap_addr)) ); DECLARE_EVENT_CLASS(netdev_frame_event, -- cgit v1.2.3 From b327c84c328ed2be4dbad4f5ed7c17476fe1b3bf Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 29 Jun 2022 12:22:24 +0300 Subject: wifi: mac80211: replace link_id with link_conf in start/stop_ap() When calling start/stop_ap(), mac80211 already has a protected link_conf pointer. Pass it to the driver, so it shouldn't handle RCU protection. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 ++++++++-------- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 ++- drivers/net/wireless/realtek/rtw89/mac80211.c | 5 +++-- drivers/net/wireless/silabs/wfx/sta.c | 4 ++-- drivers/net/wireless/silabs/wfx/sta.h | 4 ++-- include/net/mac80211.h | 4 ++-- net/mac80211/cfg.c | 4 ++-- net/mac80211/driver-ops.h | 18 ++++++++++++------ net/mac80211/trace.h | 23 +++++++++-------------- net/mac80211/util.c | 3 ++- 10 files changed, 44 insertions(+), 40 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3de558f286a1..126106ea62d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2397,7 +2397,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2525,20 +2525,20 @@ out_unlock: static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { - return iwl_mvm_start_ap_ibss(hw, vif, link_id); + return iwl_mvm_start_ap_ibss(hw, vif, link_conf); } static int iwl_mvm_start_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - return iwl_mvm_start_ap_ibss(hw, vif, 0); + return iwl_mvm_start_ap_ibss(hw, vif, &vif->bss_conf); } static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2603,15 +2603,15 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { - iwl_mvm_stop_ap_ibss(hw, vif, link_id); + iwl_mvm_stop_ap_ibss(hw, vif, link_conf); } static void iwl_mvm_stop_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - iwl_mvm_stop_ap_ibss(hw, vif, 0); + iwl_mvm_stop_ap_ibss(hw, vif, &vif->bss_conf); } static void diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index bb7291665d37..c7b98a0599d5 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -430,7 +430,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, } static int rtw_ops_start_ap(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, unsigned int link_id) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct rtw_dev *rtwdev = hw->priv; struct rtw_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index f40569c8575c..cef27e781ae2 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -382,7 +382,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, } static int rtw89_ops_start_ap(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, unsigned int link_id) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; @@ -403,7 +404,7 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, static void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 89402afe4fe6..920bd1a4a1b1 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -380,7 +380,7 @@ static void wfx_set_mfp_ap(struct wfx_vif *wvif) } int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; struct wfx_dev *wdev = wvif->wdev; @@ -399,7 +399,7 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index 6558c5698cc8..bf2e76167a6f 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -30,9 +30,9 @@ void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id); + struct ieee80211_bss_conf *link_conf); void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id); + struct ieee80211_bss_conf *link_conf); int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 36eba96a1012..dcb8b6dac2e1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4092,9 +4092,9 @@ struct ieee80211_ops { u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id); + struct ieee80211_bss_conf *link_conf); void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id); + struct ieee80211_bss_conf *link_conf); u64 (*prepare_multicast)(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fa3b6cc2cafa..9214883eb0a8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1296,7 +1296,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP; } - err = drv_start_ap(sdata->local, sdata, link_id); + err = drv_start_ap(sdata->local, sdata, link_conf); if (err) { old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1457,7 +1457,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, GFP_KERNEL); } - drv_stop_ap(sdata->local, sdata, link_id); + drv_stop_ap(sdata->local, sdata, link_conf); /* free all potentially still buffered bcast frames */ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index eb16a354338c..a04a88d122b7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -987,32 +987,38 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, static inline int drv_start_ap(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { int ret = 0; + /* make sure link_conf is protected */ + sdata_assert_lock(sdata); + might_sleep(); if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_start_ap(local, sdata, link_id); + trace_drv_start_ap(local, sdata, link_conf); if (local->ops->start_ap) - ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id); + ret = local->ops->start_ap(&local->hw, &sdata->vif, link_conf); trace_drv_return_int(local, ret); return ret; } static inline void drv_stop_ap(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id) + struct ieee80211_bss_conf *link_conf) { + /* make sure link_conf is protected */ + sdata_assert_lock(sdata); + if (!check_sdata_in_driver(sdata)) return; - trace_drv_stop_ap(local, sdata, link_id); + trace_drv_stop_ap(local, sdata, link_conf); if (local->ops->stop_ap) - local->ops->stop_ap(&local->hw, &sdata->vif, link_id); + local->ops->stop_ap(&local->hw, &sdata->vif, link_conf); trace_drv_return_void(local); } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index b6f12ac91849..75e5c1376351 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1754,9 +1754,9 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TRACE_EVENT(drv_start_ap, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id), + struct ieee80211_bss_conf *link_conf), - TP_ARGS(local, sdata, link_id), + TP_ARGS(local, sdata, link_conf), TP_STRUCT__entry( LOCAL_ENTRY @@ -1769,17 +1769,12 @@ TRACE_EVENT(drv_start_ap, ), TP_fast_assign( - struct ieee80211_bss_conf *info = - sdata_dereference(sdata->vif.link_conf[link_id], sdata); - LOCAL_ASSIGN; VIF_ASSIGN; - __entry->link_id = link_id; - if (info) { - __entry->dtimper = info->dtim_period; - __entry->bcnint = info->beacon_int; - __entry->hidden_ssid = info->hidden_ssid; - } + __entry->link_id = link_conf->link_id; + __entry->dtimper = link_conf->dtim_period; + __entry->bcnint = link_conf->beacon_int; + __entry->hidden_ssid = link_conf->hidden_ssid; memcpy(__get_dynamic_array(ssid), sdata->vif.cfg.ssid, sdata->vif.cfg.ssid_len); @@ -1794,9 +1789,9 @@ TRACE_EVENT(drv_start_ap, TRACE_EVENT(drv_stop_ap, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id), + struct ieee80211_bss_conf *link_conf), - TP_ARGS(local, sdata, link_id), + TP_ARGS(local, sdata, link_conf), TP_STRUCT__entry( LOCAL_ENTRY @@ -1807,7 +1802,7 @@ TRACE_EVENT(drv_stop_ap, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - __entry->link_id = link_id; + __entry->link_id = link_conf->link_id; ), TP_printk( diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0ff09c639c50..cb0dd874c5df 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2579,7 +2579,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) changed |= BSS_CHANGED_AP_PROBE_RESP; if (rcu_access_pointer(sdata->deflink.u.ap.beacon)) - drv_start_ap(local, sdata, 0); + drv_start_ap(local, sdata, + sdata->deflink.conf); } fallthrough; case NL80211_IFTYPE_MESH_POINT: -- cgit v1.2.3 From 19654a61bfd66539087119fbceed46e48f084d89 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jul 2022 14:01:29 +0200 Subject: wifi: cfg80211: add ieee80211_chanwidth_rate_flags() To simplify things when we don't have a full chandef, add ieee80211_chanwidth_rate_flags(). Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2fe3eff11a8b..f9ea49e67164 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -939,19 +939,18 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, enum nl80211_iftype iftype); /** - * ieee80211_chandef_rate_flags - returns rate flags for a channel + * ieee80211_chanwidth_rate_flags - return rate flags for channel width + * @width: the channel width of the channel * * In some channel types, not all rates may be used - for example CCK * rates may not be used in 5/10 MHz channels. * - * @chandef: channel definition for the channel - * - * Returns: rate flags which apply for this channel + * Returns: rate flags which apply for this channel width */ static inline enum ieee80211_rate_flags -ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef) +ieee80211_chanwidth_rate_flags(enum nl80211_chan_width width) { - switch (chandef->width) { + switch (width) { case NL80211_CHAN_WIDTH_5: return IEEE80211_RATE_SUPPORTS_5MHZ; case NL80211_CHAN_WIDTH_10: @@ -962,6 +961,20 @@ ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef) return 0; } +/** + * ieee80211_chandef_rate_flags - returns rate flags for a channel + * @chandef: channel definition for the channel + * + * See ieee80211_chanwidth_rate_flags(). + * + * Returns: rate flags which apply for this channel + */ +static inline enum ieee80211_rate_flags +ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef) +{ + return ieee80211_chanwidth_rate_flags(chandef->width); +} + /** * ieee80211_chandef_max_power - maximum transmission power for the chandef * -- cgit v1.2.3 From 4e9c3af398207d95957ae6c25290891574f2d7e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Jul 2022 15:02:33 +0200 Subject: wifi: nl80211: add EML/MLD capabilities to per-iftype capabilities We have the per-interface type capabilities, currently for extended capabilities, add the EML/MLD capabilities there to have this advertised by the driver. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 12 ++++++++++-- net/wireless/nl80211.c | 9 +++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f9ea49e67164..bc960646973b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4993,12 +4993,16 @@ struct wiphy_vendor_command { * 802.11-2012 8.4.2.29 for the defined fields. * @extended_capabilities_mask: mask of the valid values * @extended_capabilities_len: length of the extended capabilities + * @eml_capabilities: EML capabilities (for MLO) + * @mld_capa_and_ops: MLD capabilities and operations (for MLO) */ struct wiphy_iftype_ext_capab { enum nl80211_iftype iftype; const u8 *extended_capabilities; const u8 *extended_capabilities_mask; u8 extended_capabilities_len; + u16 eml_capabilities; + u16 mld_capa_and_ops; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 37bfc934325a..3fa586e38f88 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2368,8 +2368,10 @@ enum nl80211_commands { * * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes: * %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA, - * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per - * interface type. + * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities and + * other interface-type specific capabilities per interface type. For MLO, + * %NL80211_ATTR_EML_CAPABILITY and %NL80211_ATTR_MLD_CAPA_AND_OPS are + * present. * * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO * groupID for monitor mode. @@ -2709,6 +2711,9 @@ enum nl80211_commands { * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum * number prior to the introduction of this attribute. * + * @NL80211_ATTR_EML_CAPABILITY: EML Capability information (u16) + * @NL80211_ATTR_MLD_CAPA_AND_OPS: MLD Capabilities and Operations (u16) + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3231,6 +3236,9 @@ enum nl80211_attrs { NL80211_ATTR_MAX_NUM_AKM_SUITES, + NL80211_ATTR_EML_CAPABILITY, + NL80211_ATTR_MLD_CAPA_AND_OPS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37ec8b3897b4..35fb2b0517d9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2867,6 +2867,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, capab->extended_capabilities_mask)) goto nla_put_failure; + if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO && + (nla_put_u16(msg, + NL80211_ATTR_EML_CAPABILITY, + capab->eml_capabilities) || + nla_put_u16(msg, + NL80211_ATTR_MLD_CAPA_AND_OPS, + capab->mld_capa_and_ops))) + goto nla_put_failure; + nla_nest_end(msg, nested_ext_capab); if (state->split) break; -- cgit v1.2.3 From 67207bab9341418698ae1029b28a44b58c39257e Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 30 Jun 2022 15:27:59 +0300 Subject: wifi: cfg80211/mac80211: Support control port TX from specific link In case of authentication with a legacy station, link addressed EAPOL frames should be sent. Support it. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/tx.c | 20 ++++++++++++++++++-- net/wireless/nl80211.c | 5 ++++- net/wireless/rdev-ops.h | 7 ++++--- net/wireless/trace.h | 11 +++++++---- 6 files changed, 35 insertions(+), 12 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bc960646973b..8dbc64286d91 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4580,7 +4580,7 @@ struct cfg80211_ops { struct net_device *dev, const u8 *buf, size_t len, const u8 *dest, const __be16 proto, - const bool noencrypt, + const bool noencrypt, int link_id, u64 *cookie); int (*get_ftm_responder_stats)(struct wiphy *wiphy, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d17d73e8d19f..58b08315fa26 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1946,7 +1946,7 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta); int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len, const u8 *dest, __be16 proto, bool unencrypted, - u64 *cookie); + int link_id, u64 *cookie); int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4a7a714de79e..8f25cfe0d543 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5674,7 +5674,7 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len, const u8 *dest, __be16 proto, bool unencrypted, - u64 *cookie) + int link_id, u64 *cookie) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; @@ -5714,7 +5714,23 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, ehdr = skb_push(skb, sizeof(struct ethhdr)); memcpy(ehdr->h_dest, dest, ETH_ALEN); - memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + + if (link_id < 0) { + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + } else { + struct ieee80211_bss_conf *link_conf; + + rcu_read_lock(); + link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); + if (!link_conf) { + dev_kfree_skb(skb); + rcu_read_unlock(); + return -ENOLINK; + } + memcpy(ehdr->h_source, link_conf->addr, ETH_ALEN); + rcu_read_unlock(); + } + ehdr->h_proto = proto; skb->dev = dev; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 35fcf36bbaad..53d63effbca9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15223,6 +15223,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) u16 proto; bool noencrypt; u64 cookie = 0; + int link_id; int err; if (!wiphy_ext_feature_isset(&rdev->wiphy, @@ -15271,8 +15272,10 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) noencrypt = nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); + link_id = nl80211_link_id_or_invalid(info->attrs); + err = rdev_tx_control_port(rdev, dev, buf, len, - dest, cpu_to_be16(proto), noencrypt, + dest, cpu_to_be16(proto), noencrypt, link_id, dont_wait_for_ack ? NULL : &cookie); if (!err && !dont_wait_for_ack) nl_set_extack_cookie_u64(info->extack, cookie); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 53f5a0126dfd..40915a82da73 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -746,13 +746,14 @@ static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev, struct net_device *dev, const void *buf, size_t len, const u8 *dest, __be16 proto, - const bool noencrypt, u64 *cookie) + const bool noencrypt, int link, + u64 *cookie) { int ret; trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len, - dest, proto, noencrypt); + dest, proto, noencrypt, link); ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len, - dest, proto, noencrypt, cookie); + dest, proto, noencrypt, link, cookie); if (cookie) trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); else diff --git a/net/wireless/trace.h b/net/wireless/trace.h index dac66ad5937d..592b9e9e821a 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2015,14 +2015,15 @@ TRACE_EVENT(rdev_mgmt_tx, TRACE_EVENT(rdev_tx_control_port, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *buf, size_t len, const u8 *dest, __be16 proto, - bool unencrypted), - TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted), + bool unencrypted, int link_id), + TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted, link_id), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY MAC_ENTRY(dest) __field(__be16, proto) __field(bool, unencrypted) + __field(int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; @@ -2030,12 +2031,14 @@ TRACE_EVENT(rdev_tx_control_port, MAC_ASSIGN(dest, dest); __entry->proto = proto; __entry->unencrypted = unencrypted; + __entry->link_id = link_id; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT "," - " proto: 0x%x, unencrypted: %s", + " proto: 0x%x, unencrypted: %s, link: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest), be16_to_cpu(__entry->proto), - BOOL_TO_STR(__entry->unencrypted)) + BOOL_TO_STR(__entry->unencrypted), + __entry->link_id) ); TRACE_EVENT(rdev_set_noack_map, -- cgit v1.2.3 From 727eff4dd198d79f9e81d3aafbab741a8374b5d0 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Sun, 3 Jul 2022 18:04:15 +0300 Subject: wifi: mac80211: replace link_id with link_conf in switch/(un)assign_vif_chanctx() Since mac80211 already has a protected pointer to link_conf, pass it to the driver to avoid additional RCU locking. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++-- drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- drivers/net/wireless/silabs/wfx/sta.c | 4 ++-- drivers/net/wireless/silabs/wfx/sta.h | 4 ++-- drivers/net/wireless/ti/wlcore/main.c | 4 ++-- include/net/mac80211.h | 8 +++---- net/mac80211/chan.c | 9 ++++---- net/mac80211/driver-ops.h | 26 ++++++++++++++++------- net/mac80211/trace.h | 16 +++++++------- net/mac80211/util.c | 2 +- 13 files changed, 51 insertions(+), 42 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ac54396418c9..9dd3b8fba4b0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8920,7 +8920,7 @@ unlock: static int ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; @@ -9000,7 +9000,7 @@ err: static void ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index ec7b3a3629f3..92e17d3c634e 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7073,7 +7073,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; @@ -7163,7 +7163,7 @@ out: static void ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d2c20c332c7a..a4197c14f0a9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2597,7 +2597,7 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw, static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; @@ -2629,7 +2629,7 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 126106ea62d3..5eb28f8ee87e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4264,7 +4264,7 @@ out: } static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4338,7 +4338,7 @@ out: static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5da7a097d518..7d573e90ad81 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2794,7 +2794,7 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); @@ -2805,7 +2805,7 @@ static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 920bd1a4a1b1..626dfb4b7a55 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -683,7 +683,7 @@ void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf * } int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; @@ -696,7 +696,7 @@ int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index bf2e76167a6f..888db5cd3206 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -51,10 +51,10 @@ int wfx_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf void wfx_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf); void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, u32 changed); int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf); void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *conf); /* Hardware API Callbacks */ diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1edec9f3c0d8..3e3922d4c788 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4701,7 +4701,7 @@ out: static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; @@ -4752,7 +4752,7 @@ out: static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dcb8b6dac2e1..e4ead73c5c43 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -261,13 +261,13 @@ enum ieee80211_chanctx_switch_mode { * done. * * @vif: the vif that should be switched from old_ctx to new_ctx - * @link_id: the link ID that's switching + * @link_conf: the link conf that's switching * @old_ctx: the old context to which the vif was assigned * @new_ctx: the new context to which the vif must be assigned */ struct ieee80211_vif_chanctx_switch { struct ieee80211_vif *vif; - unsigned int link_id; + struct ieee80211_bss_conf *link_conf; struct ieee80211_chanctx_conf *old_ctx; struct ieee80211_chanctx_conf *new_ctx; }; @@ -4297,11 +4297,11 @@ struct ieee80211_ops { u32 changed); int (*assign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); int (*switch_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 2e9bc285f0a5..f247daa41563 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -835,7 +835,6 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, struct ieee80211_chanctx *new_ctx) { struct ieee80211_sub_if_data *sdata = link->sdata; - unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *curr_ctx = NULL; @@ -850,13 +849,13 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, if (conf) { curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_unassign_vif_chanctx(local, sdata, link_id, curr_ctx); + drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx); conf = NULL; list_del(&link->assigned_chanctx_list); } if (new_ctx) { - ret = drv_assign_vif_chanctx(local, sdata, link_id, new_ctx); + ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx); if (ret) goto out; @@ -1276,7 +1275,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) vif_chsw[0].vif = &sdata->vif; vif_chsw[0].old_ctx = &old_ctx->conf; vif_chsw[0].new_ctx = &new_ctx->conf; - vif_chsw[0].link_id = link->link_id; + vif_chsw[0].link_conf = link->conf; list_del(&link->reserved_chanctx_list); link->reserved_chanctx = NULL; @@ -1440,7 +1439,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, vif_chsw[i].vif = &link->sdata->vif; vif_chsw[i].old_ctx = &old_ctx->conf; vif_chsw[i].new_ctx = &ctx->conf; - vif_chsw[i].link_id = link->link_id; + vif_chsw[i].link_conf = link->conf; i++; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index a04a88d122b7..0f06081c68ca 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -937,22 +937,31 @@ static inline void drv_change_chanctx(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss_conf *link_conf) +{ + /* deflink always exists, so need to check only for other links */ + if (sdata->deflink.conf != link_conf) + sdata_assert_lock(sdata); +} + static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx *ctx) { int ret = 0; + drv_verify_link_exists(sdata, link_conf); if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_assign_vif_chanctx(local, sdata, link_id, ctx); + trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx); if (local->ops->assign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); ret = local->ops->assign_vif_chanctx(&local->hw, &sdata->vif, - link_id, + link_conf, &ctx->conf); } trace_drv_return_int(local, ret); @@ -962,20 +971,21 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx *ctx) { might_sleep(); + drv_verify_link_exists(sdata, link_conf); if (!check_sdata_in_driver(sdata)) return; - trace_drv_unassign_vif_chanctx(local, sdata, link_id, ctx); + trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx); if (local->ops->unassign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); local->ops->unassign_vif_chanctx(&local->hw, &sdata->vif, - link_id, + link_conf, &ctx->conf); } trace_drv_return_void(local); @@ -992,7 +1002,7 @@ static inline int drv_start_ap(struct ieee80211_local *local, int ret = 0; /* make sure link_conf is protected */ - sdata_assert_lock(sdata); + drv_verify_link_exists(sdata, link_conf); might_sleep(); @@ -1011,7 +1021,7 @@ static inline void drv_stop_ap(struct ieee80211_local *local, struct ieee80211_bss_conf *link_conf) { /* make sure link_conf is protected */ - sdata_assert_lock(sdata); + drv_verify_link_exists(sdata, link_conf); if (!check_sdata_in_driver(sdata)) return; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 75e5c1376351..402110f439f8 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1669,7 +1669,7 @@ TRACE_EVENT(drv_switch_vif_chanctx, SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); - SWITCH_ENTRY_ASSIGN(link_id, link_id); + SWITCH_ENTRY_ASSIGN(link_id, link_conf->link_id); strncpy(local_vifs[i].vif.vif_name, sdata->name, sizeof(local_vifs[i].vif.vif_name)); @@ -1710,10 +1710,10 @@ TRACE_EVENT(drv_switch_vif_chanctx, DECLARE_EVENT_CLASS(local_sdata_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, link_id, ctx), + TP_ARGS(local, sdata, link_conf, ctx), TP_STRUCT__entry( LOCAL_ENTRY @@ -1726,7 +1726,7 @@ DECLARE_EVENT_CLASS(local_sdata_chanctx, LOCAL_ASSIGN; VIF_ASSIGN; CHANCTX_ASSIGN; - __entry->link_id = link_id; + __entry->link_id = link_conf->link_id; ), TP_printk( @@ -1738,17 +1738,17 @@ DECLARE_EVENT_CLASS(local_sdata_chanctx, DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, link_id, ctx) + TP_ARGS(local, sdata, link_conf, ctx) ); DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, link_id, ctx) + TP_ARGS(local, sdata, link_conf, ctx) ); TRACE_EVENT(drv_start_ap, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 739c05fdb9bb..8cb93d65b80e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2270,7 +2270,7 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_assign_vif_chanctx(local, sdata, link->link_id, ctx); + drv_assign_vif_chanctx(local, sdata, link->conf, ctx); } mutex_unlock(&local->chanctx_mtx); } -- cgit v1.2.3 From 7840bd468a99edac26492afa828b8fcbbbb2384e Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 4 Jul 2022 00:38:22 +0300 Subject: wifi: mac80211: remove link_id parameter from link_info_changed() Since struct ieee80211_bss_conf already contains link_id, passing link_id is not necessary. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- include/net/mac80211.h | 1 - net/mac80211/driver-ops.h | 4 ++-- net/mac80211/main.c | 5 ++--- net/mac80211/trace.h | 6 +++--- 5 files changed, 9 insertions(+), 10 deletions(-) (limited to 'include/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7d573e90ad81..5418c4973501 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2178,10 +2178,11 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 link_id, u64 changed) + u64 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct mac80211_hwsim_data *data = hw->priv; + unsigned int link_id = info->link_id; struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; hwsim_check_magic(vif); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e4ead73c5c43..6fc4253b5644 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4088,7 +4088,6 @@ struct ieee80211_ops { void (*link_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - unsigned int link_id, u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 0f06081c68ca..482f5c97a72b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -190,10 +190,10 @@ static inline void drv_link_info_changed(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_link_info_changed(local, sdata, info, link_id, changed); + trace_drv_link_info_changed(local, sdata, info, changed); if (local->ops->link_info_changed) local->ops->link_info_changed(&local->hw, &sdata->vif, - info, link_id, changed); + info, changed); else if (local->ops->bss_info_changed) local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8d5b18318b20..26bb30606282 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -248,11 +248,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, /* FIXME: should be for each link */ trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf, - 0, changed); + changed); if (local->ops->link_info_changed) local->ops->link_info_changed(&local->hw, &sdata->vif, - &sdata->vif.bss_conf, - 0, ch); + &sdata->vif.bss_conf, ch); } if (local->ops->bss_info_changed) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 402110f439f8..9f4377566c42 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -449,9 +449,9 @@ TRACE_EVENT(drv_link_info_changed, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *link_conf, - int link_id, u64 changed), + u64 changed), - TP_ARGS(local, sdata, link_conf, link_id, changed), + TP_ARGS(local, sdata, link_conf, changed), TP_STRUCT__entry( LOCAL_ENTRY @@ -486,7 +486,7 @@ TRACE_EVENT(drv_link_info_changed, LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; - __entry->link_id = link_id; + __entry->link_id = link_conf->link_id; __entry->shortpre = link_conf->use_short_preamble; __entry->cts = link_conf->use_cts_prot; __entry->shortslot = link_conf->use_short_slot; -- cgit v1.2.3 From 7464f665158e09f3f29116d8d0676824c1f1eeda Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 18:32:49 +0200 Subject: wifi: cfg80211: add cfg80211_get_iftype_ext_capa() Add a helper function cfg80211_get_iftype_ext_capa() to look up interface type-specific (extended) capabilities. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 ++++++++ net/wireless/util.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8dbc64286d91..d5af3a7fc2b4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5005,6 +5005,14 @@ struct wiphy_iftype_ext_capab { u16 mld_capa_and_ops; }; +/** + * cfg80211_get_iftype_ext_capa - lookup interface type extended capability + * @wiphy: the wiphy to look up from + * @type: the interface type to look up + */ +const struct wiphy_iftype_ext_capab * +cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type); + /** * struct cfg80211_pmsr_capabilities - cfg80211 peer measurement capabilities * @max_peers: maximum number of peers in a single measurement diff --git a/net/wireless/util.c b/net/wireless/util.c index fe7956c8c6da..2c127951764a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2490,3 +2490,17 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, return rdev_del_virtual_intf(rdev, wdev); } + +const struct wiphy_iftype_ext_capab * +cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type) +{ + int i; + + for (i = 0; i < wiphy->num_iftype_ext_capab; i++) { + if (wiphy->iftype_ext_capab[i].iftype == type) + return &wiphy->iftype_ext_capab[i]; + } + + return NULL; +} +EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa); -- cgit v1.2.3 From 3e0278b717b077f9ccf0280580ce6c5eb9c4dbac Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 13 Jul 2022 12:05:27 +0300 Subject: wifi: mac80211: select link when transmitting to non-MLO stations When an MLO AP is transmitting to a non-MLO station, addr2 should be set to a link address. This should be done before the frame is encrypted as otherwise aad verification would fail. In case of software encryption this can't be left for the device to handle, and should be done by mac80211 when building the frame hdr. Signed-off-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/cfg.c | 4 ++++ net/mac80211/tx.c | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6fc4253b5644..6f856da28d71 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2147,6 +2147,7 @@ struct ieee80211_link_sta { * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only * valid if the STA is a TDLS peer in the first place. * @mfp: indicates whether the STA uses management frame protection or not. + * @mlo: indicates whether the STA is MLO station. * @max_amsdu_subframes: indicates the maximal number of MSDUs in a single * A-MSDU. Taken from the Extended Capabilities element. 0 means * unlimited. @@ -2180,6 +2181,7 @@ struct ieee80211_sta { bool tdls; bool tdls_initiator; bool mfp; + bool mlo; u8 max_amsdu_subframes; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1cacd1e0fc85..fe6500b36953 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1818,6 +1818,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, return ret; } + /* Mark the STA as MLO if MLD MAC address is available */ + if (params->link_sta_params.mld_mac) + sta->sta.mlo = true; + return 0; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5dd29288c009..1d60eab8308a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2570,6 +2570,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; + u8 link_id = IEEE80211_LINK_UNSPECIFIED; if (IS_ERR(sta)) sta = NULL; @@ -2618,7 +2619,21 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + + if (sdata->vif.valid_links && sta && !sta->sta.mlo) { + struct ieee80211_link_data *link; + + link_id = sta->deflink.link_id; + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) { + ret = -ENOLINK; + goto free; + } + memcpy(hdr.addr2, link->conf->addr, ETH_ALEN); + } else { + memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + } + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; break; @@ -2882,7 +2897,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, info->ack_frame_id = info_id; info->band = band; info->control.flags = ctrl_flags | - u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); return skb; -- cgit v1.2.3 From 4bc5008e4387106215b50ae1a4ac2467455725ca Mon Sep 17 00:00:00 2001 From: Wen Gu Date: Thu, 14 Jul 2022 17:44:02 +0800 Subject: net/smc: Introduce a sysctl for setting SMC-R buffer type This patch introduces the sysctl smcr_buf_type for setting the type of SMC-R sndbufs and RMBs. Valid values includes: - SMCR_PHYS_CONT_BUFS, which means use physically contiguous buffers for better performance and is the default value. - SMCR_VIRT_CONT_BUFS, which means use virtually contiguous buffers in case of physically contiguous memory is scarce. - SMCR_MIXED_BUFS, which means first try to use physically contiguous buffers. If not available, then use virtually contiguous buffers. Signed-off-by: Wen Gu Signed-off-by: David S. Miller --- Documentation/networking/smc-sysctl.rst | 13 +++++++++++++ include/net/netns/smc.h | 1 + net/smc/smc_core.h | 6 ++++++ net/smc/smc_sysctl.c | 11 +++++++++++ 4 files changed, 31 insertions(+) (limited to 'include/net') diff --git a/Documentation/networking/smc-sysctl.rst b/Documentation/networking/smc-sysctl.rst index 0987fd1bc220..742e90e6d822 100644 --- a/Documentation/networking/smc-sysctl.rst +++ b/Documentation/networking/smc-sysctl.rst @@ -21,3 +21,16 @@ autocorking_size - INTEGER know how/when to uncork their sockets. Default: 64K + +smcr_buf_type - INTEGER + Controls which type of sndbufs and RMBs to use in later newly created + SMC-R link group. Only for SMC-R. + + Default: 0 (physically contiguous sndbufs and RMBs) + + Possible values: + + - 0 - Use physically contiguous buffers + - 1 - Use virtually contiguous buffers + - 2 - Mixed use of the two types. Try physically contiguous buffers first. + If not available, use virtually contiguous buffers then. diff --git a/include/net/netns/smc.h b/include/net/netns/smc.h index e5389eeaf8bd..2adbe2b245df 100644 --- a/include/net/netns/smc.h +++ b/include/net/netns/smc.h @@ -18,5 +18,6 @@ struct netns_smc { struct ctl_table_header *smc_hdr; #endif unsigned int sysctl_autocorking_size; + unsigned int sysctl_smcr_buf_type; }; #endif diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 46ddec5f1edc..7652dfa783ff 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -217,6 +217,12 @@ enum smc_lgr_type { /* redundancy state of lgr */ SMC_LGR_ASYMMETRIC_LOCAL, /* local has 1, peer 2 active RNICs */ }; +enum smcr_buf_type { /* types of SMC-R sndbufs and RMBs */ + SMCR_PHYS_CONT_BUFS = 0, + SMCR_VIRT_CONT_BUFS = 1, + SMCR_MIXED_BUFS = 2, +}; + enum smc_llc_flowtype { SMC_LLC_FLOW_NONE = 0, SMC_LLC_FLOW_ADD_LINK = 2, diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c index cf3ab1334c00..0613868fdb97 100644 --- a/net/smc/smc_sysctl.c +++ b/net/smc/smc_sysctl.c @@ -15,6 +15,7 @@ #include #include "smc.h" +#include "smc_core.h" #include "smc_sysctl.h" static struct ctl_table smc_table[] = { @@ -25,6 +26,15 @@ static struct ctl_table smc_table[] = { .mode = 0644, .proc_handler = proc_douintvec, }, + { + .procname = "smcr_buf_type", + .data = &init_net.smc.sysctl_smcr_buf_type, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_TWO, + }, { } }; @@ -49,6 +59,7 @@ int __net_init smc_sysctl_net_init(struct net *net) goto err_reg; net->smc.sysctl_autocorking_size = SMC_AUTOCORKING_DEFAULT_SIZE; + net->smc.sysctl_smcr_buf_type = SMCR_PHYS_CONT_BUFS; return 0; -- cgit v1.2.3 From 4cbc325ed6b4dce4910be06d9d6940a8b919c59b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Jul 2022 22:22:25 -0700 Subject: tls: rx: allow only one reader at a time recvmsg() in TLS gets data from the skb list (rx_list) or fresh skbs we read from TCP via strparser. The former holds skbs which were already decrypted for peek or decrypted and partially consumed. tls_wait_data() only notices appearance of fresh skbs coming out of TCP (or psock). It is possible, if there is a concurrent call to peek() and recv() that the peek() will move the data from input to rx_list without recv() noticing. recv() will then read data out of order or never wake up. This is not a practical use case/concern, but it makes the self tests less reliable. This patch solves the problem by allowing only one reader in. Because having multiple processes calling read()/peek() is not normal avoid adding a lock and try to fast-path the single reader case. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/net/tls.h | 3 +++ net/tls/tls_sw.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 7 deletions(-) (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index 8742e13bc362..e8935cfe0cd6 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -116,11 +116,14 @@ struct tls_sw_context_rx { void (*saved_data_ready)(struct sock *sk); struct sk_buff *recv_pkt; + u8 reader_present; u8 async_capable:1; u8 zc_capable:1; + u8 reader_contended:1; atomic_t decrypt_pending; /* protect crypto_wait with decrypt_pending*/ spinlock_t decrypt_compl_lock; + struct wait_queue_head wq; }; struct tls_record_info { diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 68d79ee48a56..761a63751616 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1753,6 +1753,51 @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot, sk_flush_backlog(sk); } +static long tls_rx_reader_lock(struct sock *sk, struct tls_sw_context_rx *ctx, + bool nonblock) +{ + long timeo; + + lock_sock(sk); + + timeo = sock_rcvtimeo(sk, nonblock); + + while (unlikely(ctx->reader_present)) { + DEFINE_WAIT_FUNC(wait, woken_wake_function); + + ctx->reader_contended = 1; + + add_wait_queue(&ctx->wq, &wait); + sk_wait_event(sk, &timeo, + !READ_ONCE(ctx->reader_present), &wait); + remove_wait_queue(&ctx->wq, &wait); + + if (!timeo) + return -EAGAIN; + if (signal_pending(current)) + return sock_intr_errno(timeo); + } + + WRITE_ONCE(ctx->reader_present, 1); + + return timeo; +} + +static void tls_rx_reader_unlock(struct sock *sk, struct tls_sw_context_rx *ctx) +{ + if (unlikely(ctx->reader_contended)) { + if (wq_has_sleeper(&ctx->wq)) + wake_up(&ctx->wq); + else + ctx->reader_contended = 0; + + WARN_ON_ONCE(!ctx->reader_present); + } + + WRITE_ONCE(ctx->reader_present, 0); + release_sock(sk); +} + int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, @@ -1782,7 +1827,9 @@ int tls_sw_recvmsg(struct sock *sk, return sock_recv_errqueue(sk, msg, len, SOL_IP, IP_RECVERR); psock = sk_psock_get(sk); - lock_sock(sk); + timeo = tls_rx_reader_lock(sk, ctx, flags & MSG_DONTWAIT); + if (timeo < 0) + return timeo; bpf_strp_enabled = sk_psock_strp_enabled(psock); /* If crypto failed the connection is broken */ @@ -1801,7 +1848,6 @@ int tls_sw_recvmsg(struct sock *sk, target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); len = len - copied; - timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); zc_capable = !bpf_strp_enabled && !is_kvec && !is_peek && ctx->zc_capable; @@ -1956,7 +2002,7 @@ recv_end: copied += decrypted; end: - release_sock(sk); + tls_rx_reader_unlock(sk, ctx); if (psock) sk_psock_put(sk, psock); return copied ? : err; @@ -1978,9 +2024,9 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, long timeo; int chunk; - lock_sock(sk); - - timeo = sock_rcvtimeo(sk, flags & SPLICE_F_NONBLOCK); + timeo = tls_rx_reader_lock(sk, ctx, flags & SPLICE_F_NONBLOCK); + if (timeo < 0) + return timeo; from_queue = !skb_queue_empty(&ctx->rx_list); if (from_queue) { @@ -2029,7 +2075,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, } splice_read_end: - release_sock(sk); + tls_rx_reader_unlock(sk, ctx); return copied ? : err; } @@ -2371,6 +2417,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) } else { crypto_init_wait(&sw_ctx_rx->async_wait); spin_lock_init(&sw_ctx_rx->decrypt_compl_lock); + init_waitqueue_head(&sw_ctx_rx->wq); crypto_info = &ctx->crypto_recv.info; cctx = &ctx->rx; skb_queue_head_init(&sw_ctx_rx->rx_list); -- cgit v1.2.3 From 53d57999fe02785040bc53e2f12efc881f13ae17 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Jul 2022 22:22:28 -0700 Subject: tls: rx: remove the message decrypted tracking We no longer allow a decrypted skb to remain linked to ctx->recv_pkt. Anything on the list is decrypted, anything on ctx->recv_pkt needs to be decrypted. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/net/strparser.h | 1 - net/tls/tls_sw.c | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'include/net') diff --git a/include/net/strparser.h b/include/net/strparser.h index 88900b05443e..41e2ce9e9e10 100644 --- a/include/net/strparser.h +++ b/include/net/strparser.h @@ -72,7 +72,6 @@ struct sk_skb_cb { /* strp users' data follows */ struct tls_msg { u8 control; - u8 decrypted; } tls; /* temp_reg is a temporary register used for bpf_convert_data_end_access * when dst_reg == src_reg. diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index f5f06d1ba024..49cfaa8119c6 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1563,21 +1563,13 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb, struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_prot_info *prot = &tls_ctx->prot_info; struct strp_msg *rxm = strp_msg(skb); - struct tls_msg *tlm = tls_msg(skb); int pad, err; - if (tlm->decrypted) { - darg->zc = false; - darg->async = false; - return 0; - } - if (tls_ctx->rx_conf == TLS_HW) { err = tls_device_decrypted(sk, tls_ctx, skb, rxm); if (err < 0) return err; if (err > 0) { - tlm->decrypted = 1; darg->zc = false; darg->async = false; goto decrypt_done; @@ -1610,7 +1602,6 @@ decrypt_done: rxm->full_len -= pad; rxm->offset += prot->prepend_size; rxm->full_len -= prot->overhead_size; - tlm->decrypted = 1; decrypt_next: tls_advance_record_sn(sk, prot, &tls_ctx->rx); @@ -2130,7 +2121,6 @@ static int tls_read_size(struct strparser *strp, struct sk_buff *skb) if (ret < 0) goto read_failure; - tlm->decrypted = 0; tlm->control = header[0]; data_len = ((header[4] & 0xFF) | (header[3] << 8)); -- cgit v1.2.3 From c618db2afe7c31d13ca8cf05b60f17165fbdc282 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Jul 2022 22:22:33 -0700 Subject: tls: rx: async: hold onto the input skb Async crypto currently benefits from the fact that we decrypt in place. When we allow input and output to be different skbs we will have to hang onto the input while we move to the next record. Clone the inputs and keep them on a list. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/net/tls.h | 1 + net/tls/Makefile | 2 +- net/tls/tls.h | 3 +++ net/tls/tls_strp.c | 17 +++++++++++++++++ net/tls/tls_sw.c | 26 +++++++++++++++++--------- 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 net/tls/tls_strp.c (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index e8935cfe0cd6..181c496b01b8 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -123,6 +123,7 @@ struct tls_sw_context_rx { atomic_t decrypt_pending; /* protect crypto_wait with decrypt_pending*/ spinlock_t decrypt_compl_lock; + struct sk_buff_head async_hold; struct wait_queue_head wq; }; diff --git a/net/tls/Makefile b/net/tls/Makefile index f1ffbfe8968d..e41c800489ac 100644 --- a/net/tls/Makefile +++ b/net/tls/Makefile @@ -7,7 +7,7 @@ CFLAGS_trace.o := -I$(src) obj-$(CONFIG_TLS) += tls.o -tls-y := tls_main.o tls_sw.o tls_proc.o trace.o +tls-y := tls_main.o tls_sw.o tls_proc.o trace.o tls_strp.o tls-$(CONFIG_TLS_TOE) += tls_toe.o tls-$(CONFIG_TLS_DEVICE) += tls_device.o tls_device_fallback.o diff --git a/net/tls/tls.h b/net/tls/tls.h index 44522b221717..c818dc68955d 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -124,6 +124,9 @@ int tls_sw_fallback_init(struct sock *sk, struct tls_offload_context_tx *offload_ctx, struct tls_crypto_info *crypto_info); +int tls_strp_msg_hold(struct sock *sk, struct sk_buff *skb, + struct sk_buff_head *dst); + static inline struct tls_msg *tls_msg(struct sk_buff *skb) { struct sk_skb_cb *scb = (struct sk_skb_cb *)skb->cb; diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c new file mode 100644 index 000000000000..9ccab79a6e1e --- /dev/null +++ b/net/tls/tls_strp.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include "tls.h" + +int tls_strp_msg_hold(struct sock *sk, struct sk_buff *skb, + struct sk_buff_head *dst) +{ + struct sk_buff *clone; + + clone = skb_clone(skb, sk->sk_allocation); + if (!clone) + return -ENOMEM; + __skb_queue_tail(dst, clone); + return 0; +} diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 09fe2cfff51a..f767501e178d 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1535,8 +1535,13 @@ fallback_to_reg_recv: goto exit_free_pages; darg->skb = tls_strp_msg(ctx); - if (darg->async) - return 0; + + if (unlikely(darg->async)) { + err = tls_strp_msg_hold(sk, skb, &ctx->async_hold); + if (err) + __skb_queue_tail(&ctx->async_hold, darg->skb); + return err; + } if (prot->tail_size) darg->tail = dctx->tail; @@ -1998,14 +2003,16 @@ recv_end: reinit_completion(&ctx->async_wait.completion); pending = atomic_read(&ctx->decrypt_pending); spin_unlock_bh(&ctx->decrypt_compl_lock); - if (pending) { + ret = 0; + if (pending) ret = crypto_wait_req(-EINPROGRESS, &ctx->async_wait); - if (ret) { - if (err >= 0 || err == -EINPROGRESS) - err = ret; - decrypted = 0; - goto end; - } + __skb_queue_purge(&ctx->async_hold); + + if (ret) { + if (err >= 0 || err == -EINPROGRESS) + err = ret; + decrypted = 0; + goto end; } /* Drain records from the rx_list & copy if required */ @@ -2440,6 +2447,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) crypto_info = &ctx->crypto_recv.info; cctx = &ctx->rx; skb_queue_head_init(&sw_ctx_rx->rx_list); + skb_queue_head_init(&sw_ctx_rx->async_hold); aead = &sw_ctx_rx->aead_recv; } -- cgit v1.2.3 From 852e85a704c2e11c050bdea286bc438aba4f4a22 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:34 +0200 Subject: net: devlink: add unlocked variants of devling_trap*() functions Add unlocked variants of devl_trap*() functions to be used in drivers called-in with devlink->lock held. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 20 ++++++ net/core/devlink.c | 180 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 168 insertions(+), 32 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 88c701b375a2..fb1e17d998b6 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1745,9 +1745,15 @@ void devlink_flash_update_timeout_notify(struct devlink *devlink, const char *component, unsigned long timeout); +int devl_traps_register(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count, void *priv); int devlink_traps_register(struct devlink *devlink, const struct devlink_trap *traps, size_t traps_count, void *priv); +void devl_traps_unregister(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count); void devlink_traps_unregister(struct devlink *devlink, const struct devlink_trap *traps, size_t traps_count); @@ -1755,17 +1761,31 @@ void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb, void *trap_ctx, struct devlink_port *in_devlink_port, const struct flow_action_cookie *fa_cookie); void *devlink_trap_ctx_priv(void *trap_ctx); +int devl_trap_groups_register(struct devlink *devlink, + const struct devlink_trap_group *groups, + size_t groups_count); int devlink_trap_groups_register(struct devlink *devlink, const struct devlink_trap_group *groups, size_t groups_count); +void devl_trap_groups_unregister(struct devlink *devlink, + const struct devlink_trap_group *groups, + size_t groups_count); void devlink_trap_groups_unregister(struct devlink *devlink, const struct devlink_trap_group *groups, size_t groups_count); int +devl_trap_policers_register(struct devlink *devlink, + const struct devlink_trap_policer *policers, + size_t policers_count); +int devlink_trap_policers_register(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count); void +devl_trap_policers_unregister(struct devlink *devlink, + const struct devlink_trap_policer *policers, + size_t policers_count); +void devlink_trap_policers_unregister(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count); diff --git a/net/core/devlink.c b/net/core/devlink.c index d2a4e6ee1be6..b0f6e8388880 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -11544,7 +11544,7 @@ static void devlink_trap_disable(struct devlink *devlink, } /** - * devlink_traps_register - Register packet traps with devlink. + * devl_traps_register - Register packet traps with devlink. * @devlink: devlink. * @traps: Packet traps. * @traps_count: Count of provided packet traps. @@ -11552,16 +11552,16 @@ static void devlink_trap_disable(struct devlink *devlink, * * Return: Non-zero value on failure. */ -int devlink_traps_register(struct devlink *devlink, - const struct devlink_trap *traps, - size_t traps_count, void *priv) +int devl_traps_register(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count, void *priv) { int i, err; if (!devlink->ops->trap_init || !devlink->ops->trap_action_set) return -EINVAL; - devl_lock(devlink); + devl_assert_locked(devlink); for (i = 0; i < traps_count; i++) { const struct devlink_trap *trap = &traps[i]; @@ -11573,7 +11573,6 @@ int devlink_traps_register(struct devlink *devlink, if (err) goto err_trap_register; } - devl_unlock(devlink); return 0; @@ -11581,24 +11580,47 @@ err_trap_register: err_trap_verify: for (i--; i >= 0; i--) devlink_trap_unregister(devlink, &traps[i]); + return err; +} +EXPORT_SYMBOL_GPL(devl_traps_register); + +/** + * devlink_traps_register - Register packet traps with devlink. + * @devlink: devlink. + * @traps: Packet traps. + * @traps_count: Count of provided packet traps. + * @priv: Driver private information. + * + * Context: Takes and release devlink->lock . + * + * Return: Non-zero value on failure. + */ +int devlink_traps_register(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count, void *priv) +{ + int err; + + devl_lock(devlink); + err = devl_traps_register(devlink, traps, traps_count, priv); devl_unlock(devlink); return err; } EXPORT_SYMBOL_GPL(devlink_traps_register); /** - * devlink_traps_unregister - Unregister packet traps from devlink. + * devl_traps_unregister - Unregister packet traps from devlink. * @devlink: devlink. * @traps: Packet traps. * @traps_count: Count of provided packet traps. */ -void devlink_traps_unregister(struct devlink *devlink, - const struct devlink_trap *traps, - size_t traps_count) +void devl_traps_unregister(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count) { int i; - devl_lock(devlink); + devl_assert_locked(devlink); /* Make sure we do not have any packets in-flight while unregistering * traps by disabling all of them and waiting for a grace period. */ @@ -11607,6 +11629,23 @@ void devlink_traps_unregister(struct devlink *devlink, synchronize_rcu(); for (i = traps_count - 1; i >= 0; i--) devlink_trap_unregister(devlink, &traps[i]); +} +EXPORT_SYMBOL_GPL(devl_traps_unregister); + +/** + * devlink_traps_unregister - Unregister packet traps from devlink. + * @devlink: devlink. + * @traps: Packet traps. + * @traps_count: Count of provided packet traps. + * + * Context: Takes and release devlink->lock . + */ +void devlink_traps_unregister(struct devlink *devlink, + const struct devlink_trap *traps, + size_t traps_count) +{ + devl_lock(devlink); + devl_traps_unregister(devlink, traps, traps_count); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_traps_unregister); @@ -11766,20 +11805,20 @@ devlink_trap_group_unregister(struct devlink *devlink, } /** - * devlink_trap_groups_register - Register packet trap groups with devlink. + * devl_trap_groups_register - Register packet trap groups with devlink. * @devlink: devlink. * @groups: Packet trap groups. * @groups_count: Count of provided packet trap groups. * * Return: Non-zero value on failure. */ -int devlink_trap_groups_register(struct devlink *devlink, - const struct devlink_trap_group *groups, - size_t groups_count) +int devl_trap_groups_register(struct devlink *devlink, + const struct devlink_trap_group *groups, + size_t groups_count) { int i, err; - devl_lock(devlink); + devl_assert_locked(devlink); for (i = 0; i < groups_count; i++) { const struct devlink_trap_group *group = &groups[i]; @@ -11791,7 +11830,6 @@ int devlink_trap_groups_register(struct devlink *devlink, if (err) goto err_trap_group_register; } - devl_unlock(devlink); return 0; @@ -11799,26 +11837,65 @@ err_trap_group_register: err_trap_group_verify: for (i--; i >= 0; i--) devlink_trap_group_unregister(devlink, &groups[i]); + return err; +} +EXPORT_SYMBOL_GPL(devl_trap_groups_register); + +/** + * devlink_trap_groups_register - Register packet trap groups with devlink. + * @devlink: devlink. + * @groups: Packet trap groups. + * @groups_count: Count of provided packet trap groups. + * + * Context: Takes and release devlink->lock . + * + * Return: Non-zero value on failure. + */ +int devlink_trap_groups_register(struct devlink *devlink, + const struct devlink_trap_group *groups, + size_t groups_count) +{ + int err; + + devl_lock(devlink); + err = devl_trap_groups_register(devlink, groups, groups_count); devl_unlock(devlink); return err; } EXPORT_SYMBOL_GPL(devlink_trap_groups_register); +/** + * devl_trap_groups_unregister - Unregister packet trap groups from devlink. + * @devlink: devlink. + * @groups: Packet trap groups. + * @groups_count: Count of provided packet trap groups. + */ +void devl_trap_groups_unregister(struct devlink *devlink, + const struct devlink_trap_group *groups, + size_t groups_count) +{ + int i; + + devl_assert_locked(devlink); + for (i = groups_count - 1; i >= 0; i--) + devlink_trap_group_unregister(devlink, &groups[i]); +} +EXPORT_SYMBOL_GPL(devl_trap_groups_unregister); + /** * devlink_trap_groups_unregister - Unregister packet trap groups from devlink. * @devlink: devlink. * @groups: Packet trap groups. * @groups_count: Count of provided packet trap groups. + * + * Context: Takes and release devlink->lock . */ void devlink_trap_groups_unregister(struct devlink *devlink, const struct devlink_trap_group *groups, size_t groups_count) { - int i; - devl_lock(devlink); - for (i = groups_count - 1; i >= 0; i--) - devlink_trap_group_unregister(devlink, &groups[i]); + devl_trap_groups_unregister(devlink, groups, groups_count); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister); @@ -11905,7 +11982,7 @@ devlink_trap_policer_unregister(struct devlink *devlink, } /** - * devlink_trap_policers_register - Register packet trap policers with devlink. + * devl_trap_policers_register - Register packet trap policers with devlink. * @devlink: devlink. * @policers: Packet trap policers. * @policers_count: Count of provided packet trap policers. @@ -11913,13 +11990,13 @@ devlink_trap_policer_unregister(struct devlink *devlink, * Return: Non-zero value on failure. */ int -devlink_trap_policers_register(struct devlink *devlink, - const struct devlink_trap_policer *policers, - size_t policers_count) +devl_trap_policers_register(struct devlink *devlink, + const struct devlink_trap_policer *policers, + size_t policers_count) { int i, err; - devl_lock(devlink); + devl_assert_locked(devlink); for (i = 0; i < policers_count; i++) { const struct devlink_trap_policer *policer = &policers[i]; @@ -11934,35 +12011,74 @@ devlink_trap_policers_register(struct devlink *devlink, if (err) goto err_trap_policer_register; } - devl_unlock(devlink); - return 0; err_trap_policer_register: err_trap_policer_verify: for (i--; i >= 0; i--) devlink_trap_policer_unregister(devlink, &policers[i]); + return err; +} +EXPORT_SYMBOL_GPL(devl_trap_policers_register); + +/** + * devlink_trap_policers_register - Register packet trap policers with devlink. + * @devlink: devlink. + * @policers: Packet trap policers. + * @policers_count: Count of provided packet trap policers. + * + * Return: Non-zero value on failure. + * + * Context: Takes and release devlink->lock . + */ +int +devlink_trap_policers_register(struct devlink *devlink, + const struct devlink_trap_policer *policers, + size_t policers_count) +{ + int err; + + devl_lock(devlink); + err = devl_trap_policers_register(devlink, policers, policers_count); devl_unlock(devlink); return err; } EXPORT_SYMBOL_GPL(devlink_trap_policers_register); +/** + * devl_trap_policers_unregister - Unregister packet trap policers from devlink. + * @devlink: devlink. + * @policers: Packet trap policers. + * @policers_count: Count of provided packet trap policers. + */ +void +devl_trap_policers_unregister(struct devlink *devlink, + const struct devlink_trap_policer *policers, + size_t policers_count) +{ + int i; + + devl_assert_locked(devlink); + for (i = policers_count - 1; i >= 0; i--) + devlink_trap_policer_unregister(devlink, &policers[i]); +} +EXPORT_SYMBOL_GPL(devl_trap_policers_unregister); + /** * devlink_trap_policers_unregister - Unregister packet trap policers from devlink. * @devlink: devlink. * @policers: Packet trap policers. * @policers_count: Count of provided packet trap policers. + * + * Context: Takes and release devlink->lock . */ void devlink_trap_policers_unregister(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count) { - int i; - devl_lock(devlink); - for (i = policers_count - 1; i >= 0; i--) - devlink_trap_policer_unregister(devlink, &policers[i]); + devl_trap_policers_unregister(devlink, policers, policers_count); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister); -- cgit v1.2.3 From c223d6a4bf6d2a88f2418316393f9170f81c54f0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:35 +0200 Subject: net: devlink: add unlocked variants of devlink_resource*() functions Add unlocked variants of devlink_resource*() functions to be used in drivers called-in with devlink->lock held. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 17 ++++ net/core/devlink.c | 217 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 173 insertions(+), 61 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index fb1e17d998b6..d341753753ce 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1608,23 +1608,40 @@ extern struct devlink_dpipe_header devlink_dpipe_header_ethernet; extern struct devlink_dpipe_header devlink_dpipe_header_ipv4; extern struct devlink_dpipe_header devlink_dpipe_header_ipv6; +int devl_resource_register(struct devlink *devlink, + const char *resource_name, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, + const struct devlink_resource_size_params *size_params); int devlink_resource_register(struct devlink *devlink, const char *resource_name, u64 resource_size, u64 resource_id, u64 parent_resource_id, const struct devlink_resource_size_params *size_params); +void devl_resources_unregister(struct devlink *devlink); void devlink_resources_unregister(struct devlink *devlink); +int devl_resource_size_get(struct devlink *devlink, + u64 resource_id, + u64 *p_resource_size); int devlink_resource_size_get(struct devlink *devlink, u64 resource_id, u64 *p_resource_size); int devlink_dpipe_table_resource_set(struct devlink *devlink, const char *table_name, u64 resource_id, u64 resource_units); +void devl_resource_occ_get_register(struct devlink *devlink, + u64 resource_id, + devlink_resource_occ_get_t *occ_get, + void *occ_get_priv); void devlink_resource_occ_get_register(struct devlink *devlink, u64 resource_id, devlink_resource_occ_get_t *occ_get, void *occ_get_priv); +void devl_resource_occ_get_unregister(struct devlink *devlink, + u64 resource_id); + void devlink_resource_occ_get_unregister(struct devlink *devlink, u64 resource_id); int devlink_params_register(struct devlink *devlink, diff --git a/net/core/devlink.c b/net/core/devlink.c index b0f6e8388880..1688271ef7b2 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10555,45 +10555,41 @@ unlock: EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); /** - * devlink_resource_register - devlink resource register + * devl_resource_register - devlink resource register * - * @devlink: devlink - * @resource_name: resource's name - * @resource_size: resource's size - * @resource_id: resource's id - * @parent_resource_id: resource's parent id - * @size_params: size parameters + * @devlink: devlink + * @resource_name: resource's name + * @resource_size: resource's size + * @resource_id: resource's id + * @parent_resource_id: resource's parent id + * @size_params: size parameters * - * Generic resources should reuse the same names across drivers. - * Please see the generic resources list at: - * Documentation/networking/devlink/devlink-resource.rst + * Generic resources should reuse the same names across drivers. + * Please see the generic resources list at: + * Documentation/networking/devlink/devlink-resource.rst */ -int devlink_resource_register(struct devlink *devlink, - const char *resource_name, - u64 resource_size, - u64 resource_id, - u64 parent_resource_id, - const struct devlink_resource_size_params *size_params) +int devl_resource_register(struct devlink *devlink, + const char *resource_name, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, + const struct devlink_resource_size_params *size_params) { struct devlink_resource *resource; struct list_head *resource_list; bool top_hierarchy; - int err = 0; + + lockdep_assert_held(&devlink->lock); top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP; - devl_lock(devlink); resource = devlink_resource_find(devlink, NULL, resource_id); - if (resource) { - err = -EINVAL; - goto out; - } + if (resource) + return -EINVAL; resource = kzalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) { - err = -ENOMEM; - goto out; - } + if (!resource) + return -ENOMEM; if (top_hierarchy) { resource_list = &devlink->resource_list; @@ -10607,8 +10603,7 @@ int devlink_resource_register(struct devlink *devlink, resource->parent = parent_resource; } else { kfree(resource); - err = -EINVAL; - goto out; + return -EINVAL; } } @@ -10621,7 +10616,39 @@ int devlink_resource_register(struct devlink *devlink, sizeof(resource->size_params)); INIT_LIST_HEAD(&resource->resource_list); list_add_tail(&resource->list, resource_list); -out: + + return 0; +} +EXPORT_SYMBOL_GPL(devl_resource_register); + +/** + * devlink_resource_register - devlink resource register + * + * @devlink: devlink + * @resource_name: resource's name + * @resource_size: resource's size + * @resource_id: resource's id + * @parent_resource_id: resource's parent id + * @size_params: size parameters + * + * Generic resources should reuse the same names across drivers. + * Please see the generic resources list at: + * Documentation/networking/devlink/devlink-resource.rst + * + * Context: Takes and release devlink->lock . + */ +int devlink_resource_register(struct devlink *devlink, + const char *resource_name, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, + const struct devlink_resource_size_params *size_params) +{ + int err; + + devl_lock(devlink); + err = devl_resource_register(devlink, resource_name, resource_size, + resource_id, parent_resource_id, size_params); devl_unlock(devlink); return err; } @@ -10641,15 +10668,15 @@ static void devlink_resource_unregister(struct devlink *devlink, } /** - * devlink_resources_unregister - free all resources + * devl_resources_unregister - free all resources * - * @devlink: devlink + * @devlink: devlink */ -void devlink_resources_unregister(struct devlink *devlink) +void devl_resources_unregister(struct devlink *devlink) { struct devlink_resource *tmp, *child_resource; - devl_lock(devlink); + lockdep_assert_held(&devlink->lock); list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list, list) { @@ -10657,34 +10684,65 @@ void devlink_resources_unregister(struct devlink *devlink) list_del(&child_resource->list); kfree(child_resource); } +} +EXPORT_SYMBOL_GPL(devl_resources_unregister); +/** + * devlink_resources_unregister - free all resources + * + * @devlink: devlink + * + * Context: Takes and release devlink->lock . + */ +void devlink_resources_unregister(struct devlink *devlink) +{ + devl_lock(devlink); + devl_resources_unregister(devlink); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_resources_unregister); +/** + * devl_resource_size_get - get and update size + * + * @devlink: devlink + * @resource_id: the requested resource id + * @p_resource_size: ptr to update + */ +int devl_resource_size_get(struct devlink *devlink, + u64 resource_id, + u64 *p_resource_size) +{ + struct devlink_resource *resource; + + lockdep_assert_held(&devlink->lock); + + resource = devlink_resource_find(devlink, NULL, resource_id); + if (!resource) + return -EINVAL; + *p_resource_size = resource->size_new; + resource->size = resource->size_new; + return 0; +} +EXPORT_SYMBOL_GPL(devl_resource_size_get); + /** * devlink_resource_size_get - get and update size * * @devlink: devlink * @resource_id: the requested resource id * @p_resource_size: ptr to update + * + * Context: Takes and release devlink->lock . */ int devlink_resource_size_get(struct devlink *devlink, u64 resource_id, u64 *p_resource_size) { - struct devlink_resource *resource; - int err = 0; + int err; devl_lock(devlink); - resource = devlink_resource_find(devlink, NULL, resource_id); - if (!resource) { - err = -EINVAL; - goto out; - } - *p_resource_size = resource->size_new; - resource->size = resource->size_new; -out: + err = devl_resource_size_get(devlink, resource_id, p_resource_size); devl_unlock(devlink); return err; } @@ -10721,6 +10779,33 @@ out: } EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set); +/** + * devl_resource_occ_get_register - register occupancy getter + * + * @devlink: devlink + * @resource_id: resource id + * @occ_get: occupancy getter callback + * @occ_get_priv: occupancy getter callback priv + */ +void devl_resource_occ_get_register(struct devlink *devlink, + u64 resource_id, + devlink_resource_occ_get_t *occ_get, + void *occ_get_priv) +{ + struct devlink_resource *resource; + + lockdep_assert_held(&devlink->lock); + + resource = devlink_resource_find(devlink, NULL, resource_id); + if (WARN_ON(!resource)) + return; + WARN_ON(resource->occ_get); + + resource->occ_get = occ_get; + resource->occ_get_priv = occ_get_priv; +} +EXPORT_SYMBOL_GPL(devl_resource_occ_get_register); + /** * devlink_resource_occ_get_register - register occupancy getter * @@ -10728,47 +10813,57 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set); * @resource_id: resource id * @occ_get: occupancy getter callback * @occ_get_priv: occupancy getter callback priv + * + * Context: Takes and release devlink->lock . */ void devlink_resource_occ_get_register(struct devlink *devlink, u64 resource_id, devlink_resource_occ_get_t *occ_get, void *occ_get_priv) { - struct devlink_resource *resource; - devl_lock(devlink); - resource = devlink_resource_find(devlink, NULL, resource_id); - if (WARN_ON(!resource)) - goto out; - WARN_ON(resource->occ_get); - - resource->occ_get = occ_get; - resource->occ_get_priv = occ_get_priv; -out: + devl_resource_occ_get_register(devlink, resource_id, + occ_get, occ_get_priv); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register); /** - * devlink_resource_occ_get_unregister - unregister occupancy getter + * devl_resource_occ_get_unregister - unregister occupancy getter * - * @devlink: devlink - * @resource_id: resource id + * @devlink: devlink + * @resource_id: resource id */ -void devlink_resource_occ_get_unregister(struct devlink *devlink, - u64 resource_id) +void devl_resource_occ_get_unregister(struct devlink *devlink, + u64 resource_id) { struct devlink_resource *resource; - devl_lock(devlink); + lockdep_assert_held(&devlink->lock); + resource = devlink_resource_find(devlink, NULL, resource_id); if (WARN_ON(!resource)) - goto out; + return; WARN_ON(!resource->occ_get); resource->occ_get = NULL; resource->occ_get_priv = NULL; -out: +} +EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister); + +/** + * devlink_resource_occ_get_unregister - unregister occupancy getter + * + * @devlink: devlink + * @resource_id: resource id + * + * Context: Takes and release devlink->lock . + */ +void devlink_resource_occ_get_unregister(struct devlink *devlink, + u64 resource_id) +{ + devl_lock(devlink); + devl_resource_occ_get_unregister(devlink, resource_id); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister); -- cgit v1.2.3 From 755cfa69c4ece770c5a15dd51a9da2a7aafafa7c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:36 +0200 Subject: net: devlink: add unlocked variants of devlink_sb*() functions Add unlocked variants of devlink_sb*() functions to be used in drivers called-in with devlink->lock held. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 5 +++++ net/core/devlink.c | 54 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 18 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index d341753753ce..0057809a13b0 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1579,10 +1579,15 @@ void devlink_linecard_provision_clear(struct devlink_linecard *linecard); void devlink_linecard_provision_fail(struct devlink_linecard *linecard); void devlink_linecard_activate(struct devlink_linecard *linecard); void devlink_linecard_deactivate(struct devlink_linecard *linecard); +int devl_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, + u16 egress_tc_count); int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, u32 size, u16 ingress_pools_count, u16 egress_pools_count, u16 ingress_tc_count, u16 egress_tc_count); +void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index); void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index); int devlink_dpipe_table_register(struct devlink *devlink, const char *table_name, diff --git a/net/core/devlink.c b/net/core/devlink.c index 1688271ef7b2..64dab4024d11 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10375,25 +10375,21 @@ void devlink_linecard_deactivate(struct devlink_linecard *linecard) } EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); -int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, - u32 size, u16 ingress_pools_count, - u16 egress_pools_count, u16 ingress_tc_count, - u16 egress_tc_count) +int devl_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, + u16 egress_tc_count) { struct devlink_sb *devlink_sb; - int err = 0; - devl_lock(devlink); - if (devlink_sb_index_exists(devlink, sb_index)) { - err = -EEXIST; - goto unlock; - } + lockdep_assert_held(&devlink->lock); + + if (devlink_sb_index_exists(devlink, sb_index)) + return -EEXIST; devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL); - if (!devlink_sb) { - err = -ENOMEM; - goto unlock; - } + if (!devlink_sb) + return -ENOMEM; devlink_sb->index = sb_index; devlink_sb->size = size; devlink_sb->ingress_pools_count = ingress_pools_count; @@ -10401,23 +10397,45 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, devlink_sb->ingress_tc_count = ingress_tc_count; devlink_sb->egress_tc_count = egress_tc_count; list_add_tail(&devlink_sb->list, &devlink->sb_list); -unlock: + return 0; +} +EXPORT_SYMBOL_GPL(devl_sb_register); + +int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, + u16 egress_tc_count) +{ + int err; + + devl_lock(devlink); + err = devl_sb_register(devlink, sb_index, size, ingress_pools_count, + egress_pools_count, ingress_tc_count, + egress_tc_count); devl_unlock(devlink); return err; } EXPORT_SYMBOL_GPL(devlink_sb_register); -void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index) +void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index) { struct devlink_sb *devlink_sb; - devl_lock(devlink); + lockdep_assert_held(&devlink->lock); + devlink_sb = devlink_sb_get_by_index(devlink, sb_index); WARN_ON(!devlink_sb); list_del(&devlink_sb->list); - devl_unlock(devlink); kfree(devlink_sb); } +EXPORT_SYMBOL_GPL(devl_sb_unregister); + +void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index) +{ + devl_lock(devlink); + devl_sb_unregister(devlink, sb_index); + devl_unlock(devlink); +} EXPORT_SYMBOL_GPL(devlink_sb_unregister); /** -- cgit v1.2.3 From 70a2ff89369d17c55efacb789171c3bd05c21817 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:37 +0200 Subject: net: devlink: add unlocked variants of devlink_dpipe*() functions Add unlocked variants of devlink_dpipe*() functions to be used in drivers called-in with devlink->lock held. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 12 ++++ net/core/devlink.c | 181 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 147 insertions(+), 46 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 0057809a13b0..18ad88527847 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1589,14 +1589,23 @@ int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, u16 egress_tc_count); void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index); void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index); +int devl_dpipe_table_register(struct devlink *devlink, + const char *table_name, + struct devlink_dpipe_table_ops *table_ops, + void *priv, bool counter_control_extern); int devlink_dpipe_table_register(struct devlink *devlink, const char *table_name, struct devlink_dpipe_table_ops *table_ops, void *priv, bool counter_control_extern); +void devl_dpipe_table_unregister(struct devlink *devlink, + const char *table_name); void devlink_dpipe_table_unregister(struct devlink *devlink, const char *table_name); +void devl_dpipe_headers_register(struct devlink *devlink, + struct devlink_dpipe_headers *dpipe_headers); void devlink_dpipe_headers_register(struct devlink *devlink, struct devlink_dpipe_headers *dpipe_headers); +void devl_dpipe_headers_unregister(struct devlink *devlink); void devlink_dpipe_headers_unregister(struct devlink *devlink); bool devlink_dpipe_table_counter_enabled(struct devlink *devlink, const char *table_name); @@ -1633,6 +1642,9 @@ int devl_resource_size_get(struct devlink *devlink, int devlink_resource_size_get(struct devlink *devlink, u64 resource_id, u64 *p_resource_size); +int devl_dpipe_table_resource_set(struct devlink *devlink, + const char *table_name, u64 resource_id, + u64 resource_units); int devlink_dpipe_table_resource_set(struct devlink *devlink, const char *table_name, u64 resource_id, u64 resource_units); diff --git a/net/core/devlink.c b/net/core/devlink.c index 64dab4024d11..b249c18a8bbc 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10438,6 +10438,23 @@ void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index) } EXPORT_SYMBOL_GPL(devlink_sb_unregister); +/** + * devl_dpipe_headers_register - register dpipe headers + * + * @devlink: devlink + * @dpipe_headers: dpipe header array + * + * Register the headers supported by hardware. + */ +void devl_dpipe_headers_register(struct devlink *devlink, + struct devlink_dpipe_headers *dpipe_headers) +{ + lockdep_assert_held(&devlink->lock); + + devlink->dpipe_headers = dpipe_headers; +} +EXPORT_SYMBOL_GPL(devl_dpipe_headers_register); + /** * devlink_dpipe_headers_register - register dpipe headers * @@ -10445,27 +10462,46 @@ EXPORT_SYMBOL_GPL(devlink_sb_unregister); * @dpipe_headers: dpipe header array * * Register the headers supported by hardware. + * + * Context: Takes and release devlink->lock . */ void devlink_dpipe_headers_register(struct devlink *devlink, struct devlink_dpipe_headers *dpipe_headers) { devl_lock(devlink); - devlink->dpipe_headers = dpipe_headers; + devl_dpipe_headers_register(devlink, dpipe_headers); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register); +/** + * devl_dpipe_headers_unregister - unregister dpipe headers + * + * @devlink: devlink + * + * Unregister the headers supported by hardware. + */ +void devl_dpipe_headers_unregister(struct devlink *devlink) +{ + lockdep_assert_held(&devlink->lock); + + devlink->dpipe_headers = NULL; +} +EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister); + /** * devlink_dpipe_headers_unregister - unregister dpipe headers * * @devlink: devlink * * Unregister the headers supported by hardware. + * + * Context: Takes and release devlink->lock . */ void devlink_dpipe_headers_unregister(struct devlink *devlink) { devl_lock(devlink); - devlink->dpipe_headers = NULL; + devl_dpipe_headers_unregister(devlink); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister); @@ -10502,38 +10538,33 @@ bool devlink_dpipe_table_counter_enabled(struct devlink *devlink, EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled); /** - * devlink_dpipe_table_register - register dpipe table + * devl_dpipe_table_register - register dpipe table * - * @devlink: devlink - * @table_name: table name - * @table_ops: table ops - * @priv: priv - * @counter_control_extern: external control for counters + * @devlink: devlink + * @table_name: table name + * @table_ops: table ops + * @priv: priv + * @counter_control_extern: external control for counters */ -int devlink_dpipe_table_register(struct devlink *devlink, - const char *table_name, - struct devlink_dpipe_table_ops *table_ops, - void *priv, bool counter_control_extern) +int devl_dpipe_table_register(struct devlink *devlink, + const char *table_name, + struct devlink_dpipe_table_ops *table_ops, + void *priv, bool counter_control_extern) { struct devlink_dpipe_table *table; - int err = 0; + + lockdep_assert_held(&devlink->lock); if (WARN_ON(!table_ops->size_get)) return -EINVAL; - devl_lock(devlink); - if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name, - devlink)) { - err = -EEXIST; - goto unlock; - } + devlink)) + return -EEXIST; table = kzalloc(sizeof(*table), GFP_KERNEL); - if (!table) { - err = -ENOMEM; - goto unlock; - } + if (!table) + return -ENOMEM; table->name = table_name; table->table_ops = table_ops; @@ -10541,33 +10572,72 @@ int devlink_dpipe_table_register(struct devlink *devlink, table->counter_control_extern = counter_control_extern; list_add_tail_rcu(&table->list, &devlink->dpipe_table_list); -unlock: + + return 0; +} +EXPORT_SYMBOL_GPL(devl_dpipe_table_register); + +/** + * devlink_dpipe_table_register - register dpipe table + * + * @devlink: devlink + * @table_name: table name + * @table_ops: table ops + * @priv: priv + * @counter_control_extern: external control for counters + * + * Context: Takes and release devlink->lock . + */ +int devlink_dpipe_table_register(struct devlink *devlink, + const char *table_name, + struct devlink_dpipe_table_ops *table_ops, + void *priv, bool counter_control_extern) +{ + int err; + + devl_lock(devlink); + err = devl_dpipe_table_register(devlink, table_name, table_ops, priv, + counter_control_extern); devl_unlock(devlink); return err; } EXPORT_SYMBOL_GPL(devlink_dpipe_table_register); /** - * devlink_dpipe_table_unregister - unregister dpipe table + * devl_dpipe_table_unregister - unregister dpipe table * - * @devlink: devlink - * @table_name: table name + * @devlink: devlink + * @table_name: table name */ -void devlink_dpipe_table_unregister(struct devlink *devlink, - const char *table_name) +void devl_dpipe_table_unregister(struct devlink *devlink, + const char *table_name) { struct devlink_dpipe_table *table; - devl_lock(devlink); + lockdep_assert_held(&devlink->lock); + table = devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name, devlink); if (!table) - goto unlock; + return; list_del_rcu(&table->list); - devl_unlock(devlink); kfree_rcu(table, rcu); - return; -unlock: +} +EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister); + +/** + * devlink_dpipe_table_unregister - unregister dpipe table + * + * @devlink: devlink + * @table_name: table name + * + * Context: Takes and release devlink->lock . + */ +void devlink_dpipe_table_unregister(struct devlink *devlink, + const char *table_name) +{ + devl_lock(devlink); + devl_dpipe_table_unregister(devlink, table_name); devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); @@ -10766,6 +10836,32 @@ int devlink_resource_size_get(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devlink_resource_size_get); +/** + * devl_dpipe_table_resource_set - set the resource id + * + * @devlink: devlink + * @table_name: table name + * @resource_id: resource id + * @resource_units: number of resource's units consumed per table's entry + */ +int devl_dpipe_table_resource_set(struct devlink *devlink, + const char *table_name, u64 resource_id, + u64 resource_units) +{ + struct devlink_dpipe_table *table; + + table = devlink_dpipe_table_find(&devlink->dpipe_table_list, + table_name, devlink); + if (!table) + return -EINVAL; + + table->resource_id = resource_id; + table->resource_units = resource_units; + table->resource_valid = true; + return 0; +} +EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set); + /** * devlink_dpipe_table_resource_set - set the resource id * @@ -10773,25 +10869,18 @@ EXPORT_SYMBOL_GPL(devlink_resource_size_get); * @table_name: table name * @resource_id: resource id * @resource_units: number of resource's units consumed per table's entry + * + * Context: Takes and release devlink->lock . */ int devlink_dpipe_table_resource_set(struct devlink *devlink, const char *table_name, u64 resource_id, u64 resource_units) { - struct devlink_dpipe_table *table; - int err = 0; + int err; devl_lock(devlink); - table = devlink_dpipe_table_find(&devlink->dpipe_table_list, - table_name, devlink); - if (!table) { - err = -EINVAL; - goto out; - } - table->resource_id = resource_id; - table->resource_units = resource_units; - table->resource_valid = true; -out: + err = devl_dpipe_table_resource_set(devlink, table_name, + resource_id, resource_units); devl_unlock(devlink); return err; } -- cgit v1.2.3 From eb0e9fa2c6355e744d3ea7d07d34d89a4735320e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:39 +0200 Subject: net: devlink: add unlocked variants of devlink_region_create/destroy() functions Add unlocked variants of devlink_region_create/destroy() functions to be used in drivers called-in with devlink->lock held. Signed-off-by: Jiri Pirko Reviewed-by: Moshe Shemesh Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 5 +++ net/core/devlink.c | 89 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 28 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 18ad88527847..391d401ddb55 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1676,6 +1676,10 @@ int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id, int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id, union devlink_param_value init_val); void devlink_param_value_changed(struct devlink *devlink, u32 param_id); +struct devlink_region *devl_region_create(struct devlink *devlink, + const struct devlink_region_ops *ops, + u32 region_max_snapshots, + u64 region_size); struct devlink_region * devlink_region_create(struct devlink *devlink, const struct devlink_region_ops *ops, @@ -1684,6 +1688,7 @@ struct devlink_region * devlink_port_region_create(struct devlink_port *port, const struct devlink_port_region_ops *ops, u32 region_max_snapshots, u64 region_size); +void devl_region_destroy(struct devlink_region *region); void devlink_region_destroy(struct devlink_region *region); void devlink_port_region_destroy(struct devlink_region *region); diff --git a/net/core/devlink.c b/net/core/devlink.c index b249c18a8bbc..fe9657d6162f 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -11192,36 +11192,31 @@ void devlink_param_value_changed(struct devlink *devlink, u32 param_id) EXPORT_SYMBOL_GPL(devlink_param_value_changed); /** - * devlink_region_create - create a new address region + * devl_region_create - create a new address region * - * @devlink: devlink - * @ops: region operations and name - * @region_max_snapshots: Maximum supported number of snapshots for region - * @region_size: size of region + * @devlink: devlink + * @ops: region operations and name + * @region_max_snapshots: Maximum supported number of snapshots for region + * @region_size: size of region */ -struct devlink_region * -devlink_region_create(struct devlink *devlink, - const struct devlink_region_ops *ops, - u32 region_max_snapshots, u64 region_size) +struct devlink_region *devl_region_create(struct devlink *devlink, + const struct devlink_region_ops *ops, + u32 region_max_snapshots, + u64 region_size) { struct devlink_region *region; - int err = 0; + + devl_assert_locked(devlink); if (WARN_ON(!ops) || WARN_ON(!ops->destructor)) return ERR_PTR(-EINVAL); - devl_lock(devlink); - - if (devlink_region_get_by_name(devlink, ops->name)) { - err = -EEXIST; - goto unlock; - } + if (devlink_region_get_by_name(devlink, ops->name)) + return ERR_PTR(-EEXIST); region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) { - err = -ENOMEM; - goto unlock; - } + if (!region) + return ERR_PTR(-ENOMEM); region->devlink = devlink; region->max_snapshots = region_max_snapshots; @@ -11231,12 +11226,32 @@ devlink_region_create(struct devlink *devlink, list_add_tail(®ion->list, &devlink->region_list); devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW); - devl_unlock(devlink); return region; +} +EXPORT_SYMBOL_GPL(devl_region_create); -unlock: +/** + * devlink_region_create - create a new address region + * + * @devlink: devlink + * @ops: region operations and name + * @region_max_snapshots: Maximum supported number of snapshots for region + * @region_size: size of region + * + * Context: Takes and release devlink->lock . + */ +struct devlink_region * +devlink_region_create(struct devlink *devlink, + const struct devlink_region_ops *ops, + u32 region_max_snapshots, u64 region_size) +{ + struct devlink_region *region; + + devl_lock(devlink); + region = devl_region_create(devlink, ops, region_max_snapshots, + region_size); devl_unlock(devlink); - return ERR_PTR(err); + return region; } EXPORT_SYMBOL_GPL(devlink_region_create); @@ -11247,6 +11262,8 @@ EXPORT_SYMBOL_GPL(devlink_region_create); * @ops: region operations and name * @region_max_snapshots: Maximum supported number of snapshots for region * @region_size: size of region + * + * Context: Takes and release devlink->lock . */ struct devlink_region * devlink_port_region_create(struct devlink_port *port, @@ -11292,16 +11309,16 @@ unlock: EXPORT_SYMBOL_GPL(devlink_port_region_create); /** - * devlink_region_destroy - destroy address region + * devl_region_destroy - destroy address region * - * @region: devlink region to destroy + * @region: devlink region to destroy */ -void devlink_region_destroy(struct devlink_region *region) +void devl_region_destroy(struct devlink_region *region) { struct devlink *devlink = region->devlink; struct devlink_snapshot *snapshot, *ts; - devl_lock(devlink); + devl_assert_locked(devlink); /* Free all snapshots of region */ list_for_each_entry_safe(snapshot, ts, ®ion->snapshot_list, list) @@ -11310,9 +11327,25 @@ void devlink_region_destroy(struct devlink_region *region) list_del(®ion->list); devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL); - devl_unlock(devlink); kfree(region); } +EXPORT_SYMBOL_GPL(devl_region_destroy); + +/** + * devlink_region_destroy - destroy address region + * + * @region: devlink region to destroy + * + * Context: Takes and release devlink->lock . + */ +void devlink_region_destroy(struct devlink_region *region) +{ + struct devlink *devlink = region->devlink; + + devl_lock(devlink); + devl_region_destroy(region); + devl_unlock(devlink); +} EXPORT_SYMBOL_GPL(devlink_region_destroy); /** -- cgit v1.2.3 From 012ec02ae4410207f796a9b280a60b80b6cc790a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:40 +0200 Subject: netdevsim: convert driver to use unlocked devlink API during init/fini Prepare for devlink reload being called with devlink->lock held and convert the netdevsim driver to use unlocked devlink API during init and fini flows. Take devl_lock() in reload_down() and reload_up() ops in the meantime before reload cmd is converted to take the lock itself. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/netdevsim/bus.c | 19 ------ drivers/net/netdevsim/dev.c | 134 ++++++++++++++++++-------------------- drivers/net/netdevsim/fib.c | 62 +++++++++--------- drivers/net/netdevsim/netdevsim.h | 3 - include/net/devlink.h | 1 + net/core/devlink.c | 6 ++ 6 files changed, 102 insertions(+), 123 deletions(-) (limited to 'include/net') diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 25cb2e600d53..b5f4df1a07a3 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -72,16 +72,7 @@ new_port_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) - return -EBUSY; - - if (nsim_bus_dev->in_reload) { - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); - return -EBUSY; - } - ret = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); return ret ? ret : count; } @@ -102,16 +93,7 @@ del_port_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) - return -EBUSY; - - if (nsim_bus_dev->in_reload) { - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); - return -EBUSY; - } - ret = nsim_drv_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); return ret ? ret : count; } @@ -298,7 +280,6 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queu nsim_bus_dev->num_queues = num_queues; nsim_bus_dev->initial_net = current->nsproxy->net_ns; nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; - mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); /* Disallow using nsim_bus_dev */ smp_store_release(&nsim_bus_dev->init, false); diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 57a3ac893792..5802e80e8fe1 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -436,62 +436,62 @@ static int nsim_dev_resources_register(struct devlink *devlink) int err; /* Resources for IPv4 */ - err = devlink_resource_register(devlink, "IPv4", (u64)-1, - NSIM_RESOURCE_IPV4, - DEVLINK_RESOURCE_ID_PARENT_TOP, - ¶ms); + err = devl_resource_register(devlink, "IPv4", (u64)-1, + NSIM_RESOURCE_IPV4, + DEVLINK_RESOURCE_ID_PARENT_TOP, + ¶ms); if (err) { pr_err("Failed to register IPv4 top resource\n"); goto out; } - err = devlink_resource_register(devlink, "fib", (u64)-1, - NSIM_RESOURCE_IPV4_FIB, - NSIM_RESOURCE_IPV4, ¶ms); + err = devl_resource_register(devlink, "fib", (u64)-1, + NSIM_RESOURCE_IPV4_FIB, + NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB resource\n"); return err; } - err = devlink_resource_register(devlink, "fib-rules", (u64)-1, - NSIM_RESOURCE_IPV4_FIB_RULES, - NSIM_RESOURCE_IPV4, ¶ms); + err = devl_resource_register(devlink, "fib-rules", (u64)-1, + NSIM_RESOURCE_IPV4_FIB_RULES, + NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB rules resource\n"); return err; } /* Resources for IPv6 */ - err = devlink_resource_register(devlink, "IPv6", (u64)-1, - NSIM_RESOURCE_IPV6, - DEVLINK_RESOURCE_ID_PARENT_TOP, - ¶ms); + err = devl_resource_register(devlink, "IPv6", (u64)-1, + NSIM_RESOURCE_IPV6, + DEVLINK_RESOURCE_ID_PARENT_TOP, + ¶ms); if (err) { pr_err("Failed to register IPv6 top resource\n"); goto out; } - err = devlink_resource_register(devlink, "fib", (u64)-1, - NSIM_RESOURCE_IPV6_FIB, - NSIM_RESOURCE_IPV6, ¶ms); + err = devl_resource_register(devlink, "fib", (u64)-1, + NSIM_RESOURCE_IPV6_FIB, + NSIM_RESOURCE_IPV6, ¶ms); if (err) { pr_err("Failed to register IPv6 FIB resource\n"); return err; } - err = devlink_resource_register(devlink, "fib-rules", (u64)-1, - NSIM_RESOURCE_IPV6_FIB_RULES, - NSIM_RESOURCE_IPV6, ¶ms); + err = devl_resource_register(devlink, "fib-rules", (u64)-1, + NSIM_RESOURCE_IPV6_FIB_RULES, + NSIM_RESOURCE_IPV6, ¶ms); if (err) { pr_err("Failed to register IPv6 FIB rules resource\n"); return err; } /* Resources for nexthops */ - err = devlink_resource_register(devlink, "nexthops", (u64)-1, - NSIM_RESOURCE_NEXTHOPS, - DEVLINK_RESOURCE_ID_PARENT_TOP, - ¶ms); + err = devl_resource_register(devlink, "nexthops", (u64)-1, + NSIM_RESOURCE_NEXTHOPS, + DEVLINK_RESOURCE_ID_PARENT_TOP, + ¶ms); out: return err; @@ -557,15 +557,15 @@ static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev, struct devlink *devlink) { nsim_dev->dummy_region = - devlink_region_create(devlink, &dummy_region_ops, - NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, - NSIM_DEV_DUMMY_REGION_SIZE); + devl_region_create(devlink, &dummy_region_ops, + NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, + NSIM_DEV_DUMMY_REGION_SIZE); return PTR_ERR_OR_ZERO(nsim_dev->dummy_region); } static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev) { - devlink_region_destroy(nsim_dev->dummy_region); + devl_region_destroy(nsim_dev->dummy_region); } static int @@ -832,7 +832,11 @@ static void nsim_dev_trap_report_work(struct work_struct *work) /* For each running port and enabled packet trap, generate a UDP * packet with a random 5-tuple and report it. */ - devl_lock(priv_to_devlink(nsim_dev)); + if (!devl_trylock(priv_to_devlink(nsim_dev))) { + schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0); + return; + } + list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { if (!netif_running(nsim_dev_port->ns->netdev)) continue; @@ -880,18 +884,18 @@ static int nsim_dev_traps_init(struct devlink *devlink) nsim_trap_data->nsim_dev = nsim_dev; nsim_dev->trap_data = nsim_trap_data; - err = devlink_trap_policers_register(devlink, nsim_trap_policers_arr, - policers_count); + err = devl_trap_policers_register(devlink, nsim_trap_policers_arr, + policers_count); if (err) goto err_trap_policers_cnt_free; - err = devlink_trap_groups_register(devlink, nsim_trap_groups_arr, - ARRAY_SIZE(nsim_trap_groups_arr)); + err = devl_trap_groups_register(devlink, nsim_trap_groups_arr, + ARRAY_SIZE(nsim_trap_groups_arr)); if (err) goto err_trap_policers_unregister; - err = devlink_traps_register(devlink, nsim_traps_arr, - ARRAY_SIZE(nsim_traps_arr), NULL); + err = devl_traps_register(devlink, nsim_traps_arr, + ARRAY_SIZE(nsim_traps_arr), NULL); if (err) goto err_trap_groups_unregister; @@ -903,11 +907,11 @@ static int nsim_dev_traps_init(struct devlink *devlink) return 0; err_trap_groups_unregister: - devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, - ARRAY_SIZE(nsim_trap_groups_arr)); + devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, + ARRAY_SIZE(nsim_trap_groups_arr)); err_trap_policers_unregister: - devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, - ARRAY_SIZE(nsim_trap_policers_arr)); + devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, + ARRAY_SIZE(nsim_trap_policers_arr)); err_trap_policers_cnt_free: kfree(nsim_trap_data->trap_policers_cnt_arr); err_trap_items_free: @@ -923,12 +927,12 @@ static void nsim_dev_traps_exit(struct devlink *devlink) /* caution, trap work takes devlink lock */ cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); - devlink_traps_unregister(devlink, nsim_traps_arr, - ARRAY_SIZE(nsim_traps_arr)); - devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, - ARRAY_SIZE(nsim_trap_groups_arr)); - devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, - ARRAY_SIZE(nsim_trap_policers_arr)); + devl_traps_unregister(devlink, nsim_traps_arr, + ARRAY_SIZE(nsim_traps_arr)); + devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, + ARRAY_SIZE(nsim_trap_groups_arr)); + devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, + ARRAY_SIZE(nsim_trap_policers_arr)); kfree(nsim_dev->trap_data->trap_policers_cnt_arr); kfree(nsim_dev->trap_data->trap_items_arr); kfree(nsim_dev->trap_data); @@ -943,24 +947,19 @@ static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, struct netlink_ext_ack *extack) { struct nsim_dev *nsim_dev = devlink_priv(devlink); - struct nsim_bus_dev *nsim_bus_dev; - - nsim_bus_dev = nsim_dev->nsim_bus_dev; - if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) - return -EOPNOTSUPP; + devl_lock(devlink); if (nsim_dev->dont_allow_reload) { /* For testing purposes, user set debugfs dont_allow_reload * value to true. So forbid it. */ NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); + devl_unlock(devlink); return -EOPNOTSUPP; } - nsim_bus_dev->in_reload = true; nsim_dev_reload_destroy(nsim_dev); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); + devl_unlock(devlink); return 0; } @@ -969,25 +968,21 @@ static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_actio struct netlink_ext_ack *extack) { struct nsim_dev *nsim_dev = devlink_priv(devlink); - struct nsim_bus_dev *nsim_bus_dev; int ret; - nsim_bus_dev = nsim_dev->nsim_bus_dev; - mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); - nsim_bus_dev->in_reload = false; - + devl_lock(devlink); if (nsim_dev->fail_reload) { /* For testing purposes, user set debugfs fail_reload * value to true. Fail right away. */ NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); + devl_unlock(devlink); return -EINVAL; } *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); ret = nsim_dev_reload_create(nsim_dev, extack); - mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); + devl_unlock(devlink); return ret; } @@ -1434,11 +1429,9 @@ static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) { struct nsim_dev_port *nsim_dev_port, *tmp; - devl_lock(priv_to_devlink(nsim_dev)); list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) __nsim_dev_port_del(nsim_dev_port); - devl_unlock(priv_to_devlink(nsim_dev)); } static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, @@ -1447,9 +1440,7 @@ static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, int i, err; for (i = 0; i < port_count; i++) { - devl_lock(priv_to_devlink(nsim_dev)); err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); - devl_unlock(priv_to_devlink(nsim_dev)); if (err) goto err_port_del_all; } @@ -1537,6 +1528,7 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_bus_dev->initial_net, &nsim_bus_dev->dev); if (!devlink) return -ENOMEM; + devl_lock(devlink); nsim_dev = devlink_priv(devlink); nsim_dev->nsim_bus_dev = nsim_bus_dev; nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); @@ -1555,7 +1547,7 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) GFP_KERNEL | __GFP_NOWARN); if (!nsim_dev->vfconfigs) { err = -ENOMEM; - goto err_devlink_free; + goto err_devlink_unlock; } err = nsim_dev_resources_register(devlink); @@ -1608,6 +1600,7 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; devlink_set_features(devlink, DEVLINK_F_RELOAD); + devl_unlock(devlink); devlink_register(devlink); return 0; @@ -1631,10 +1624,11 @@ err_params_unregister: devlink_params_unregister(devlink, nsim_devlink_params, ARRAY_SIZE(nsim_devlink_params)); err_dl_unregister: - devlink_resources_unregister(devlink); + devl_resources_unregister(devlink); err_vfc_free: kfree(nsim_dev->vfconfigs); -err_devlink_free: +err_devlink_unlock: + devl_unlock(devlink); devlink_free(devlink); dev_set_drvdata(&nsim_bus_dev->dev, NULL); return err; @@ -1648,13 +1642,11 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) return; debugfs_remove(nsim_dev->take_snapshot); - devl_lock(devlink); if (nsim_dev_get_vfs(nsim_dev)) { nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); if (nsim_esw_mode_is_switchdev(nsim_dev)) nsim_esw_legacy_enable(nsim_dev, NULL); } - devl_unlock(devlink); nsim_dev_port_del_all(nsim_dev); nsim_dev_hwstats_exit(nsim_dev); @@ -1671,14 +1663,16 @@ void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) struct devlink *devlink = priv_to_devlink(nsim_dev); devlink_unregister(devlink); + devl_lock(devlink); nsim_dev_reload_destroy(nsim_dev); nsim_bpf_dev_exit(nsim_dev); nsim_dev_debugfs_exit(nsim_dev); devlink_params_unregister(devlink, nsim_devlink_params, ARRAY_SIZE(nsim_devlink_params)); - devlink_resources_unregister(devlink); + devl_resources_unregister(devlink); kfree(nsim_dev->vfconfigs); + devl_unlock(devlink); devlink_free(devlink); dev_set_drvdata(&nsim_bus_dev->dev, NULL); } diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index c8f398f5bc5b..94e7512bef94 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -1453,7 +1453,7 @@ static void nsim_fib_set_max_all(struct nsim_fib_data *data, int err; u64 val; - err = devlink_resource_size_get(devlink, res_ids[i], &val); + err = devl_resource_size_get(devlink, res_ids[i], &val); if (err) val = (u64) -1; nsim_fib_set_max(data, res_ids[i], val); @@ -1562,26 +1562,26 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, goto err_nexthop_nb_unregister; } - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV4_FIB, - nsim_fib_ipv4_resource_occ_get, - data); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV4_FIB_RULES, - nsim_fib_ipv4_rules_res_occ_get, - data); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV6_FIB, - nsim_fib_ipv6_resource_occ_get, - data); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV6_FIB_RULES, - nsim_fib_ipv6_rules_res_occ_get, - data); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_NEXTHOPS, - nsim_fib_nexthops_res_occ_get, - data); + devl_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV4_FIB, + nsim_fib_ipv4_resource_occ_get, + data); + devl_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV4_FIB_RULES, + nsim_fib_ipv4_rules_res_occ_get, + data); + devl_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV6_FIB, + nsim_fib_ipv6_resource_occ_get, + data); + devl_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV6_FIB_RULES, + nsim_fib_ipv6_rules_res_occ_get, + data); + devl_resource_occ_get_register(devlink, + NSIM_RESOURCE_NEXTHOPS, + nsim_fib_nexthops_res_occ_get, + data); return data; err_nexthop_nb_unregister: @@ -1604,16 +1604,16 @@ err_data_free: void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) { - devlink_resource_occ_get_unregister(devlink, - NSIM_RESOURCE_NEXTHOPS); - devlink_resource_occ_get_unregister(devlink, - NSIM_RESOURCE_IPV6_FIB_RULES); - devlink_resource_occ_get_unregister(devlink, - NSIM_RESOURCE_IPV6_FIB); - devlink_resource_occ_get_unregister(devlink, - NSIM_RESOURCE_IPV4_FIB_RULES); - devlink_resource_occ_get_unregister(devlink, - NSIM_RESOURCE_IPV4_FIB); + devl_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_NEXTHOPS); + devl_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV6_FIB_RULES); + devl_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV6_FIB); + devl_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV4_FIB_RULES); + devl_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV4_FIB); unregister_fib_notifier(devlink_net(devlink), &data->fib_nb); unregister_nexthop_notifier(devlink_net(devlink), &data->nexthop_nb); flush_work(&data->fib_event_work); diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 0b122872b2c9..7d8ed8d8df5c 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -376,9 +376,6 @@ struct nsim_bus_dev { */ unsigned int max_vfs; unsigned int num_vfs; - /* Lock for devlink->reload_enabled in netdevsim module */ - struct mutex nsim_bus_reload_lock; - bool in_reload; bool init; }; diff --git a/include/net/devlink.h b/include/net/devlink.h index 391d401ddb55..242798967a44 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1517,6 +1517,7 @@ struct device *devlink_to_dev(const struct devlink *devlink); /* Devlink instance explicit locking */ void devl_lock(struct devlink *devlink); +int devl_trylock(struct devlink *devlink); void devl_unlock(struct devlink *devlink); void devl_assert_locked(struct devlink *devlink); bool devl_lock_is_held(struct devlink *devlink); diff --git a/net/core/devlink.c b/net/core/devlink.c index fe9657d6162f..1c75de6f6388 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -266,6 +266,12 @@ void devl_lock(struct devlink *devlink) } EXPORT_SYMBOL_GPL(devl_lock); +int devl_trylock(struct devlink *devlink) +{ + return mutex_trylock(&devlink->lock); +} +EXPORT_SYMBOL_GPL(devl_trylock); + void devl_unlock(struct devlink *devlink) { mutex_unlock(&devlink->lock); -- cgit v1.2.3 From f655dacb59ac987a56b82d2e73d85de411eb02aa Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 16 Jul 2022 13:02:41 +0200 Subject: net: devlink: remove unused locked functions Remove locked versions of functions that are no longer used by anyone. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 20 ------ net/core/devlink.c | 168 -------------------------------------------------- 2 files changed, 188 deletions(-) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 242798967a44..780744b550b8 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1594,20 +1594,11 @@ int devl_dpipe_table_register(struct devlink *devlink, const char *table_name, struct devlink_dpipe_table_ops *table_ops, void *priv, bool counter_control_extern); -int devlink_dpipe_table_register(struct devlink *devlink, - const char *table_name, - struct devlink_dpipe_table_ops *table_ops, - void *priv, bool counter_control_extern); void devl_dpipe_table_unregister(struct devlink *devlink, const char *table_name); -void devlink_dpipe_table_unregister(struct devlink *devlink, - const char *table_name); void devl_dpipe_headers_register(struct devlink *devlink, struct devlink_dpipe_headers *dpipe_headers); -void devlink_dpipe_headers_register(struct devlink *devlink, - struct devlink_dpipe_headers *dpipe_headers); void devl_dpipe_headers_unregister(struct devlink *devlink); -void devlink_dpipe_headers_unregister(struct devlink *devlink); bool devlink_dpipe_table_counter_enabled(struct devlink *devlink, const char *table_name); int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx); @@ -1640,9 +1631,6 @@ void devlink_resources_unregister(struct devlink *devlink); int devl_resource_size_get(struct devlink *devlink, u64 resource_id, u64 *p_resource_size); -int devlink_resource_size_get(struct devlink *devlink, - u64 resource_id, - u64 *p_resource_size); int devl_dpipe_table_resource_set(struct devlink *devlink, const char *table_name, u64 resource_id, u64 resource_units); @@ -1817,18 +1805,10 @@ int devl_trap_policers_register(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count); -int -devlink_trap_policers_register(struct devlink *devlink, - const struct devlink_trap_policer *policers, - size_t policers_count); void devl_trap_policers_unregister(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count); -void -devlink_trap_policers_unregister(struct devlink *devlink, - const struct devlink_trap_policer *policers, - size_t policers_count); #if IS_ENABLED(CONFIG_NET_DEVLINK) diff --git a/net/core/devlink.c b/net/core/devlink.c index 1c75de6f6388..98d79feeb3dc 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -10461,25 +10461,6 @@ void devl_dpipe_headers_register(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_dpipe_headers_register); -/** - * devlink_dpipe_headers_register - register dpipe headers - * - * @devlink: devlink - * @dpipe_headers: dpipe header array - * - * Register the headers supported by hardware. - * - * Context: Takes and release devlink->lock . - */ -void devlink_dpipe_headers_register(struct devlink *devlink, - struct devlink_dpipe_headers *dpipe_headers) -{ - devl_lock(devlink); - devl_dpipe_headers_register(devlink, dpipe_headers); - devl_unlock(devlink); -} -EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register); - /** * devl_dpipe_headers_unregister - unregister dpipe headers * @@ -10495,23 +10476,6 @@ void devl_dpipe_headers_unregister(struct devlink *devlink) } EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister); -/** - * devlink_dpipe_headers_unregister - unregister dpipe headers - * - * @devlink: devlink - * - * Unregister the headers supported by hardware. - * - * Context: Takes and release devlink->lock . - */ -void devlink_dpipe_headers_unregister(struct devlink *devlink) -{ - devl_lock(devlink); - devl_dpipe_headers_unregister(devlink); - devl_unlock(devlink); -} -EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister); - /** * devlink_dpipe_table_counter_enabled - check if counter allocation * required @@ -10583,32 +10547,6 @@ int devl_dpipe_table_register(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_dpipe_table_register); -/** - * devlink_dpipe_table_register - register dpipe table - * - * @devlink: devlink - * @table_name: table name - * @table_ops: table ops - * @priv: priv - * @counter_control_extern: external control for counters - * - * Context: Takes and release devlink->lock . - */ -int devlink_dpipe_table_register(struct devlink *devlink, - const char *table_name, - struct devlink_dpipe_table_ops *table_ops, - void *priv, bool counter_control_extern) -{ - int err; - - devl_lock(devlink); - err = devl_dpipe_table_register(devlink, table_name, table_ops, priv, - counter_control_extern); - devl_unlock(devlink); - return err; -} -EXPORT_SYMBOL_GPL(devlink_dpipe_table_register); - /** * devl_dpipe_table_unregister - unregister dpipe table * @@ -10631,23 +10569,6 @@ void devl_dpipe_table_unregister(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister); -/** - * devlink_dpipe_table_unregister - unregister dpipe table - * - * @devlink: devlink - * @table_name: table name - * - * Context: Takes and release devlink->lock . - */ -void devlink_dpipe_table_unregister(struct devlink *devlink, - const char *table_name) -{ - devl_lock(devlink); - devl_dpipe_table_unregister(devlink, table_name); - devl_unlock(devlink); -} -EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); - /** * devl_resource_register - devlink resource register * @@ -10820,28 +10741,6 @@ int devl_resource_size_get(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_resource_size_get); -/** - * devlink_resource_size_get - get and update size - * - * @devlink: devlink - * @resource_id: the requested resource id - * @p_resource_size: ptr to update - * - * Context: Takes and release devlink->lock . - */ -int devlink_resource_size_get(struct devlink *devlink, - u64 resource_id, - u64 *p_resource_size) -{ - int err; - - devl_lock(devlink); - err = devl_resource_size_get(devlink, resource_id, p_resource_size); - devl_unlock(devlink); - return err; -} -EXPORT_SYMBOL_GPL(devlink_resource_size_get); - /** * devl_dpipe_table_resource_set - set the resource id * @@ -10868,30 +10767,6 @@ int devl_dpipe_table_resource_set(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set); -/** - * devlink_dpipe_table_resource_set - set the resource id - * - * @devlink: devlink - * @table_name: table name - * @resource_id: resource id - * @resource_units: number of resource's units consumed per table's entry - * - * Context: Takes and release devlink->lock . - */ -int devlink_dpipe_table_resource_set(struct devlink *devlink, - const char *table_name, u64 resource_id, - u64 resource_units) -{ - int err; - - devl_lock(devlink); - err = devl_dpipe_table_resource_set(devlink, table_name, - resource_id, resource_units); - devl_unlock(devlink); - return err; -} -EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set); - /** * devl_resource_occ_get_register - register occupancy getter * @@ -12262,30 +12137,6 @@ err_trap_policer_verify: } EXPORT_SYMBOL_GPL(devl_trap_policers_register); -/** - * devlink_trap_policers_register - Register packet trap policers with devlink. - * @devlink: devlink. - * @policers: Packet trap policers. - * @policers_count: Count of provided packet trap policers. - * - * Return: Non-zero value on failure. - * - * Context: Takes and release devlink->lock . - */ -int -devlink_trap_policers_register(struct devlink *devlink, - const struct devlink_trap_policer *policers, - size_t policers_count) -{ - int err; - - devl_lock(devlink); - err = devl_trap_policers_register(devlink, policers, policers_count); - devl_unlock(devlink); - return err; -} -EXPORT_SYMBOL_GPL(devlink_trap_policers_register); - /** * devl_trap_policers_unregister - Unregister packet trap policers from devlink. * @devlink: devlink. @@ -12305,25 +12156,6 @@ devl_trap_policers_unregister(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devl_trap_policers_unregister); -/** - * devlink_trap_policers_unregister - Unregister packet trap policers from devlink. - * @devlink: devlink. - * @policers: Packet trap policers. - * @policers_count: Count of provided packet trap policers. - * - * Context: Takes and release devlink->lock . - */ -void -devlink_trap_policers_unregister(struct devlink *devlink, - const struct devlink_trap_policer *policers, - size_t policers_count) -{ - devl_lock(devlink); - devl_trap_policers_unregister(devlink, policers, policers_count); - devl_unlock(devlink); -} -EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister); - static void __devlink_compat_running_version(struct devlink *devlink, char *buf, size_t len) { -- cgit v1.2.3 From ca0cab11928870701535fbc3e49a4b196f722743 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 18 Jul 2022 10:55:12 +0200 Subject: net/sched: remove qdisc_root_lock() helper the last caller has been removed with commit 96f5e66e8a79 ("mac80211: fix aggregation for hardware with ampdu queues"), so it's safe to remove this function. Signed-off-by: Davide Caratti Link: https://lore.kernel.org/r/703d549e3088367651d92a059743f1be848d74b7.1658133689.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski --- include/net/sch_generic.h | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'include/net') diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index d6cf5116b5f9..ec693fe7c553 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -551,25 +551,6 @@ static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc) return qdisc->dev_queue->qdisc_sleeping; } -/* The qdisc root lock is a mechanism by which to top level - * of a qdisc tree can be locked from any qdisc node in the - * forest. This allows changing the configuration of some - * aspect of the qdisc tree while blocking out asynchronous - * qdisc access in the packet processing paths. - * - * It is only legal to do this when the root will not change - * on us. Otherwise we'll potentially lock the wrong qdisc - * root. This is enforced by holding the RTNL semaphore, which - * all users of this lock accessor must do. - */ -static inline spinlock_t *qdisc_root_lock(const struct Qdisc *qdisc) -{ - struct Qdisc *root = qdisc_root(qdisc); - - ASSERT_RTNL(); - return qdisc_lock(root); -} - static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc) { struct Qdisc *root = qdisc_root_sleeping(qdisc); -- cgit v1.2.3 From 877afadad2dce8aae1f2aad8ce47e072d4f6165e Mon Sep 17 00:00:00 2001 From: Schspa Shi Date: Fri, 3 Jun 2022 16:19:14 +0800 Subject: Bluetooth: When HCI work queue is drained, only queue chained work The HCI command, event, and data packet processing workqueue is drained to avoid deadlock in commit 76727c02c1e1 ("Bluetooth: Call drain_workqueue() before resetting state"). There is another delayed work, which will queue command to this drained workqueue. Which results in the following error report: Bluetooth: hci2: command 0x040f tx timeout WARNING: CPU: 1 PID: 18374 at kernel/workqueue.c:1438 __queue_work+0xdad/0x1140 Workqueue: events hci_cmd_timeout RIP: 0010:__queue_work+0xdad/0x1140 RSP: 0000:ffffc90002cffc60 EFLAGS: 00010093 RAX: 0000000000000000 RBX: ffff8880b9d3ec00 RCX: 0000000000000000 RDX: ffff888024ba0000 RSI: ffffffff814e048d RDI: ffff8880b9d3ec08 RBP: 0000000000000008 R08: 0000000000000000 R09: 00000000b9d39700 R10: ffffffff814f73c6 R11: 0000000000000000 R12: ffff88807cce4c60 R13: 0000000000000000 R14: ffff8880796d8800 R15: ffff8880796d8800 FS: 0000000000000000(0000) GS:ffff8880b9d00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000c0174b4000 CR3: 000000007cae9000 CR4: 00000000003506e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ? queue_work_on+0xcb/0x110 ? lockdep_hardirqs_off+0x90/0xd0 queue_work_on+0xee/0x110 process_one_work+0x996/0x1610 ? pwq_dec_nr_in_flight+0x2a0/0x2a0 ? rwlock_bug.part.0+0x90/0x90 ? _raw_spin_lock_irq+0x41/0x50 worker_thread+0x665/0x1080 ? process_one_work+0x1610/0x1610 kthread+0x2e9/0x3a0 ? kthread_complete_and_exit+0x40/0x40 ret_from_fork+0x1f/0x30 To fix this, we can add a new HCI_DRAIN_WQ flag, and don't queue the timeout workqueue while command workqueue is draining. Fixes: 76727c02c1e1 ("Bluetooth: Call drain_workqueue() before resetting state") Reported-by: syzbot+63bed493aebbf6872647@syzkaller.appspotmail.com Signed-off-by: Schspa Shi Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 10 +++++++++- net/bluetooth/hci_event.c | 5 +++-- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index fe7935be7dc4..4a45c48eb0d2 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -361,6 +361,7 @@ enum { HCI_QUALITY_REPORT, HCI_OFFLOAD_CODECS_ENABLED, HCI_LE_SIMULTANEOUS_ROLES, + HCI_CMD_DRAIN_WORKQUEUE, __HCI_NUM_FLAGS, }; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a0f99baafd35..6a53bcc5cfbb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -594,6 +594,11 @@ static int hci_dev_do_reset(struct hci_dev *hdev) skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); + /* Cancel these to avoid queueing non-chained pending work */ + hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + cancel_delayed_work(&hdev->cmd_timer); + cancel_delayed_work(&hdev->ncmd_timer); + /* Avoid potential lockdep warnings from the *_flush() calls by * ensuring the workqueue is empty up front. */ @@ -607,6 +612,8 @@ static int hci_dev_do_reset(struct hci_dev *hdev) if (hdev->flush) hdev->flush(hdev); + hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); + atomic_set(&hdev->cmd_cnt, 1); hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; @@ -3864,7 +3871,8 @@ static void hci_cmd_work(struct work_struct *work) if (res < 0) __hci_cmd_sync_cancel(hdev, -res); - if (test_bit(HCI_RESET, &hdev->flags)) + if (test_bit(HCI_RESET, &hdev->flags) || + hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) cancel_delayed_work(&hdev->cmd_timer); else schedule_delayed_work(&hdev->cmd_timer, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 63585c0bb9ce..34bec7446d00 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3768,8 +3768,9 @@ static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev, u8 ncmd) cancel_delayed_work(&hdev->ncmd_timer); atomic_set(&hdev->cmd_cnt, 1); } else { - schedule_delayed_work(&hdev->ncmd_timer, - HCI_NCMD_TIMEOUT); + if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) + schedule_delayed_work(&hdev->ncmd_timer, + HCI_NCMD_TIMEOUT); } } } -- cgit v1.2.3 From 359ee4f834f5b4f8096f7edc0c20ef37d1fca861 Mon Sep 17 00:00:00 2001 From: Abhishek Pandit-Subedi Date: Thu, 2 Jun 2022 09:46:50 -0700 Subject: Bluetooth: Unregister suspend with userchannel When HCI_USERCHANNEL is used, unregister the suspend notifier when binding and register when releasing. The userchannel socket should be left alone after open is completed. Signed-off-by: Abhishek Pandit-Subedi Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 33 +++++++++++++++++++++++++-------- net/bluetooth/hci_sock.c | 3 +++ 3 files changed, 30 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c0ea2a4892b1..ae689bc7122e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1286,6 +1286,8 @@ void hci_free_dev(struct hci_dev *hdev); int hci_register_dev(struct hci_dev *hdev); void hci_unregister_dev(struct hci_dev *hdev); void hci_release_dev(struct hci_dev *hdev); +int hci_register_suspend_notifier(struct hci_dev *hdev); +int hci_unregister_suspend_notifier(struct hci_dev *hdev); int hci_suspend_dev(struct hci_dev *hdev); int hci_resume_dev(struct hci_dev *hdev); int hci_reset_dev(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6a53bcc5cfbb..1ace311cdea9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2647,12 +2647,8 @@ int hci_register_dev(struct hci_dev *hdev) hci_sock_dev_event(hdev, HCI_DEV_REG); hci_dev_hold(hdev); - if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) { - hdev->suspend_notifier.notifier_call = hci_suspend_notifier; - error = register_pm_notifier(&hdev->suspend_notifier); - if (error) - goto err_wqueue; - } + if (hci_register_suspend_notifier(hdev)) + goto err_wqueue; queue_work(hdev->req_workqueue, &hdev->power_on); @@ -2687,8 +2683,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_cmd_sync_clear(hdev); - if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) - unregister_pm_notifier(&hdev->suspend_notifier); + hci_unregister_suspend_notifier(hdev); msft_unregister(hdev); @@ -2752,6 +2747,28 @@ void hci_release_dev(struct hci_dev *hdev) } EXPORT_SYMBOL(hci_release_dev); +int hci_register_suspend_notifier(struct hci_dev *hdev) +{ + int ret = 0; + + if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) { + hdev->suspend_notifier.notifier_call = hci_suspend_notifier; + ret = register_pm_notifier(&hdev->suspend_notifier); + } + + return ret; +} + +int hci_unregister_suspend_notifier(struct hci_dev *hdev) +{ + int ret = 0; + + if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) + ret = unregister_pm_notifier(&hdev->suspend_notifier); + + return ret; +} + /* Suspend HCI device */ int hci_suspend_dev(struct hci_dev *hdev) { diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index bd8358b44aa4..0d015d4a8e41 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -887,6 +887,7 @@ static int hci_sock_release(struct socket *sock) */ hci_dev_do_close(hdev); hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); + hci_register_suspend_notifier(hdev); mgmt_index_added(hdev); } @@ -1215,6 +1216,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, } mgmt_index_removed(hdev); + hci_unregister_suspend_notifier(hdev); err = hci_dev_open(hdev->id); if (err) { @@ -1229,6 +1231,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, err = 0; } else { hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); + hci_register_suspend_notifier(hdev); mgmt_index_added(hdev); hci_dev_put(hdev); goto done; -- cgit v1.2.3 From 34a718bc86f908de8ef79affaff6a3de7b95759c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 8 Jun 2022 15:00:01 -0700 Subject: Bluetooth: HCI: Fix not always setting Scan Response/Advertising Data The scan response and advertising data needs to be tracked on a per instance (adv_info) since when these instaces are removed so are their data, to fix that new flags are introduced which is used to mark when the data changes and then checked to confirm when the data needs to be synced with the controller. Tested-by: Tedd Ho-Jeong An Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 11 +++++++ net/bluetooth/hci_core.c | 42 ++++++++++++------------- net/bluetooth/hci_sync.c | 66 +++++++++++++++++++++++++++------------- 3 files changed, 76 insertions(+), 43 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ae689bc7122e..6d32e3e942b7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -243,8 +243,10 @@ struct adv_info { __u16 duration; __u16 adv_data_len; __u8 adv_data[HCI_MAX_EXT_AD_LENGTH]; + bool adv_data_changed; __u16 scan_rsp_len; __u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH]; + bool scan_rsp_changed; __s8 tx_power; __u32 min_interval; __u32 max_interval; @@ -258,6 +260,15 @@ struct adv_info { #define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F +#define DATA_CMP(_d1, _l1, _d2, _l2) \ + (_l1 == _l2 ? memcmp(_d1, _d2, _l1) : _l1 - _l2) + +#define ADV_DATA_CMP(_adv, _data, _len) \ + DATA_CMP((_adv)->adv_data, (_adv)->adv_data_len, _data, _len) + +#define SCAN_RSP_CMP(_adv, _data, _len) \ + DATA_CMP((_adv)->scan_rsp_data, (_adv)->scan_rsp_len, _data, _len) + struct monitored_device { struct list_head list; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 94f38f669932..72df3425725f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1728,18 +1728,12 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, } adv_instance->flags = flags; - adv_instance->adv_data_len = adv_data_len; - adv_instance->scan_rsp_len = scan_rsp_len; adv_instance->min_interval = min_interval; adv_instance->max_interval = max_interval; adv_instance->tx_power = tx_power; - if (adv_data_len) - memcpy(adv_instance->adv_data, adv_data, adv_data_len); - - if (scan_rsp_len) - memcpy(adv_instance->scan_rsp_data, - scan_rsp_data, scan_rsp_len); + hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data, + scan_rsp_len, scan_rsp_data); adv_instance->timeout = timeout; adv_instance->remaining_time = timeout; @@ -1762,29 +1756,33 @@ int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data) { - struct adv_info *adv_instance; + struct adv_info *adv; - adv_instance = hci_find_adv_instance(hdev, instance); + adv = hci_find_adv_instance(hdev, instance); /* If advertisement doesn't exist, we can't modify its data */ - if (!adv_instance) + if (!adv) return -ENOENT; - if (adv_data_len) { - memset(adv_instance->adv_data, 0, - sizeof(adv_instance->adv_data)); - memcpy(adv_instance->adv_data, adv_data, adv_data_len); - adv_instance->adv_data_len = adv_data_len; + if (adv_data_len && ADV_DATA_CMP(adv, adv_data, adv_data_len)) { + memset(adv->adv_data, 0, sizeof(adv->adv_data)); + memcpy(adv->adv_data, adv_data, adv_data_len); + adv->adv_data_len = adv_data_len; + adv->adv_data_changed = true; } - if (scan_rsp_len) { - memset(adv_instance->scan_rsp_data, 0, - sizeof(adv_instance->scan_rsp_data)); - memcpy(adv_instance->scan_rsp_data, - scan_rsp_data, scan_rsp_len); - adv_instance->scan_rsp_len = scan_rsp_len; + if (scan_rsp_len && SCAN_RSP_CMP(adv, scan_rsp_data, scan_rsp_len)) { + memset(adv->scan_rsp_data, 0, sizeof(adv->scan_rsp_data)); + memcpy(adv->scan_rsp_data, scan_rsp_data, scan_rsp_len); + adv->scan_rsp_len = scan_rsp_len; + adv->scan_rsp_changed = true; } + /* Mark as changed if there are flags which would affect it */ + if (((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) || + adv->flags & MGMT_ADV_FLAG_LOCAL_NAME) + adv->scan_rsp_changed = true; + return 0; } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 1739e8cb3291..a727f16914e4 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -849,26 +849,38 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance) u8 data[HCI_MAX_EXT_AD_LENGTH]; } pdu; u8 len; + struct adv_info *adv = NULL; + int err; memset(&pdu, 0, sizeof(pdu)); - len = eir_create_scan_rsp(hdev, instance, pdu.data); - - if (hdev->scan_rsp_data_len == len && - !memcmp(pdu.data, hdev->scan_rsp_data, len)) - return 0; + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + if (!adv || !adv->scan_rsp_changed) + return 0; + } - memcpy(hdev->scan_rsp_data, pdu.data, len); - hdev->scan_rsp_data_len = len; + len = eir_create_scan_rsp(hdev, instance, pdu.data); pdu.cp.handle = instance; pdu.cp.length = len; pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; - return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, - sizeof(pdu.cp) + len, &pdu.cp, - HCI_CMD_TIMEOUT); + err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, + sizeof(pdu.cp) + len, &pdu.cp, + HCI_CMD_TIMEOUT); + if (err) + return err; + + if (adv) { + adv->scan_rsp_changed = false; + } else { + memcpy(hdev->scan_rsp_data, pdu.data, len); + hdev->scan_rsp_data_len = len; + } + + return 0; } static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance) @@ -1119,27 +1131,39 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance) u8 data[HCI_MAX_EXT_AD_LENGTH]; } pdu; u8 len; + struct adv_info *adv = NULL; + int err; memset(&pdu, 0, sizeof(pdu)); - len = eir_create_adv_data(hdev, instance, pdu.data); - - /* There's nothing to do if the data hasn't changed */ - if (hdev->adv_data_len == len && - memcmp(pdu.data, hdev->adv_data, len) == 0) - return 0; + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + if (!adv || !adv->adv_data_changed) + return 0; + } - memcpy(hdev->adv_data, pdu.data, len); - hdev->adv_data_len = len; + len = eir_create_adv_data(hdev, instance, pdu.data); pdu.cp.length = len; pdu.cp.handle = instance; pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; - return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA, - sizeof(pdu.cp) + len, &pdu.cp, - HCI_CMD_TIMEOUT); + err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA, + sizeof(pdu.cp) + len, &pdu.cp, + HCI_CMD_TIMEOUT); + if (err) + return err; + + /* Update data if the command succeed */ + if (adv) { + adv->adv_data_changed = false; + } else { + memcpy(hdev->adv_data, pdu.data, len); + hdev->adv_data_len = len; + } + + return 0; } static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance) -- cgit v1.2.3 From 6f43f6169a8229bb6ddbf483d3be760d48c4cdd1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 20 Jul 2022 14:23:49 +0300 Subject: Bluetooth: clean up error pointer checking The bt_skb_sendmsg() function can't return NULL so there is no need to check for that. Several of these checks were removed previously but this one was missed. Signed-off-by: Dan Carpenter Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 6b48d9e2aab9..a8b52175af05 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -494,7 +494,7 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk, struct sk_buff *skb, **frag; skb = bt_skb_sendmsg(sk, msg, len, mtu, headroom, tailroom); - if (IS_ERR_OR_NULL(skb)) + if (IS_ERR(skb)) return skb; len -= skb->len; -- cgit v1.2.3 From 766ae2422b4312a73510ebee9266bc23b466fbbb Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Thu, 21 Jul 2022 14:04:30 +0800 Subject: Bluetooth: hci_sync: Check LMP feature bit instead of quirk BT core driver should addtionally check LMP feature bit "Erroneous Data Reporting" instead of quirk HCI_QUIRK_BROKEN_ERR_DATA_REPORTING set by BT device driver to decide if HCI commands HCI_Read|Write_Default_Erroneous_Data_Reporting are broken. BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 2, Part C | page 587 This feature indicates whether the device is able to support the Packet_Status_Flag and the HCI commands HCI_Write_Default_- Erroneous_Data_Reporting and HCI_Read_Default_Erroneous_- Data_Reporting. the quirk was introduced by 'commit cde1a8a99287 ("Bluetooth: btusb: Fix and detect most of the Chinese Bluetooth controllers")' to mark HCI commands HCI_Read|Write_Default_Erroneous_Data_Reporting broken by BT device driver, but the reason why these two HCI commands are broken is that feature "Erroneous Data Reporting" is not enabled by firmware, this scenario is illustrated by below log of QCA controllers with USB I/F: @ RAW Open: hcitool (privileged) version 2.22 < HCI Command: Read Local Supported Commands (0x04|0x0002) plen 0 > HCI Event: Command Complete (0x0e) plen 68 Read Local Supported Commands (0x04|0x0002) ncmd 1 Status: Success (0x00) Commands: 288 entries ...... Read Default Erroneous Data Reporting (Octet 18 - Bit 2) Write Default Erroneous Data Reporting (Octet 18 - Bit 3) ...... < HCI Command: Read Default Erroneous Data Reporting (0x03|0x005a) plen 0 > HCI Event: Command Complete (0x0e) plen 4 Read Default Erroneous Data Reporting (0x03|0x005a) ncmd 1 Status: Unknown HCI Command (0x01) < HCI Command: Read Local Supported Features (0x04|0x0003) plen 0 > HCI Event: Command Complete (0x0e) plen 12 Read Local Supported Features (0x04|0x0003) ncmd 1 Status: Success (0x00) Features: 0xff 0xfe 0x0f 0xfe 0xd8 0x3f 0x5b 0x87 3 slot packets ...... Signed-off-by: Zijun Hu Tested-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_sync.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4a45c48eb0d2..5cf0fbfb89b4 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -497,6 +497,7 @@ enum { #define LMP_EXT_INQ 0x01 #define LMP_SIMUL_LE_BR 0x02 #define LMP_SIMPLE_PAIR 0x08 +#define LMP_ERR_DATA_REPORTING 0x20 #define LMP_NO_FLUSH 0x40 #define LMP_LSTO 0x01 diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 49da90b6eecd..a6325f9ebfd2 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3221,7 +3221,7 @@ static int hci_read_page_scan_activity_sync(struct hci_dev *hdev) static int hci_read_def_err_data_reporting_sync(struct hci_dev *hdev) { if (!(hdev->commands[18] & 0x04) || - test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks)) + !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING)) return 0; return __hci_cmd_sync_status(hdev, HCI_OP_READ_DEF_ERR_DATA_REPORTING, @@ -3706,7 +3706,7 @@ static int hci_set_err_data_report_sync(struct hci_dev *hdev) bool enabled = hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED); if (!(hdev->commands[18] & 0x08) || - test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks)) + !(hdev->features[0][6] & LMP_ERR_DATA_REPORTING)) return 0; if (enabled == hdev->err_data_reporting) -- cgit v1.2.3 From 63b1a7dd38bfd4630e5f59a20a2b7b1f3d04f486 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Thu, 21 Jul 2022 14:04:33 +0800 Subject: Bluetooth: hci_sync: Remove HCI_QUIRK_BROKEN_ERR_DATA_REPORTING Core driver addtionally checks LMP feature bit "Erroneous Data Reporting" instead of quirk HCI_QUIRK_BROKEN_ERR_DATA_REPORTING to decide if HCI commands HCI_Read|Write_Default_Erroneous_Data_Reporting are broken, so remove this unnecessary quirk. Signed-off-by: Zijun Hu Tested-by: Zijun Hu Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci.h | 11 ----------- net/bluetooth/hci_sync.c | 3 --- 2 files changed, 14 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5cf0fbfb89b4..927f51b92854 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -228,17 +228,6 @@ enum { */ HCI_QUIRK_VALID_LE_STATES, - /* When this quirk is set, then erroneous data reporting - * is ignored. This is mainly due to the fact that the HCI - * Read Default Erroneous Data Reporting command is advertised, - * but not supported; these controllers often reply with unknown - * command and tend to lock up randomly. Needing a hard reset. - * - * This quirk can be set before hci_register_dev is called or - * during the hdev->setup vendor callback. - */ - HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, - /* * When this quirk is set, then the hci_suspend_notifier is not * registered. This is intended for devices which drop completely diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index a6325f9ebfd2..e793305beb67 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3865,9 +3865,6 @@ static const struct { HCI_QUIRK_BROKEN(STORED_LINK_KEY, "HCI Delete Stored Link Key command is advertised, " "but not supported."), - HCI_QUIRK_BROKEN(ERR_DATA_REPORTING, - "HCI Read Default Erroneous Data Reporting command is " - "advertised, but not supported."), HCI_QUIRK_BROKEN(READ_TRANSMIT_POWER, "HCI Read Transmit Power Level command is advertised, " "but not supported."), -- cgit v1.2.3 From b747a83690c8f53bc7a3f75899415c699b2c51aa Mon Sep 17 00:00:00 2001 From: Manish Mandlik Date: Wed, 20 Jul 2022 16:21:13 -0700 Subject: Bluetooth: hci_sync: Refactor add Adv Monitor Make use of hci_cmd_sync_queue for adding an advertisement monitor. Signed-off-by: Manish Mandlik Reviewed-by: Miao-chen Chou Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 5 +- net/bluetooth/hci_core.c | 46 +++++------ net/bluetooth/mgmt.c | 52 ++++-------- net/bluetooth/msft.c | 171 +++++++++------------------------------ 4 files changed, 78 insertions(+), 196 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6d32e3e942b7..b45d31285961 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1420,10 +1420,8 @@ bool hci_adv_instance_is_scannable(struct hci_dev *hdev, u8 instance); void hci_adv_monitors_clear(struct hci_dev *hdev); void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); -int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); -bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, - int *err); +int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err); bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err); bool hci_is_adv_monitoring(struct hci_dev *hdev); @@ -1885,7 +1883,6 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); -int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, bdaddr_t *bdaddr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d2c5f32d651b..6f9ce2f6f281 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1880,11 +1880,6 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) kfree(monitor); } -int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) -{ - return mgmt_add_adv_patterns_monitor_complete(hdev, status); -} - int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) { return mgmt_remove_adv_monitor_complete(hdev, status); @@ -1892,49 +1887,48 @@ int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) /* Assigns handle to a monitor, and if offloading is supported and power is on, * also attempts to forward the request to the controller. - * Returns true if request is forwarded (result is pending), false otherwise. - * This function requires the caller holds hdev->lock. + * This function requires the caller holds hci_req_sync_lock. */ -bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, - int *err) +int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) { int min, max, handle; + int status = 0; - *err = 0; + if (!monitor) + return -EINVAL; - if (!monitor) { - *err = -EINVAL; - return false; - } + hci_dev_lock(hdev); min = HCI_MIN_ADV_MONITOR_HANDLE; max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES; handle = idr_alloc(&hdev->adv_monitors_idr, monitor, min, max, GFP_KERNEL); - if (handle < 0) { - *err = handle; - return false; - } + + hci_dev_unlock(hdev); + + if (handle < 0) + return handle; monitor->handle = handle; if (!hdev_is_powered(hdev)) - return false; + return status; switch (hci_get_adv_monitor_offload_ext(hdev)) { case HCI_ADV_MONITOR_EXT_NONE: - hci_update_passive_scan(hdev); - bt_dev_dbg(hdev, "%s add monitor status %d", hdev->name, *err); + bt_dev_dbg(hdev, "%s add monitor %d status %d", hdev->name, + monitor->handle, status); /* Message was not forwarded to controller - not an error */ - return false; + break; + case HCI_ADV_MONITOR_EXT_MSFT: - *err = msft_add_monitor_pattern(hdev, monitor); - bt_dev_dbg(hdev, "%s add monitor msft status %d", hdev->name, - *err); + status = msft_add_monitor_pattern(hdev, monitor); + bt_dev_dbg(hdev, "%s add monitor %d msft status %d", hdev->name, + monitor->handle, status); break; } - return (*err == 0); + return status; } /* Attempts to tell the controller and free the monitor. If somehow the diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f3e4e2c9ec7a..e2d41dcf1031 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4646,23 +4646,15 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, return err; } -int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) +static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, + void *data, int status) { struct mgmt_rp_add_adv_patterns_monitor rp; - struct mgmt_pending_cmd *cmd; - struct adv_monitor *monitor; - int err = 0; + struct mgmt_pending_cmd *cmd = data; + struct adv_monitor *monitor = cmd->user_data; hci_dev_lock(hdev); - cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev); - if (!cmd) { - cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev); - if (!cmd) - goto done; - } - - monitor = cmd->user_data; rp.monitor_handle = cpu_to_le16(monitor->handle); if (!status) { @@ -4673,26 +4665,29 @@ int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status) hci_update_passive_scan(hdev); } - err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); -done: hci_dev_unlock(hdev); - bt_dev_dbg(hdev, "add monitor %d complete, status %u", + bt_dev_dbg(hdev, "add monitor %d complete, status %d", rp.monitor_handle, status); +} - return err; +static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data) +{ + struct mgmt_pending_cmd *cmd = data; + struct adv_monitor *monitor = cmd->user_data; + + return hci_add_adv_monitor(hdev, monitor); } static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, struct adv_monitor *m, u8 status, void *data, u16 len, u16 op) { - struct mgmt_rp_add_adv_patterns_monitor rp; struct mgmt_pending_cmd *cmd; int err; - bool pending; hci_dev_lock(hdev); @@ -4714,12 +4709,11 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, } cmd->user_data = m; - pending = hci_add_adv_monitor(hdev, m, &err); + err = hci_cmd_sync_queue(hdev, mgmt_add_adv_patterns_monitor_sync, cmd, + mgmt_add_adv_patterns_monitor_complete); if (err) { - if (err == -ENOSPC || err == -ENOMEM) + if (err == -ENOMEM) status = MGMT_STATUS_NO_RESOURCES; - else if (err == -EINVAL) - status = MGMT_STATUS_INVALID_PARAMS; else status = MGMT_STATUS_FAILED; @@ -4727,18 +4721,6 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (!pending) { - mgmt_pending_remove(cmd); - rp.monitor_handle = cpu_to_le16(m->handle); - mgmt_adv_monitor_added(sk, hdev, m->handle); - m->state = ADV_MONITOR_STATE_REGISTERED; - hdev->adv_monitors_cnt++; - - hci_dev_unlock(hdev); - return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS, - &rp, sizeof(rp)); - } - hci_dev_unlock(hdev); return 0; diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index f43994523b1f..54fbc718e893 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -99,15 +99,12 @@ struct msft_data { __u8 evt_prefix_len; __u8 *evt_prefix; struct list_head handle_map; - __u16 pending_add_handle; __u16 pending_remove_handle; __u8 resuming; __u8 suspending; __u8 filter_enabled; }; -static int __msft_add_monitor_pattern(struct hci_dev *hdev, - struct adv_monitor *monitor); static int __msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, u16 handle); @@ -164,34 +161,6 @@ failed: return false; } -static void reregister_monitor(struct hci_dev *hdev, int handle) -{ - struct adv_monitor *monitor; - struct msft_data *msft = hdev->msft_data; - int err; - - while (1) { - monitor = idr_get_next(&hdev->adv_monitors_idr, &handle); - if (!monitor) { - /* All monitors have been resumed */ - msft->resuming = false; - hci_update_passive_scan(hdev); - return; - } - - msft->pending_add_handle = (u16)handle; - err = __msft_add_monitor_pattern(hdev, monitor); - - /* If success, we return and wait for monitor added callback */ - if (!err) - return; - - /* Otherwise remove the monitor and keep registering */ - hci_free_adv_monitor(hdev, monitor); - handle++; - } -} - /* is_mgmt = true matches the handle exposed to userspace via mgmt. * is_mgmt = false matches the handle used by the msft controller. * This function requires the caller holds hdev->lock @@ -243,34 +212,27 @@ static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, return count; } -static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, - u8 status, u16 opcode, - struct sk_buff *skb) +static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode, + struct adv_monitor *monitor, + struct sk_buff *skb) { struct msft_rp_le_monitor_advertisement *rp; - struct adv_monitor *monitor; struct msft_monitor_advertisement_handle_data *handle_data; struct msft_data *msft = hdev->msft_data; + int status = 0; hci_dev_lock(hdev); - monitor = idr_find(&hdev->adv_monitors_idr, msft->pending_add_handle); - if (!monitor) { - bt_dev_err(hdev, "msft add advmon: monitor %u is not found!", - msft->pending_add_handle); + rp = (struct msft_rp_le_monitor_advertisement *)skb->data; + if (skb->len < sizeof(*rp)) { status = HCI_ERROR_UNSPECIFIED; goto unlock; } + status = rp->status; if (status) goto unlock; - rp = (struct msft_rp_le_monitor_advertisement *)skb->data; - if (skb->len < sizeof(*rp)) { - status = HCI_ERROR_UNSPECIFIED; - goto unlock; - } - handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL); if (!handle_data) { status = HCI_ERROR_UNSPECIFIED; @@ -285,13 +247,12 @@ static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, monitor->state = ADV_MONITOR_STATE_OFFLOADED; unlock: - if (status && monitor) + if (status) hci_free_adv_monitor(hdev, monitor); hci_dev_unlock(hdev); - if (!msft->resuming) - hci_add_adv_patterns_monitor_complete(hdev, status); + return status; } static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, @@ -463,7 +424,6 @@ static int msft_add_monitor_sync(struct hci_dev *hdev, ptrdiff_t offset = 0; u8 pattern_count = 0; struct sk_buff *skb; - u8 status; if (!msft_monitor_pattern_valid(monitor)) return -EINVAL; @@ -505,20 +465,40 @@ static int msft_add_monitor_sync(struct hci_dev *hdev, if (IS_ERR(skb)) return PTR_ERR(skb); - status = skb->data[0]; - skb_pull(skb, 1); + return msft_le_monitor_advertisement_cb(hdev, hdev->msft_opcode, + monitor, skb); +} - msft_le_monitor_advertisement_cb(hdev, status, hdev->msft_opcode, skb); +/* This function requires the caller holds hci_req_sync_lock */ +static void reregister_monitor(struct hci_dev *hdev) +{ + struct adv_monitor *monitor; + struct msft_data *msft = hdev->msft_data; + int handle = 0; - return status; + if (!msft) + return; + + msft->resuming = true; + + while (1) { + monitor = idr_get_next(&hdev->adv_monitors_idr, &handle); + if (!monitor) + break; + + msft_add_monitor_sync(hdev, monitor); + + handle++; + } + + /* All monitors have been reregistered */ + msft->resuming = false; } /* This function requires the caller holds hci_req_sync_lock */ int msft_resume_sync(struct hci_dev *hdev) { struct msft_data *msft = hdev->msft_data; - struct adv_monitor *monitor; - int handle = 0; if (!msft || !msft_monitor_supported(hdev)) return 0; @@ -533,24 +513,12 @@ int msft_resume_sync(struct hci_dev *hdev) hci_dev_unlock(hdev); - msft->resuming = true; - - while (1) { - monitor = idr_get_next(&hdev->adv_monitors_idr, &handle); - if (!monitor) - break; - - msft_add_monitor_sync(hdev, monitor); - - handle++; - } - - /* All monitors have been resumed */ - msft->resuming = false; + reregister_monitor(hdev); return 0; } +/* This function requires the caller holds hci_req_sync_lock */ void msft_do_open(struct hci_dev *hdev) { struct msft_data *msft = hdev->msft_data; @@ -583,7 +551,7 @@ void msft_do_open(struct hci_dev *hdev) /* Monitors get removed on power off, so we need to explicitly * tell the controller to re-monitor. */ - reregister_monitor(hdev, 0); + reregister_monitor(hdev); } } @@ -829,66 +797,7 @@ static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev, hci_dev_unlock(hdev); } -/* This function requires the caller holds hdev->lock */ -static int __msft_add_monitor_pattern(struct hci_dev *hdev, - struct adv_monitor *monitor) -{ - struct msft_cp_le_monitor_advertisement *cp; - struct msft_le_monitor_advertisement_pattern_data *pattern_data; - struct msft_le_monitor_advertisement_pattern *pattern; - struct adv_pattern *entry; - struct hci_request req; - struct msft_data *msft = hdev->msft_data; - size_t total_size = sizeof(*cp) + sizeof(*pattern_data); - ptrdiff_t offset = 0; - u8 pattern_count = 0; - int err = 0; - - if (!msft_monitor_pattern_valid(monitor)) - return -EINVAL; - - list_for_each_entry(entry, &monitor->patterns, list) { - pattern_count++; - total_size += sizeof(*pattern) + entry->length; - } - - cp = kmalloc(total_size, GFP_KERNEL); - if (!cp) - return -ENOMEM; - - cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT; - cp->rssi_high = monitor->rssi.high_threshold; - cp->rssi_low = monitor->rssi.low_threshold; - cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout; - cp->rssi_sampling_period = monitor->rssi.sampling_period; - - cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN; - - pattern_data = (void *)cp->data; - pattern_data->count = pattern_count; - - list_for_each_entry(entry, &monitor->patterns, list) { - pattern = (void *)(pattern_data->data + offset); - /* the length also includes data_type and offset */ - pattern->length = entry->length + 2; - pattern->data_type = entry->ad_type; - pattern->start_byte = entry->offset; - memcpy(pattern->pattern, entry->value, entry->length); - offset += sizeof(*pattern) + entry->length; - } - - hci_req_init(&req, hdev); - hci_req_add(&req, hdev->msft_opcode, total_size, cp); - err = hci_req_run_skb(&req, msft_le_monitor_advertisement_cb); - kfree(cp); - - if (!err) - msft->pending_add_handle = monitor->handle; - - return err; -} - -/* This function requires the caller holds hdev->lock */ +/* This function requires the caller holds hci_req_sync_lock */ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) { struct msft_data *msft = hdev->msft_data; @@ -899,7 +808,7 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) if (msft->resuming || msft->suspending) return -EBUSY; - return __msft_add_monitor_pattern(hdev, monitor); + return msft_add_monitor_sync(hdev, monitor); } /* This function requires the caller holds hdev->lock */ -- cgit v1.2.3 From 7cf5c2978f23fdbb2dd7b4e8b07e362ae2d8211c Mon Sep 17 00:00:00 2001 From: Manish Mandlik Date: Wed, 20 Jul 2022 16:21:14 -0700 Subject: Bluetooth: hci_sync: Refactor remove Adv Monitor Make use of hci_cmd_sync_queue for removing an advertisement monitor. Signed-off-by: Manish Mandlik Reviewed-by: Miao-chen Chou Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 6 +-- net/bluetooth/hci_core.c | 81 ++++++++++++--------------------- net/bluetooth/mgmt.c | 62 ++++++++++--------------- net/bluetooth/msft.c | 98 ++++++++-------------------------------- net/bluetooth/msft.h | 6 +-- 5 files changed, 75 insertions(+), 178 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b45d31285961..df7dac4a5bbd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1420,10 +1420,9 @@ bool hci_adv_instance_is_scannable(struct hci_dev *hdev, u8 instance); void hci_adv_monitors_clear(struct hci_dev *hdev); void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); -int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); -bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err); -bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err); +int hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle); +int hci_remove_all_adv_monitor(struct hci_dev *hdev); bool hci_is_adv_monitoring(struct hci_dev *hdev); int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev); @@ -1883,7 +1882,6 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); -int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, bdaddr_t *bdaddr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6f9ce2f6f281..e42824e82758 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1880,11 +1880,6 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) kfree(monitor); } -int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) -{ - return mgmt_remove_adv_monitor_complete(hdev, status); -} - /* Assigns handle to a monitor, and if offloading is supported and power is on, * also attempts to forward the request to the controller. * This function requires the caller holds hci_req_sync_lock. @@ -1933,92 +1928,72 @@ int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) /* Attempts to tell the controller and free the monitor. If somehow the * controller doesn't have a corresponding handle, remove anyway. - * Returns true if request is forwarded (result is pending), false otherwise. - * This function requires the caller holds hdev->lock. + * This function requires the caller holds hci_req_sync_lock. */ -static bool hci_remove_adv_monitor(struct hci_dev *hdev, - struct adv_monitor *monitor, - u16 handle, int *err) +static int hci_remove_adv_monitor(struct hci_dev *hdev, + struct adv_monitor *monitor) { - *err = 0; + int status = 0; switch (hci_get_adv_monitor_offload_ext(hdev)) { case HCI_ADV_MONITOR_EXT_NONE: /* also goes here when powered off */ + bt_dev_dbg(hdev, "%s remove monitor %d status %d", hdev->name, + monitor->handle, status); goto free_monitor; + case HCI_ADV_MONITOR_EXT_MSFT: - *err = msft_remove_monitor(hdev, monitor, handle); + status = msft_remove_monitor(hdev, monitor); + bt_dev_dbg(hdev, "%s remove monitor %d msft status %d", + hdev->name, monitor->handle, status); break; } /* In case no matching handle registered, just free the monitor */ - if (*err == -ENOENT) + if (status == -ENOENT) goto free_monitor; - return (*err == 0); + return status; free_monitor: - if (*err == -ENOENT) + if (status == -ENOENT) bt_dev_warn(hdev, "Removing monitor with no matching handle %d", monitor->handle); hci_free_adv_monitor(hdev, monitor); - *err = 0; - return false; + return status; } -/* Returns true if request is forwarded (result is pending), false otherwise. - * This function requires the caller holds hdev->lock. - */ -bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err) +/* This function requires the caller holds hci_req_sync_lock */ +int hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle) { struct adv_monitor *monitor = idr_find(&hdev->adv_monitors_idr, handle); - bool pending; - - if (!monitor) { - *err = -EINVAL; - return false; - } - - pending = hci_remove_adv_monitor(hdev, monitor, handle, err); - if (!*err && !pending) - hci_update_passive_scan(hdev); - bt_dev_dbg(hdev, "%s remove monitor handle %d, status %d, %spending", - hdev->name, handle, *err, pending ? "" : "not "); + if (!monitor) + return -EINVAL; - return pending; + return hci_remove_adv_monitor(hdev, monitor); } -/* Returns true if request is forwarded (result is pending), false otherwise. - * This function requires the caller holds hdev->lock. - */ -bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err) +/* This function requires the caller holds hci_req_sync_lock */ +int hci_remove_all_adv_monitor(struct hci_dev *hdev) { struct adv_monitor *monitor; int idr_next_id = 0; - bool pending = false; - bool update = false; - - *err = 0; + int status = 0; - while (!*err && !pending) { + while (1) { monitor = idr_get_next(&hdev->adv_monitors_idr, &idr_next_id); if (!monitor) break; - pending = hci_remove_adv_monitor(hdev, monitor, 0, err); + status = hci_remove_adv_monitor(hdev, monitor); + if (status) + return status; - if (!*err && !pending) - update = true; + idr_next_id++; } - if (update) - hci_update_passive_scan(hdev); - - bt_dev_dbg(hdev, "%s remove all monitors status %d, %spending", - hdev->name, *err, pending ? "" : "not "); - - return pending; + return status; } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e2d41dcf1031..05a680a56127 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4861,49 +4861,46 @@ done: MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI); } -int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status) +static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, + void *data, int status) { struct mgmt_rp_remove_adv_monitor rp; - struct mgmt_cp_remove_adv_monitor *cp; - struct mgmt_pending_cmd *cmd; - int err = 0; + struct mgmt_pending_cmd *cmd = data; + struct mgmt_cp_remove_adv_monitor *cp = cmd->param; hci_dev_lock(hdev); - cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); - if (!cmd) - goto done; - - cp = cmd->param; rp.monitor_handle = cp->monitor_handle; if (!status) hci_update_passive_scan(hdev); - err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); -done: hci_dev_unlock(hdev); - bt_dev_dbg(hdev, "remove monitor %d complete, status %u", + bt_dev_dbg(hdev, "remove monitor %d complete, status %d", rp.monitor_handle, status); +} - return err; +static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data) +{ + struct mgmt_pending_cmd *cmd = data; + struct mgmt_cp_remove_adv_monitor *cp = cmd->param; + u16 handle = __le16_to_cpu(cp->monitor_handle); + + if (!handle) + return hci_remove_all_adv_monitor(hdev); + + return hci_remove_single_adv_monitor(hdev, handle); } static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct mgmt_cp_remove_adv_monitor *cp = data; - struct mgmt_rp_remove_adv_monitor rp; struct mgmt_pending_cmd *cmd; - u16 handle = __le16_to_cpu(cp->monitor_handle); int err, status; - bool pending; - - BT_DBG("request for %s", hdev->name); - rp.monitor_handle = cp->monitor_handle; hci_dev_lock(hdev); @@ -4921,34 +4918,23 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (handle) - pending = hci_remove_single_adv_monitor(hdev, handle, &err); - else - pending = hci_remove_all_adv_monitor(hdev, &err); + err = hci_cmd_sync_queue(hdev, mgmt_remove_adv_monitor_sync, cmd, + mgmt_remove_adv_monitor_complete); if (err) { mgmt_pending_remove(cmd); - if (err == -ENOENT) - status = MGMT_STATUS_INVALID_INDEX; + if (err == -ENOMEM) + status = MGMT_STATUS_NO_RESOURCES; else status = MGMT_STATUS_FAILED; - goto unlock; - } - - /* monitor can be removed without forwarding request to controller */ - if (!pending) { mgmt_pending_remove(cmd); - hci_dev_unlock(hdev); - - return mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_REMOVE_ADV_MONITOR, - MGMT_STATUS_SUCCESS, - &rp, sizeof(rp)); + goto unlock; } hci_dev_unlock(hdev); + return 0; unlock: diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 54fbc718e893..14975769f678 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -99,15 +99,11 @@ struct msft_data { __u8 evt_prefix_len; __u8 *evt_prefix; struct list_head handle_map; - __u16 pending_remove_handle; __u8 resuming; __u8 suspending; __u8 filter_enabled; }; -static int __msft_remove_monitor(struct hci_dev *hdev, - struct adv_monitor *monitor, u16 handle); - bool msft_monitor_supported(struct hci_dev *hdev) { return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR); @@ -255,20 +251,15 @@ unlock: return status; } -static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, - u8 status, u16 opcode, - struct sk_buff *skb) +static int msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, + u16 opcode, + struct adv_monitor *monitor, + struct sk_buff *skb) { - struct msft_cp_le_cancel_monitor_advertisement *cp; struct msft_rp_le_cancel_monitor_advertisement *rp; - struct adv_monitor *monitor; struct msft_monitor_advertisement_handle_data *handle_data; struct msft_data *msft = hdev->msft_data; - int err; - bool pending; - - if (status) - goto done; + int status = 0; rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data; if (skb->len < sizeof(*rp)) { @@ -276,22 +267,22 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, goto done; } + status = rp->status; + if (status) + goto done; + hci_dev_lock(hdev); - cp = hci_sent_cmd_data(hdev, hdev->msft_opcode); - handle_data = msft_find_handle_data(hdev, cp->handle, false); + handle_data = msft_find_handle_data(hdev, monitor->handle, true); if (handle_data) { - monitor = idr_find(&hdev->adv_monitors_idr, - handle_data->mgmt_handle); - - if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED) + if (monitor->state == ADV_MONITOR_STATE_OFFLOADED) monitor->state = ADV_MONITOR_STATE_REGISTERED; /* Do not free the monitor if it is being removed due to * suspend. It will be re-monitored on resume. */ - if (monitor && !msft->suspending) { + if (!msft->suspending) { hci_free_adv_monitor(hdev, monitor); /* Clear any monitored devices by this Adv Monitor */ @@ -303,35 +294,19 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, kfree(handle_data); } - /* If remove all monitors is required, we need to continue the process - * here because the earlier it was paused when waiting for the - * response from controller. - */ - if (msft->pending_remove_handle == 0) { - pending = hci_remove_all_adv_monitor(hdev, &err); - if (pending) { - hci_dev_unlock(hdev); - return; - } - - if (err) - status = HCI_ERROR_UNSPECIFIED; - } - hci_dev_unlock(hdev); done: - if (!msft->suspending) - hci_remove_adv_monitor_complete(hdev, status); + return status; } +/* This function requires the caller holds hci_req_sync_lock */ static int msft_remove_monitor_sync(struct hci_dev *hdev, struct adv_monitor *monitor) { struct msft_cp_le_cancel_monitor_advertisement cp; struct msft_monitor_advertisement_handle_data *handle_data; struct sk_buff *skb; - u8 status; handle_data = msft_find_handle_data(hdev, monitor->handle, true); @@ -347,13 +322,8 @@ static int msft_remove_monitor_sync(struct hci_dev *hdev, if (IS_ERR(skb)) return PTR_ERR(skb); - status = skb->data[0]; - skb_pull(skb, 1); - - msft_le_cancel_monitor_advertisement_cb(hdev, status, hdev->msft_opcode, - skb); - - return status; + return msft_le_cancel_monitor_advertisement_cb(hdev, hdev->msft_opcode, + monitor, skb); } /* This function requires the caller holds hci_req_sync_lock */ @@ -811,38 +781,8 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor) return msft_add_monitor_sync(hdev, monitor); } -/* This function requires the caller holds hdev->lock */ -static int __msft_remove_monitor(struct hci_dev *hdev, - struct adv_monitor *monitor, u16 handle) -{ - struct msft_cp_le_cancel_monitor_advertisement cp; - struct msft_monitor_advertisement_handle_data *handle_data; - struct hci_request req; - struct msft_data *msft = hdev->msft_data; - int err = 0; - - handle_data = msft_find_handle_data(hdev, monitor->handle, true); - - /* If no matched handle, just remove without telling controller */ - if (!handle_data) - return -ENOENT; - - cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT; - cp.handle = handle_data->msft_handle; - - hci_req_init(&req, hdev); - hci_req_add(&req, hdev->msft_opcode, sizeof(cp), &cp); - err = hci_req_run_skb(&req, msft_le_cancel_monitor_advertisement_cb); - - if (!err) - msft->pending_remove_handle = handle; - - return err; -} - -/* This function requires the caller holds hdev->lock */ -int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, - u16 handle) +/* This function requires the caller holds hci_req_sync_lock */ +int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor) { struct msft_data *msft = hdev->msft_data; @@ -852,7 +792,7 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, if (msft->resuming || msft->suspending) return -EBUSY; - return __msft_remove_monitor(hdev, monitor, handle); + return msft_remove_monitor_sync(hdev, monitor); } void msft_req_add_set_filter_enable(struct hci_request *req, bool enable) diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h index afcaf7d3b1cb..2a63205b377b 100644 --- a/net/bluetooth/msft.h +++ b/net/bluetooth/msft.h @@ -20,8 +20,7 @@ void msft_do_close(struct hci_dev *hdev); void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb); __u64 msft_get_features(struct hci_dev *hdev); int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor); -int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, - u16 handle); +int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor); void msft_req_add_set_filter_enable(struct hci_request *req, bool enable); int msft_set_filter_enable(struct hci_dev *hdev, bool enable); int msft_suspend_sync(struct hci_dev *hdev); @@ -49,8 +48,7 @@ static inline int msft_add_monitor_pattern(struct hci_dev *hdev, } static inline int msft_remove_monitor(struct hci_dev *hdev, - struct adv_monitor *monitor, - u16 handle) + struct adv_monitor *monitor) { return -EOPNOTSUPP; } -- cgit v1.2.3 From ca2045e059c3aa1b06c9aed448672bc86dfdce11 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 8 Apr 2022 15:07:44 -0700 Subject: Bluetooth: Add bt_status This adds bt_status which can be used to convert Unix errno to Bluetooth status. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/lib.c | 71 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index a8b52175af05..686ce2591bb2 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -521,6 +521,7 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk, } int bt_to_errno(u16 code); +__u8 bt_status(int err); void hci_sock_set_flag(struct sock *sk, int nr); void hci_sock_clear_flag(struct sock *sk, int nr); diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 5326f41a58b7..469a0c95b6e8 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -135,6 +135,77 @@ int bt_to_errno(__u16 code) } EXPORT_SYMBOL(bt_to_errno); +/* Unix errno to Bluetooth error codes mapping */ +__u8 bt_status(int err) +{ + /* Don't convert if already positive value */ + if (err >= 0) + return err; + + switch (err) { + case -EBADRQC: + return 0x01; + + case -ENOTCONN: + return 0x02; + + case -EIO: + return 0x03; + + case -EHOSTDOWN: + return 0x04; + + case -EACCES: + return 0x05; + + case -EBADE: + return 0x06; + + case -ENOMEM: + return 0x07; + + case -ETIMEDOUT: + return 0x08; + + case -EMLINK: + return 0x09; + + case EALREADY: + return 0x0b; + + case -EBUSY: + return 0x0c; + + case -ECONNREFUSED: + return 0x0d; + + case -EOPNOTSUPP: + return 0x11; + + case -EINVAL: + return 0x12; + + case -ECONNRESET: + return 0x13; + + case -ECONNABORTED: + return 0x16; + + case ELOOP: + return 0x17; + + case -EPROTONOSUPPORT: + return 0x1a; + + case -EPROTO: + return 0x19; + + default: + return 0x1f; + } +} +EXPORT_SYMBOL(bt_status); + void bt_info(const char *format, ...) { struct va_format vaf; -- cgit v1.2.3 From 1f7435c8f6558a94f75b408a74140bdcbd0f6dd1 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 21 Jun 2022 11:58:34 -0700 Subject: Bluetooth: mgmt: Fix using hci_conn_abort This fixes using hci_conn_abort instead of using hci_conn_abort_sync. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_sync.h | 2 ++ net/bluetooth/hci_sync.c | 3 +-- net/bluetooth/mgmt.c | 38 +++++++++++++++++++++++++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 2492e3b46a8f..544e949b5dbf 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -105,4 +105,6 @@ int hci_resume_sync(struct hci_dev *hdev); struct hci_conn; +int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason); + int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 36a501959b6d..1fbeee970aa7 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -4489,8 +4489,7 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } -static int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, - u8 reason) +int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) { int err; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 05a680a56127..0c6878095709 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2528,6 +2528,37 @@ static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, skip_sk); } +static void unpair_device_complete(struct hci_dev *hdev, void *data, int err) +{ + struct mgmt_pending_cmd *cmd = data; + struct mgmt_cp_unpair_device *cp = cmd->param; + + if (!err) + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); + + cmd->cmd_complete(cmd, err); + mgmt_pending_free(cmd); +} + +static int unpair_device_sync(struct hci_dev *hdev, void *data) +{ + struct mgmt_pending_cmd *cmd = data; + struct mgmt_cp_unpair_device *cp = cmd->param; + struct hci_conn *conn; + + if (cp->addr.type == BDADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->addr.bdaddr); + else + conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr, + le_addr_type(cp->addr.type)); + + if (!conn) + return 0; + + return hci_abort_conn_sync(hdev, conn, HCI_ERROR_REMOTE_USER_TERM); +} + static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2638,7 +2669,7 @@ done: goto unlock; } - cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, + cmd = mgmt_pending_new(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, sizeof(*cp)); if (!cmd) { err = -ENOMEM; @@ -2647,9 +2678,10 @@ done: cmd->cmd_complete = addr_cmd_complete; - err = hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); + err = hci_cmd_sync_queue(hdev, unpair_device_sync, cmd, + unpair_device_complete); if (err < 0) - mgmt_pending_remove(cmd); + mgmt_pending_free(cmd); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From d7e79c97c00ca82dace0e3b645d4b3b02fa273c2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 21 Jul 2022 15:42:39 +0200 Subject: net: netfilter: Add kfuncs to allocate and insert CT Introduce bpf_xdp_ct_alloc, bpf_skb_ct_alloc and bpf_ct_insert_entry kfuncs in order to insert a new entry from XDP and TC programs. Introduce bpf_nf_ct_tuple_parse utility routine to consolidate common code. We extract out a helper __nf_ct_set_timeout, used by the ctnetlink and nf_conntrack_bpf code, extract it out to nf_conntrack_core, so that nf_conntrack_bpf doesn't need a dependency on CONFIG_NF_CT_NETLINK. Later this helper will be reused as a helper to set timeout of allocated but not yet inserted CT entry. The allocation functions return struct nf_conn___init instead of nf_conn, to distinguish allocated CT from an already inserted or looked up CT. This is later used to enforce restrictions on what kfuncs allocated CT can be used with. Signed-off-by: Lorenzo Bianconi Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20220721134245.2450-8-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- include/net/netfilter/nf_conntrack_core.h | 15 +++ net/netfilter/nf_conntrack_bpf.c | 208 +++++++++++++++++++++++++++--- net/netfilter/nf_conntrack_netlink.c | 8 +- 3 files changed, 204 insertions(+), 27 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 37866c8386e2..83a60c684e6c 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -84,4 +84,19 @@ void nf_conntrack_lock(spinlock_t *lock); extern spinlock_t nf_conntrack_expect_lock; +/* ctnetlink code shared by both ctnetlink and nf_conntrack_bpf */ + +#if (IS_BUILTIN(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \ + (IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES) || \ + IS_ENABLED(CONFIG_NF_CT_NETLINK)) + +static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout) +{ + if (timeout > INT_MAX) + timeout = INT_MAX; + WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout); +} + +#endif + #endif /* _NF_CONNTRACK_CORE_H */ diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c index 16304869264f..cac4a9558968 100644 --- a/net/netfilter/nf_conntrack_bpf.c +++ b/net/netfilter/nf_conntrack_bpf.c @@ -55,6 +55,94 @@ enum { NF_BPF_CT_OPTS_SZ = 12, }; +static int bpf_nf_ct_tuple_parse(struct bpf_sock_tuple *bpf_tuple, + u32 tuple_len, u8 protonum, u8 dir, + struct nf_conntrack_tuple *tuple) +{ + union nf_inet_addr *src = dir ? &tuple->dst.u3 : &tuple->src.u3; + union nf_inet_addr *dst = dir ? &tuple->src.u3 : &tuple->dst.u3; + union nf_conntrack_man_proto *sport = dir ? (void *)&tuple->dst.u + : &tuple->src.u; + union nf_conntrack_man_proto *dport = dir ? &tuple->src.u + : (void *)&tuple->dst.u; + + if (unlikely(protonum != IPPROTO_TCP && protonum != IPPROTO_UDP)) + return -EPROTO; + + memset(tuple, 0, sizeof(*tuple)); + + switch (tuple_len) { + case sizeof(bpf_tuple->ipv4): + tuple->src.l3num = AF_INET; + src->ip = bpf_tuple->ipv4.saddr; + sport->tcp.port = bpf_tuple->ipv4.sport; + dst->ip = bpf_tuple->ipv4.daddr; + dport->tcp.port = bpf_tuple->ipv4.dport; + break; + case sizeof(bpf_tuple->ipv6): + tuple->src.l3num = AF_INET6; + memcpy(src->ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr)); + sport->tcp.port = bpf_tuple->ipv6.sport; + memcpy(dst->ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr)); + dport->tcp.port = bpf_tuple->ipv6.dport; + break; + default: + return -EAFNOSUPPORT; + } + tuple->dst.protonum = protonum; + tuple->dst.dir = dir; + + return 0; +} + +static struct nf_conn * +__bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple, + u32 tuple_len, struct bpf_ct_opts *opts, u32 opts_len, + u32 timeout) +{ + struct nf_conntrack_tuple otuple, rtuple; + struct nf_conn *ct; + int err; + + if (!opts || !bpf_tuple || opts->reserved[0] || opts->reserved[1] || + opts_len != NF_BPF_CT_OPTS_SZ) + return ERR_PTR(-EINVAL); + + if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS)) + return ERR_PTR(-EINVAL); + + err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto, + IP_CT_DIR_ORIGINAL, &otuple); + if (err < 0) + return ERR_PTR(err); + + err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto, + IP_CT_DIR_REPLY, &rtuple); + if (err < 0) + return ERR_PTR(err); + + if (opts->netns_id >= 0) { + net = get_net_ns_by_id(net, opts->netns_id); + if (unlikely(!net)) + return ERR_PTR(-ENONET); + } + + ct = nf_conntrack_alloc(net, &nf_ct_zone_dflt, &otuple, &rtuple, + GFP_ATOMIC); + if (IS_ERR(ct)) + goto out; + + memset(&ct->proto, 0, sizeof(ct->proto)); + __nf_ct_set_timeout(ct, timeout * HZ); + ct->status |= IPS_CONFIRMED; + +out: + if (opts->netns_id >= 0) + put_net(net); + + return ct; +} + static struct nf_conn *__bpf_nf_ct_lookup(struct net *net, struct bpf_sock_tuple *bpf_tuple, u32 tuple_len, struct bpf_ct_opts *opts, @@ -63,6 +151,7 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net, struct nf_conntrack_tuple_hash *hash; struct nf_conntrack_tuple tuple; struct nf_conn *ct; + int err; if (!opts || !bpf_tuple || opts->reserved[0] || opts->reserved[1] || opts_len != NF_BPF_CT_OPTS_SZ) @@ -72,27 +161,10 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net, if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS)) return ERR_PTR(-EINVAL); - memset(&tuple, 0, sizeof(tuple)); - switch (tuple_len) { - case sizeof(bpf_tuple->ipv4): - tuple.src.l3num = AF_INET; - tuple.src.u3.ip = bpf_tuple->ipv4.saddr; - tuple.src.u.tcp.port = bpf_tuple->ipv4.sport; - tuple.dst.u3.ip = bpf_tuple->ipv4.daddr; - tuple.dst.u.tcp.port = bpf_tuple->ipv4.dport; - break; - case sizeof(bpf_tuple->ipv6): - tuple.src.l3num = AF_INET6; - memcpy(tuple.src.u3.ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr)); - tuple.src.u.tcp.port = bpf_tuple->ipv6.sport; - memcpy(tuple.dst.u3.ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr)); - tuple.dst.u.tcp.port = bpf_tuple->ipv6.dport; - break; - default: - return ERR_PTR(-EAFNOSUPPORT); - } - - tuple.dst.protonum = opts->l4proto; + err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto, + IP_CT_DIR_ORIGINAL, &tuple); + if (err < 0) + return ERR_PTR(err); if (opts->netns_id >= 0) { net = get_net_ns_by_id(net, opts->netns_id); @@ -116,6 +188,43 @@ __diag_push(); __diag_ignore_all("-Wmissing-prototypes", "Global functions as their definitions will be in nf_conntrack BTF"); +struct nf_conn___init { + struct nf_conn ct; +}; + +/* bpf_xdp_ct_alloc - Allocate a new CT entry + * + * Parameters: + * @xdp_ctx - Pointer to ctx (xdp_md) in XDP program + * Cannot be NULL + * @bpf_tuple - Pointer to memory representing the tuple to look up + * Cannot be NULL + * @tuple__sz - Length of the tuple structure + * Must be one of sizeof(bpf_tuple->ipv4) or + * sizeof(bpf_tuple->ipv6) + * @opts - Additional options for allocation (documented above) + * Cannot be NULL + * @opts__sz - Length of the bpf_ct_opts structure + * Must be NF_BPF_CT_OPTS_SZ (12) + */ +struct nf_conn___init * +bpf_xdp_ct_alloc(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple, + u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz) +{ + struct xdp_buff *ctx = (struct xdp_buff *)xdp_ctx; + struct nf_conn *nfct; + + nfct = __bpf_nf_ct_alloc_entry(dev_net(ctx->rxq->dev), bpf_tuple, tuple__sz, + opts, opts__sz, 10); + if (IS_ERR(nfct)) { + if (opts) + opts->error = PTR_ERR(nfct); + return NULL; + } + + return (struct nf_conn___init *)nfct; +} + /* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a * reference to it * @@ -150,6 +259,40 @@ bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple, return nfct; } +/* bpf_skb_ct_alloc - Allocate a new CT entry + * + * Parameters: + * @skb_ctx - Pointer to ctx (__sk_buff) in TC program + * Cannot be NULL + * @bpf_tuple - Pointer to memory representing the tuple to look up + * Cannot be NULL + * @tuple__sz - Length of the tuple structure + * Must be one of sizeof(bpf_tuple->ipv4) or + * sizeof(bpf_tuple->ipv6) + * @opts - Additional options for allocation (documented above) + * Cannot be NULL + * @opts__sz - Length of the bpf_ct_opts structure + * Must be NF_BPF_CT_OPTS_SZ (12) + */ +struct nf_conn___init * +bpf_skb_ct_alloc(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple, + u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz) +{ + struct sk_buff *skb = (struct sk_buff *)skb_ctx; + struct nf_conn *nfct; + struct net *net; + + net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk); + nfct = __bpf_nf_ct_alloc_entry(net, bpf_tuple, tuple__sz, opts, opts__sz, 10); + if (IS_ERR(nfct)) { + if (opts) + opts->error = PTR_ERR(nfct); + return NULL; + } + + return (struct nf_conn___init *)nfct; +} + /* bpf_skb_ct_lookup - Lookup CT entry for the given tuple, and acquire a * reference to it * @@ -184,6 +327,26 @@ bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple, return nfct; } +/* bpf_ct_insert_entry - Add the provided entry into a CT map + * + * This must be invoked for referenced PTR_TO_BTF_ID. + * + * @nfct__ref - Pointer to referenced nf_conn___init object, obtained + * using bpf_xdp_ct_alloc or bpf_skb_ct_alloc. + */ +struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct__ref) +{ + struct nf_conn *nfct = (struct nf_conn *)nfct__ref; + int err; + + err = nf_conntrack_hash_check_insert(nfct); + if (err < 0) { + nf_conntrack_free(nfct); + return NULL; + } + return nfct; +} + /* bpf_ct_release - Release acquired nf_conn object * * This must be invoked for referenced PTR_TO_BTF_ID, and the verifier rejects @@ -204,8 +367,11 @@ void bpf_ct_release(struct nf_conn *nfct) __diag_pop() BTF_SET8_START(nf_ct_kfunc_set) +BTF_ID_FLAGS(func, bpf_xdp_ct_alloc, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_xdp_ct_lookup, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_skb_ct_alloc, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_skb_ct_lookup, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_ct_insert_entry, KF_ACQUIRE | KF_RET_NULL | KF_RELEASE) BTF_ID_FLAGS(func, bpf_ct_release, KF_RELEASE) BTF_SET8_END(nf_ct_kfunc_set) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 722af5e309ba..0729b2f0d44f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2025,9 +2025,7 @@ static int ctnetlink_change_timeout(struct nf_conn *ct, { u64 timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ; - if (timeout > INT_MAX) - timeout = INT_MAX; - WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout); + __nf_ct_set_timeout(ct, timeout); if (test_bit(IPS_DYING_BIT, &ct->status)) return -ETIME; @@ -2292,9 +2290,7 @@ ctnetlink_create_conntrack(struct net *net, goto err1; timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ; - if (timeout > INT_MAX) - timeout = INT_MAX; - ct->timeout = (u32)timeout + nfct_time_stamp; + __nf_ct_set_timeout(ct, timeout); rcu_read_lock(); if (cda[CTA_HELP]) { -- cgit v1.2.3 From 0b3892364431684e883682b85d008979e08d4ce6 Mon Sep 17 00:00:00 2001 From: Kumar Kartikeya Dwivedi Date: Thu, 21 Jul 2022 15:42:40 +0200 Subject: net: netfilter: Add kfuncs to set and change CT timeout Introduce bpf_ct_set_timeout and bpf_ct_change_timeout kfunc helpers in order to change nf_conn timeout. This is same as ctnetlink_change_timeout, hence code is shared between both by extracting it out to __nf_ct_change_timeout. It is also updated to return an error when it sees IPS_FIXED_TIMEOUT_BIT bit in ct->status, as that check was missing. It is required to introduce two kfuncs taking nf_conn___init and nf_conn instead of sharing one because KF_TRUSTED_ARGS flag causes strict type checking. This would disallow passing nf_conn___init to kfunc taking nf_conn, and vice versa. We cannot remove the KF_TRUSTED_ARGS flag as we only want to accept refcounted pointers and not e.g. ct->master. Apart from this, bpf_ct_set_timeout is only called for newly allocated CT so it doesn't need to inspect the status field just yet. Sharing the helpers even if it was possible would make timeout setting helper sensitive to order of setting status and timeout after allocation. Hence, bpf_ct_set_* kfuncs are meant to be used on allocated CT, and bpf_ct_change_* kfuncs are meant to be used on inserted or looked up CT entry. Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20220721134245.2450-9-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- include/net/netfilter/nf_conntrack_core.h | 2 ++ net/netfilter/nf_conntrack_bpf.c | 38 ++++++++++++++++++++++++++++--- net/netfilter/nf_conntrack_core.c | 22 ++++++++++++++++++ net/netfilter/nf_conntrack_netlink.c | 9 +------- 4 files changed, 60 insertions(+), 11 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 83a60c684e6c..3b0f7d0eebae 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -97,6 +97,8 @@ static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout) WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout); } +int __nf_ct_change_timeout(struct nf_conn *ct, u64 cta_timeout); + #endif #endif /* _NF_CONNTRACK_CORE_H */ diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c index cac4a9558968..b8912e15082f 100644 --- a/net/netfilter/nf_conntrack_bpf.c +++ b/net/netfilter/nf_conntrack_bpf.c @@ -331,12 +331,12 @@ bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple, * * This must be invoked for referenced PTR_TO_BTF_ID. * - * @nfct__ref - Pointer to referenced nf_conn___init object, obtained + * @nfct - Pointer to referenced nf_conn___init object, obtained * using bpf_xdp_ct_alloc or bpf_skb_ct_alloc. */ -struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct__ref) +struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i) { - struct nf_conn *nfct = (struct nf_conn *)nfct__ref; + struct nf_conn *nfct = (struct nf_conn *)nfct_i; int err; err = nf_conntrack_hash_check_insert(nfct); @@ -364,6 +364,36 @@ void bpf_ct_release(struct nf_conn *nfct) nf_ct_put(nfct); } +/* bpf_ct_set_timeout - Set timeout of allocated nf_conn + * + * Sets the default timeout of newly allocated nf_conn before insertion. + * This helper must be invoked for refcounted pointer to nf_conn___init. + * + * Parameters: + * @nfct - Pointer to referenced nf_conn object, obtained using + * bpf_xdp_ct_alloc or bpf_skb_ct_alloc. + * @timeout - Timeout in msecs. + */ +void bpf_ct_set_timeout(struct nf_conn___init *nfct, u32 timeout) +{ + __nf_ct_set_timeout((struct nf_conn *)nfct, msecs_to_jiffies(timeout)); +} + +/* bpf_ct_change_timeout - Change timeout of inserted nf_conn + * + * Change timeout associated of the inserted or looked up nf_conn. + * This helper must be invoked for refcounted pointer to nf_conn. + * + * Parameters: + * @nfct - Pointer to referenced nf_conn object, obtained using + * bpf_ct_insert_entry, bpf_xdp_ct_lookup, or bpf_skb_ct_lookup. + * @timeout - New timeout in msecs. + */ +int bpf_ct_change_timeout(struct nf_conn *nfct, u32 timeout) +{ + return __nf_ct_change_timeout(nfct, msecs_to_jiffies(timeout)); +} + __diag_pop() BTF_SET8_START(nf_ct_kfunc_set) @@ -373,6 +403,8 @@ BTF_ID_FLAGS(func, bpf_skb_ct_alloc, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_skb_ct_lookup, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_ct_insert_entry, KF_ACQUIRE | KF_RET_NULL | KF_RELEASE) BTF_ID_FLAGS(func, bpf_ct_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_ct_set_timeout, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_ct_change_timeout, KF_TRUSTED_ARGS) BTF_SET8_END(nf_ct_kfunc_set) static const struct btf_kfunc_id_set nf_conntrack_kfunc_set = { diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 082a2fd8d85b..572f59a5e936 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -2786,3 +2786,25 @@ err_expect: free_percpu(net->ct.stat); return ret; } + +#if (IS_BUILTIN(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \ + (IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES) || \ + IS_ENABLED(CONFIG_NF_CT_NETLINK)) + +/* ctnetlink code shared by both ctnetlink and nf_conntrack_bpf */ + +int __nf_ct_change_timeout(struct nf_conn *ct, u64 timeout) +{ + if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) + return -EPERM; + + __nf_ct_set_timeout(ct, timeout); + + if (test_bit(IPS_DYING_BIT, &ct->status)) + return -ETIME; + + return 0; +} +EXPORT_SYMBOL_GPL(__nf_ct_change_timeout); + +#endif diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 0729b2f0d44f..b1de07c73845 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2023,14 +2023,7 @@ static int ctnetlink_change_helper(struct nf_conn *ct, static int ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) { - u64 timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ; - - __nf_ct_set_timeout(ct, timeout); - - if (test_bit(IPS_DYING_BIT, &ct->status)) - return -ETIME; - - return 0; + return __nf_ct_change_timeout(ct, (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ); } #if defined(CONFIG_NF_CONNTRACK_MARK) -- cgit v1.2.3 From ef69aa3a986ef94f01ce8b5b619f550db54432fe Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 21 Jul 2022 15:42:41 +0200 Subject: net: netfilter: Add kfuncs to set and change CT status Introduce bpf_ct_set_status and bpf_ct_change_status kfunc helpers in order to set nf_conn field of allocated entry or update nf_conn status field of existing inserted entry. Use nf_ct_change_status_common to share the permitted status field changes between netlink and BPF side by refactoring ctnetlink_change_status. It is required to introduce two kfuncs taking nf_conn___init and nf_conn instead of sharing one because KF_TRUSTED_ARGS flag causes strict type checking. This would disallow passing nf_conn___init to kfunc taking nf_conn, and vice versa. We cannot remove the KF_TRUSTED_ARGS flag as we only want to accept refcounted pointers and not e.g. ct->master. Hence, bpf_ct_set_* kfuncs are meant to be used on allocated CT, and bpf_ct_change_* kfuncs are meant to be used on inserted or looked up CT entry. Signed-off-by: Lorenzo Bianconi Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Link: https://lore.kernel.org/r/20220721134245.2450-10-memxor@gmail.com Signed-off-by: Alexei Starovoitov --- include/net/netfilter/nf_conntrack_core.h | 2 ++ net/netfilter/nf_conntrack_bpf.c | 32 +++++++++++++++++++++++++ net/netfilter/nf_conntrack_core.c | 40 +++++++++++++++++++++++++++++++ net/netfilter/nf_conntrack_netlink.c | 39 ++---------------------------- 4 files changed, 76 insertions(+), 37 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 3b0f7d0eebae..3cd3a6e631aa 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -98,6 +98,8 @@ static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout) } int __nf_ct_change_timeout(struct nf_conn *ct, u64 cta_timeout); +void __nf_ct_change_status(struct nf_conn *ct, unsigned long on, unsigned long off); +int nf_ct_change_status_common(struct nf_conn *ct, unsigned int status); #endif diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c index b8912e15082f..1cd87b28c9b0 100644 --- a/net/netfilter/nf_conntrack_bpf.c +++ b/net/netfilter/nf_conntrack_bpf.c @@ -394,6 +394,36 @@ int bpf_ct_change_timeout(struct nf_conn *nfct, u32 timeout) return __nf_ct_change_timeout(nfct, msecs_to_jiffies(timeout)); } +/* bpf_ct_set_status - Set status field of allocated nf_conn + * + * Set the status field of the newly allocated nf_conn before insertion. + * This must be invoked for referenced PTR_TO_BTF_ID to nf_conn___init. + * + * Parameters: + * @nfct - Pointer to referenced nf_conn object, obtained using + * bpf_xdp_ct_alloc or bpf_skb_ct_alloc. + * @status - New status value. + */ +int bpf_ct_set_status(const struct nf_conn___init *nfct, u32 status) +{ + return nf_ct_change_status_common((struct nf_conn *)nfct, status); +} + +/* bpf_ct_change_status - Change status of inserted nf_conn + * + * Change the status field of the provided connection tracking entry. + * This must be invoked for referenced PTR_TO_BTF_ID to nf_conn. + * + * Parameters: + * @nfct - Pointer to referenced nf_conn object, obtained using + * bpf_ct_insert_entry, bpf_xdp_ct_lookup or bpf_skb_ct_lookup. + * @status - New status value. + */ +int bpf_ct_change_status(struct nf_conn *nfct, u32 status) +{ + return nf_ct_change_status_common(nfct, status); +} + __diag_pop() BTF_SET8_START(nf_ct_kfunc_set) @@ -405,6 +435,8 @@ BTF_ID_FLAGS(func, bpf_ct_insert_entry, KF_ACQUIRE | KF_RET_NULL | KF_RELEASE) BTF_ID_FLAGS(func, bpf_ct_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_ct_set_timeout, KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_ct_change_timeout, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_ct_set_status, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_ct_change_status, KF_TRUSTED_ARGS) BTF_SET8_END(nf_ct_kfunc_set) static const struct btf_kfunc_id_set nf_conntrack_kfunc_set = { diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 572f59a5e936..66a0aa8dbc3b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -2807,4 +2807,44 @@ int __nf_ct_change_timeout(struct nf_conn *ct, u64 timeout) } EXPORT_SYMBOL_GPL(__nf_ct_change_timeout); +void __nf_ct_change_status(struct nf_conn *ct, unsigned long on, unsigned long off) +{ + unsigned int bit; + + /* Ignore these unchangable bits */ + on &= ~IPS_UNCHANGEABLE_MASK; + off &= ~IPS_UNCHANGEABLE_MASK; + + for (bit = 0; bit < __IPS_MAX_BIT; bit++) { + if (on & (1 << bit)) + set_bit(bit, &ct->status); + else if (off & (1 << bit)) + clear_bit(bit, &ct->status); + } +} +EXPORT_SYMBOL_GPL(__nf_ct_change_status); + +int nf_ct_change_status_common(struct nf_conn *ct, unsigned int status) +{ + unsigned long d; + + d = ct->status ^ status; + + if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) + /* unchangeable */ + return -EBUSY; + + if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) + /* SEEN_REPLY bit can only be set */ + return -EBUSY; + + if (d & IPS_ASSURED && !(status & IPS_ASSURED)) + /* ASSURED bit can only be set */ + return -EBUSY; + + __nf_ct_change_status(ct, status, 0); + return 0; +} +EXPORT_SYMBOL_GPL(nf_ct_change_status_common); + #endif diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b1de07c73845..e02832ef9b9f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1890,45 +1890,10 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct, } #endif -static void -__ctnetlink_change_status(struct nf_conn *ct, unsigned long on, - unsigned long off) -{ - unsigned int bit; - - /* Ignore these unchangable bits */ - on &= ~IPS_UNCHANGEABLE_MASK; - off &= ~IPS_UNCHANGEABLE_MASK; - - for (bit = 0; bit < __IPS_MAX_BIT; bit++) { - if (on & (1 << bit)) - set_bit(bit, &ct->status); - else if (off & (1 << bit)) - clear_bit(bit, &ct->status); - } -} - static int ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) { - unsigned long d; - unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); - d = ct->status ^ status; - - if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) - /* unchangeable */ - return -EBUSY; - - if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) - /* SEEN_REPLY bit can only be set */ - return -EBUSY; - - if (d & IPS_ASSURED && !(status & IPS_ASSURED)) - /* ASSURED bit can only be set */ - return -EBUSY; - - __ctnetlink_change_status(ct, status, 0); - return 0; + return nf_ct_change_status_common(ct, ntohl(nla_get_be32(cda[CTA_STATUS]))); } static int @@ -2825,7 +2790,7 @@ ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[]) * unchangeable bits but do not error out. Also user programs * are allowed to clear the bits that they are allowed to change. */ - __ctnetlink_change_status(ct, status, ~status); + __nf_ct_change_status(ct, status, ~status); return 0; } -- cgit v1.2.3 From 949d6b405e6160ae44baea39192d67b39cb7eeac Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 20 Jul 2022 16:57:58 -0700 Subject: net: add missing includes and forward declarations under net/ This patch adds missing includes to headers under include/net. All these problems are currently masked by the existing users including the missing dependency before the broken header. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/linux/lapb.h | 5 +++++ include/net/af_vsock.h | 1 + include/net/amt.h | 3 +++ include/net/ax88796.h | 2 ++ include/net/bond_options.h | 8 ++++++++ include/net/codel_qdisc.h | 1 + include/net/datalink.h | 7 +++++++ include/net/dcbevent.h | 2 ++ include/net/dcbnl.h | 2 ++ include/net/dn_dev.h | 1 + include/net/dn_fib.h | 2 ++ include/net/dn_neigh.h | 2 ++ include/net/dn_nsp.h | 6 ++++++ include/net/dn_route.h | 3 +++ include/net/erspan.h | 3 +++ include/net/esp.h | 1 + include/net/ethoc.h | 3 +++ include/net/firewire.h | 2 ++ include/net/fq.h | 4 ++++ include/net/garp.h | 2 ++ include/net/gtp.h | 4 ++++ include/net/gue.h | 3 +++ include/net/hwbm.h | 2 ++ include/net/ila.h | 2 ++ include/net/inet6_connection_sock.h | 2 ++ include/net/inet_common.h | 6 ++++++ include/net/inet_frag.h | 3 +++ include/net/ip6_route.h | 20 ++++++++++---------- include/net/ipcomp.h | 2 ++ include/net/ipconfig.h | 2 ++ include/net/llc_c_ac.h | 7 +++++++ include/net/llc_c_st.h | 4 ++++ include/net/llc_s_ac.h | 4 ++++ include/net/llc_s_ev.h | 1 + include/net/mpls_iptunnel.h | 3 +++ include/net/mrp.h | 4 ++++ include/net/ncsi.h | 2 ++ include/net/netevent.h | 1 + include/net/netns/can.h | 1 + include/net/netns/core.h | 2 ++ include/net/netns/generic.h | 1 + include/net/netns/ipv4.h | 1 + include/net/netns/mctp.h | 1 + include/net/netns/mpls.h | 2 ++ include/net/netns/nexthop.h | 1 + include/net/netns/sctp.h | 3 +++ include/net/netns/unix.h | 2 ++ include/net/netrom.h | 1 + include/net/p8022.h | 5 +++++ include/net/phonet/pep.h | 3 +++ include/net/phonet/phonet.h | 4 ++++ include/net/phonet/pn_dev.h | 5 +++++ include/net/pptp.h | 3 +++ include/net/psnap.h | 5 +++++ include/net/regulatory.h | 3 +++ include/net/rose.h | 1 + include/net/secure_seq.h | 2 ++ include/net/smc.h | 7 +++++++ include/net/stp.h | 2 ++ include/net/transp_v6.h | 2 ++ include/net/tun_proto.h | 3 ++- include/net/udplite.h | 1 + include/net/xdp_priv.h | 1 + 63 files changed, 183 insertions(+), 11 deletions(-) (limited to 'include/net') diff --git a/include/linux/lapb.h b/include/linux/lapb.h index eb56472f23b2..b5333f9413dc 100644 --- a/include/linux/lapb.h +++ b/include/linux/lapb.h @@ -6,6 +6,11 @@ #ifndef LAPB_KERNEL_H #define LAPB_KERNEL_H +#include +#include + +struct net_device; + #define LAPB_OK 0 #define LAPB_BADTOKEN 1 #define LAPB_INVALUE 2 diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index f742e50207fb..1c53c4c4d88f 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -10,6 +10,7 @@ #include #include +#include #include #include "vsock_addr.h" diff --git a/include/net/amt.h b/include/net/amt.h index 08fc30cf2f34..c881bc8b673b 100644 --- a/include/net/amt.h +++ b/include/net/amt.h @@ -7,6 +7,9 @@ #include #include +#include +#include +#include enum amt_msg_type { AMT_MSG_DISCOVERY = 1, diff --git a/include/net/ax88796.h b/include/net/ax88796.h index 2ed23a368602..b658471f97f0 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -8,6 +8,8 @@ #ifndef __NET_AX88796_PLAT_H #define __NET_AX88796_PLAT_H +#include + struct sk_buff; struct net_device; struct platform_device; diff --git a/include/net/bond_options.h b/include/net/bond_options.h index d2aea5cf1e41..69292ecc0325 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -7,6 +7,14 @@ #ifndef _NET_BOND_OPTIONS_H #define _NET_BOND_OPTIONS_H +#include +#include +#include +#include + +struct netlink_ext_ack; +struct nlattr; + #define BOND_OPT_MAX_NAMELEN 32 #define BOND_OPT_VALID(opt) ((opt) < BOND_OPT_LAST) #define BOND_MODE_ALL_EX(x) (~(x)) diff --git a/include/net/codel_qdisc.h b/include/net/codel_qdisc.h index 58b6d0ebea10..7d3d9219f4fe 100644 --- a/include/net/codel_qdisc.h +++ b/include/net/codel_qdisc.h @@ -49,6 +49,7 @@ * Implemented on linux by Dave Taht and Eric Dumazet */ +#include #include /* Qdiscs using codel plugin must use codel_skb_cb in their own cb[] */ diff --git a/include/net/datalink.h b/include/net/datalink.h index d9b7faaa539f..c837ffc7ebf8 100644 --- a/include/net/datalink.h +++ b/include/net/datalink.h @@ -2,6 +2,13 @@ #ifndef _NET_INET_DATALINK_H_ #define _NET_INET_DATALINK_H_ +#include + +struct llc_sap; +struct net_device; +struct packet_type; +struct sk_buff; + struct datalink_proto { unsigned char type[8]; diff --git a/include/net/dcbevent.h b/include/net/dcbevent.h index 43e34131a53f..02700262f71a 100644 --- a/include/net/dcbevent.h +++ b/include/net/dcbevent.h @@ -8,6 +8,8 @@ #ifndef _DCB_EVENT_H #define _DCB_EVENT_H +struct notifier_block; + enum dcbevent_notif_type { DCB_APP_EVENT = 1, }; diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h index e4ad58c4062c..2b2d86fb3131 100644 --- a/include/net/dcbnl.h +++ b/include/net/dcbnl.h @@ -10,6 +10,8 @@ #include +struct net_device; + struct dcb_app_type { int ifindex; struct dcb_app app; diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h index 595b4f6c1eb1..bec303ea8367 100644 --- a/include/net/dn_dev.h +++ b/include/net/dn_dev.h @@ -2,6 +2,7 @@ #ifndef _NET_DN_DEV_H #define _NET_DN_DEV_H +#include struct dn_dev; diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h index ddd6565957b3..1929a3cd5ebe 100644 --- a/include/net/dn_fib.h +++ b/include/net/dn_fib.h @@ -4,6 +4,8 @@ #include #include +#include +#include extern const struct nla_policy rtm_dn_policy[]; diff --git a/include/net/dn_neigh.h b/include/net/dn_neigh.h index 2e3e7793973a..1f7df98bfc33 100644 --- a/include/net/dn_neigh.h +++ b/include/net/dn_neigh.h @@ -2,6 +2,8 @@ #ifndef _NET_DN_NEIGH_H #define _NET_DN_NEIGH_H +#include + /* * The position of the first two fields of * this structure are critical - SJW diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h index f83932b864a9..a4a18fee0b7c 100644 --- a/include/net/dn_nsp.h +++ b/include/net/dn_nsp.h @@ -6,6 +6,12 @@ *******************************************************************************/ /* dn_nsp.c functions prototyping */ +#include +#include +#include + +struct sk_buff; +struct sk_buff_head; void dn_nsp_send_data_ack(struct sock *sk); void dn_nsp_send_oth_ack(struct sock *sk); diff --git a/include/net/dn_route.h b/include/net/dn_route.h index 6f1e94ac0bdf..88c0300236cc 100644 --- a/include/net/dn_route.h +++ b/include/net/dn_route.h @@ -7,6 +7,9 @@ *******************************************************************************/ +#include +#include + struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri); int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *, struct sock *sk, int flags); diff --git a/include/net/erspan.h b/include/net/erspan.h index 0d9e86bd9893..6cb4cbd6a48f 100644 --- a/include/net/erspan.h +++ b/include/net/erspan.h @@ -58,6 +58,9 @@ * GRE proto ERSPAN type I/II = 0x88BE, type III = 0x22EB */ +#include +#include +#include #include #define ERSPAN_VERSION 0x1 /* ERSPAN type II */ diff --git a/include/net/esp.h b/include/net/esp.h index 9c5637d41d95..322950727dd0 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -5,6 +5,7 @@ #include struct ip_esp_hdr; +struct xfrm_state; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) { diff --git a/include/net/ethoc.h b/include/net/ethoc.h index 78519ed42ab4..73810f3ca492 100644 --- a/include/net/ethoc.h +++ b/include/net/ethoc.h @@ -10,6 +10,9 @@ #ifndef LINUX_NET_ETHOC_H #define LINUX_NET_ETHOC_H 1 +#include +#include + struct ethoc_platform_data { u8 hwaddr[IFHWADDRLEN]; s8 phy_id; diff --git a/include/net/firewire.h b/include/net/firewire.h index 299e5df38552..2442d645e412 100644 --- a/include/net/firewire.h +++ b/include/net/firewire.h @@ -2,6 +2,8 @@ #ifndef _NET_FIREWIRE_H #define _NET_FIREWIRE_H +#include + /* Pseudo L2 address */ #define FWNET_ALEN 16 union fwnet_hwaddr { diff --git a/include/net/fq.h b/include/net/fq.h index 2eccbbd2b559..07b5aff6ec58 100644 --- a/include/net/fq.h +++ b/include/net/fq.h @@ -7,6 +7,10 @@ #ifndef __NET_SCHED_FQ_H #define __NET_SCHED_FQ_H +#include +#include +#include + struct fq_tin; /** diff --git a/include/net/garp.h b/include/net/garp.h index 4d9a0c6a2e5f..59a07b171def 100644 --- a/include/net/garp.h +++ b/include/net/garp.h @@ -2,6 +2,8 @@ #ifndef _NET_GARP_H #define _NET_GARP_H +#include +#include #include #define GARP_PROTOCOL_ID 0x1 diff --git a/include/net/gtp.h b/include/net/gtp.h index c1d6169df331..2a503f035d18 100644 --- a/include/net/gtp.h +++ b/include/net/gtp.h @@ -2,6 +2,10 @@ #ifndef _GTP_H_ #define _GTP_H_ +#include +#include +#include + /* General GTP protocol related definitions. */ #define GTP0_PORT 3386 diff --git a/include/net/gue.h b/include/net/gue.h index e42402f180b7..dfca298bec9c 100644 --- a/include/net/gue.h +++ b/include/net/gue.h @@ -30,6 +30,9 @@ * may refer to options placed after this field. */ +#include +#include + struct guehdr { union { struct { diff --git a/include/net/hwbm.h b/include/net/hwbm.h index c81444611a22..aa495decec35 100644 --- a/include/net/hwbm.h +++ b/include/net/hwbm.h @@ -2,6 +2,8 @@ #ifndef _HWBM_H #define _HWBM_H +#include + struct hwbm_pool { /* Capacity of the pool */ int size; diff --git a/include/net/ila.h b/include/net/ila.h index f98dcd5791b0..73ebe5eab272 100644 --- a/include/net/ila.h +++ b/include/net/ila.h @@ -8,6 +8,8 @@ #ifndef _NET_ILA_H #define _NET_ILA_H +struct sk_buff; + int ila_xlat_outgoing(struct sk_buff *skb); int ila_xlat_incoming(struct sk_buff *skb); diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h index 7392f959a405..025bd8d3c769 100644 --- a/include/net/inet6_connection_sock.h +++ b/include/net/inet6_connection_sock.h @@ -11,6 +11,8 @@ #include +struct flowi; +struct flowi6; struct request_sock; struct sk_buff; struct sock; diff --git a/include/net/inet_common.h b/include/net/inet_common.h index cad2a611efde..cec453c18f1d 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -3,6 +3,10 @@ #define _INET_COMMON_H #include +#include +#include +#include +#include extern const struct proto_ops inet_stream_ops; extern const struct proto_ops inet_dgram_ops; @@ -12,6 +16,8 @@ extern const struct proto_ops inet_dgram_ops; */ struct msghdr; +struct net; +struct page; struct sock; struct sockaddr; struct socket; diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 911ad930867d..0b0876610553 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -4,6 +4,9 @@ #include #include +#include +#include +#include /* Per netns frag queues directory */ struct fqdir { diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index ca2d6b60e1ec..035d61d50a98 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -2,6 +2,16 @@ #ifndef _NET_IP6_ROUTE_H #define _NET_IP6_ROUTE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include + struct route_info { __u8 type; __u8 length; @@ -19,16 +29,6 @@ struct route_info { __u8 prefix[]; /* 0,8 or 16 */ }; -#include -#include -#include -#include -#include -#include -#include -#include -#include - #define RT6_LOOKUP_F_IFACE 0x00000001 #define RT6_LOOKUP_F_REACHABLE 0x00000002 #define RT6_LOOKUP_F_HAS_SADDR 0x00000004 diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h index fee6fc451597..c31108295079 100644 --- a/include/net/ipcomp.h +++ b/include/net/ipcomp.h @@ -2,11 +2,13 @@ #ifndef _NET_IPCOMP_H #define _NET_IPCOMP_H +#include #include #define IPCOMP_SCRATCH_SIZE 65400 struct crypto_comp; +struct ip_comp_hdr; struct ipcomp_data { u16 threshold; diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h index e3534299bd2a..8276897d0c2e 100644 --- a/include/net/ipconfig.h +++ b/include/net/ipconfig.h @@ -7,6 +7,8 @@ /* The following are initdata: */ +#include + extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ extern int ic_set_manually; /* IPconfig parameters set manually */ diff --git a/include/net/llc_c_ac.h b/include/net/llc_c_ac.h index e766300b3e99..3e1f76786d7b 100644 --- a/include/net/llc_c_ac.h +++ b/include/net/llc_c_ac.h @@ -16,6 +16,13 @@ * Connection state transition actions * (Fb = F bit; Pb = P bit; Xb = X bit) */ + +#include + +struct sk_buff; +struct sock; +struct timer_list; + #define LLC_CONN_AC_CLR_REMOTE_BUSY 1 #define LLC_CONN_AC_CONN_IND 2 #define LLC_CONN_AC_CONN_CONFIRM 3 diff --git a/include/net/llc_c_st.h b/include/net/llc_c_st.h index 48f3f891b2f9..53823d61d8b6 100644 --- a/include/net/llc_c_st.h +++ b/include/net/llc_c_st.h @@ -11,6 +11,10 @@ * * See the GNU General Public License for more details. */ + +#include +#include + /* Connection component state management */ /* connection states */ #define LLC_CONN_OUT_OF_SVC 0 /* prior to allocation */ diff --git a/include/net/llc_s_ac.h b/include/net/llc_s_ac.h index a61b98c108ee..f71790305bc9 100644 --- a/include/net/llc_s_ac.h +++ b/include/net/llc_s_ac.h @@ -11,6 +11,10 @@ * * See the GNU General Public License for more details. */ + +struct llc_sap; +struct sk_buff; + /* SAP component actions */ #define SAP_ACT_UNITDATA_IND 1 #define SAP_ACT_SEND_UI 2 diff --git a/include/net/llc_s_ev.h b/include/net/llc_s_ev.h index 84db3a59ed28..fb7df1d70af3 100644 --- a/include/net/llc_s_ev.h +++ b/include/net/llc_s_ev.h @@ -13,6 +13,7 @@ */ #include +#include /* Defines SAP component events */ /* Types of events (possible values in 'ev->type') */ diff --git a/include/net/mpls_iptunnel.h b/include/net/mpls_iptunnel.h index 9deb3a3735da..0c71c27979fb 100644 --- a/include/net/mpls_iptunnel.h +++ b/include/net/mpls_iptunnel.h @@ -6,6 +6,9 @@ #ifndef _NET_MPLS_IPTUNNEL_H #define _NET_MPLS_IPTUNNEL_H 1 +#include +#include + struct mpls_iptunnel_encap { u8 labels; u8 ttl_propagate; diff --git a/include/net/mrp.h b/include/net/mrp.h index 1c308c034e1a..92cd3fb6cf9d 100644 --- a/include/net/mrp.h +++ b/include/net/mrp.h @@ -2,6 +2,10 @@ #ifndef _NET_MRP_H #define _NET_MRP_H +#include +#include +#include + #define MRP_END_MARK 0x0 struct mrp_pdu_hdr { diff --git a/include/net/ncsi.h b/include/net/ncsi.h index fbefe80361ee..08a50d9acb0a 100644 --- a/include/net/ncsi.h +++ b/include/net/ncsi.h @@ -2,6 +2,8 @@ #ifndef __NET_NCSI_H #define __NET_NCSI_H +#include + /* * The NCSI device states seen from external. More NCSI device states are * only visible internally (in net/ncsi/internal.h). When the NCSI device diff --git a/include/net/netevent.h b/include/net/netevent.h index 4107016c3bb4..1be3757a8b7f 100644 --- a/include/net/netevent.h +++ b/include/net/netevent.h @@ -14,6 +14,7 @@ struct dst_entry; struct neighbour; +struct notifier_block ; struct netevent_redirect { struct dst_entry *old; diff --git a/include/net/netns/can.h b/include/net/netns/can.h index 52fbd8291a96..48b79f7e6236 100644 --- a/include/net/netns/can.h +++ b/include/net/netns/can.h @@ -7,6 +7,7 @@ #define __NETNS_CAN_H__ #include +#include struct can_dev_rcv_lists; struct can_pkg_stats; diff --git a/include/net/netns/core.h b/include/net/netns/core.h index 388244e315e7..8249060cf5d0 100644 --- a/include/net/netns/core.h +++ b/include/net/netns/core.h @@ -2,6 +2,8 @@ #ifndef __NETNS_CORE_H__ #define __NETNS_CORE_H__ +#include + struct ctl_table_header; struct prot_inuse; diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h index 8a1ab47c3fb3..7ce68183f6e1 100644 --- a/include/net/netns/generic.h +++ b/include/net/netns/generic.h @@ -8,6 +8,7 @@ #include #include +#include /* * Generic net pointers are to be used by modules to put some private diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index ce0cc4e8d8c7..c7320ef356d9 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -9,6 +9,7 @@ #include #include #include +#include #include struct ctl_table_header; diff --git a/include/net/netns/mctp.h b/include/net/netns/mctp.h index acedef12a35e..1db8f9aaddb4 100644 --- a/include/net/netns/mctp.h +++ b/include/net/netns/mctp.h @@ -6,6 +6,7 @@ #ifndef __NETNS_MCTP_H__ #define __NETNS_MCTP_H__ +#include #include struct netns_mctp { diff --git a/include/net/netns/mpls.h b/include/net/netns/mpls.h index a7bdcfbb0b28..19ad2574b267 100644 --- a/include/net/netns/mpls.h +++ b/include/net/netns/mpls.h @@ -6,6 +6,8 @@ #ifndef __NETNS_MPLS_H__ #define __NETNS_MPLS_H__ +#include + struct mpls_route; struct ctl_table_header; diff --git a/include/net/netns/nexthop.h b/include/net/netns/nexthop.h index 1849e77eb68a..434239b37014 100644 --- a/include/net/netns/nexthop.h +++ b/include/net/netns/nexthop.h @@ -6,6 +6,7 @@ #ifndef __NETNS_NEXTHOP_H__ #define __NETNS_NEXTHOP_H__ +#include #include struct netns_nexthop { diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h index 40240722cdca..a681147aecd8 100644 --- a/include/net/netns/sctp.h +++ b/include/net/netns/sctp.h @@ -2,6 +2,9 @@ #ifndef __NETNS_SCTP_H__ #define __NETNS_SCTP_H__ +#include +#include + struct sock; struct proc_dir_entry; struct sctp_mib; diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h index 6f1a33df061d..9859d134d5a8 100644 --- a/include/net/netns/unix.h +++ b/include/net/netns/unix.h @@ -5,6 +5,8 @@ #ifndef __NETNS_UNIX_H__ #define __NETNS_UNIX_H__ +#include + struct unix_table { spinlock_t *locks; struct hlist_head *buckets; diff --git a/include/net/netrom.h b/include/net/netrom.h index 80f15b1c1a48..f0565a5987d1 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -14,6 +14,7 @@ #include #include #include +#include #define NR_NETWORK_LEN 15 #define NR_TRANSPORT_LEN 5 diff --git a/include/net/p8022.h b/include/net/p8022.h index c2bacc66bfbc..b690ffcad66b 100644 --- a/include/net/p8022.h +++ b/include/net/p8022.h @@ -1,6 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _NET_P8022_H #define _NET_P8022_H + +struct net_device; +struct packet_type; +struct sk_buff; + struct datalink_proto * register_8022_client(unsigned char type, int (*func)(struct sk_buff *skb, diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index 27b1ab5e4e6d..645dddf5ce77 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h @@ -10,6 +10,9 @@ #ifndef NET_PHONET_PEP_H #define NET_PHONET_PEP_H +#include +#include + struct pep_sock { struct pn_sock pn_sk; diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h index a27bdc6cfeab..862f1719b523 100644 --- a/include/net/phonet/phonet.h +++ b/include/net/phonet/phonet.h @@ -10,6 +10,10 @@ #ifndef AF_PHONET_H #define AF_PHONET_H +#include +#include +#include + /* * The lower layers may not require more space, ever. Make sure it's * enough. diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 05b49d4d2b11..e9dc8dca5817 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -10,6 +10,11 @@ #ifndef PN_DEV_H #define PN_DEV_H +#include +#include + +struct net; + struct phonet_device_list { struct list_head list; struct mutex lock; diff --git a/include/net/pptp.h b/include/net/pptp.h index 383e25ca53a7..e63176bdd4c8 100644 --- a/include/net/pptp.h +++ b/include/net/pptp.h @@ -2,6 +2,9 @@ #ifndef _NET_PPTP_H #define _NET_PPTP_H +#include +#include + #define PPP_LCP_ECHOREQ 0x09 #define PPP_LCP_ECHOREP 0x0A #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) diff --git a/include/net/psnap.h b/include/net/psnap.h index 7cb0c8ab4171..88802b0754ad 100644 --- a/include/net/psnap.h +++ b/include/net/psnap.h @@ -2,6 +2,11 @@ #ifndef _NET_PSNAP_H #define _NET_PSNAP_H +struct datalink_proto; +struct sk_buff; +struct packet_type; +struct net_device; + struct datalink_proto * register_snap_client(const unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct net_device *, diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 47f06f6f5a67..896191f420d5 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -1,3 +1,4 @@ + #ifndef __NET_REGULATORY_H #define __NET_REGULATORY_H /* @@ -19,6 +20,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include /** diff --git a/include/net/rose.h b/include/net/rose.h index 0f0a4ce0fee7..f192a64ddef2 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -9,6 +9,7 @@ #define _ROSE_H #include +#include #include #define ROSE_ADDR_LEN 5 diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h index dac91aa38c5a..21e7fa2a1813 100644 --- a/include/net/secure_seq.h +++ b/include/net/secure_seq.h @@ -4,6 +4,8 @@ #include +struct net; + u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport); diff --git a/include/net/smc.h b/include/net/smc.h index e441aa97ad61..37f829d9c6e5 100644 --- a/include/net/smc.h +++ b/include/net/smc.h @@ -11,6 +11,13 @@ #ifndef _SMC_H #define _SMC_H +#include +#include +#include +#include + +struct sock; + #define SMC_MAX_PNETID_LEN 16 /* Max. length of PNET id */ struct smc_hashinfo { diff --git a/include/net/stp.h b/include/net/stp.h index 2914e6d53490..528103fce2c0 100644 --- a/include/net/stp.h +++ b/include/net/stp.h @@ -2,6 +2,8 @@ #ifndef _NET_STP_H #define _NET_STP_H +#include + struct stp_proto { unsigned char group_address[ETH_ALEN]; void (*rcv)(const struct stp_proto *, struct sk_buff *, diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index da06613c9603..b830463e3dff 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -3,6 +3,7 @@ #define _TRANSP_V6_H #include +#include /* IPv6 transport protocols */ extern struct proto rawv6_prot; @@ -12,6 +13,7 @@ extern struct proto tcpv6_prot; extern struct proto pingv6_prot; struct flowi6; +struct ipcm6_cookie; /* extension headers */ int ipv6_exthdrs_init(void); diff --git a/include/net/tun_proto.h b/include/net/tun_proto.h index 2ea3deba4c99..7b0de7852908 100644 --- a/include/net/tun_proto.h +++ b/include/net/tun_proto.h @@ -1,7 +1,8 @@ #ifndef __NET_TUN_PROTO_H #define __NET_TUN_PROTO_H -#include +#include +#include /* One byte protocol values as defined by VXLAN-GPE and NSH. These will * hopefully get a shared IANA registry. diff --git a/include/net/udplite.h b/include/net/udplite.h index a3c53110d30b..0143b373602e 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -6,6 +6,7 @@ #define _UDPLITE_H #include +#include /* UDP-Lite socket options */ #define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ diff --git a/include/net/xdp_priv.h b/include/net/xdp_priv.h index a2d58b1a12e1..c9df68d5f258 100644 --- a/include/net/xdp_priv.h +++ b/include/net/xdp_priv.h @@ -3,6 +3,7 @@ #define __LINUX_NET_XDP_PRIV_H__ #include +#include /* Private to net/core/xdp.c, but used by trace/events/xdp.h */ struct xdp_mem_allocator { -- cgit v1.2.3 From ea7d50c925cec96b22655c4dc8672fbd59355bed Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 26 Jan 2022 19:13:47 +0200 Subject: wifi: cfg80211: add a function for reporting TX status with hardware timestamps Add a function for reporting TX status with hardware timestamps. This function shall be used for reporting the TX status of Timing measurement and Fine timing measurement action frames by devices that support reporting hardware timestamps. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 47 +++++++++++++++++++++++++++++++++++++++++++++-- net/wireless/nl80211.c | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 16 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d5af3a7fc2b4..43d54f5c84f9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7837,6 +7837,38 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, flags); } +/** + * struct cfg80211_tx_status - TX status for management frame information + * + * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() + * @tx_tstamp: hardware TX timestamp in nanoseconds + * @ack_tstamp: hardware ack RX timestamp in nanoseconds + * @buf: Management frame (header + body) + * @len: length of the frame data + * @ack: Whether frame was acknowledged + */ +struct cfg80211_tx_status { + u64 cookie; + u64 tx_tstamp; + u64 ack_tstamp; + const u8 *buf; + size_t len; + bool ack; +}; + +/** + * cfg80211_mgmt_tx_status_ext - TX status notification with extended info + * @wdev: wireless device receiving the frame + * @status: TX status data + * @gfp: context flags + * + * This function is called whenever a management frame was requested to be + * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the + * transmission attempt with extended info. + */ +void cfg80211_mgmt_tx_status_ext(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp); + /** * cfg80211_mgmt_tx_status - notification of TX status for management frame * @wdev: wireless device receiving the frame @@ -7850,8 +7882,19 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the * transmission attempt. */ -void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp); +static inline void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, + u64 cookie, const u8 *buf, + size_t len, bool ack, gfp_t gfp) +{ + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = buf, + .len = len, + .ack = ack + }; + + cfg80211_mgmt_tx_status_ext(wdev, &status, gfp); +} /** * cfg80211_control_port_tx_status - notification of TX status for control diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 310d22b263d1..a3934f443a84 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18396,8 +18396,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, return -ENOBUFS; } -static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, +static void nl80211_frame_tx_status(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp, enum nl80211_commands command) { struct wiphy *wiphy = wdev->wiphy; @@ -18407,11 +18407,13 @@ static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, void *hdr; if (command == NL80211_CMD_FRAME_TX_STATUS) - trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); + trace_cfg80211_mgmt_tx_status(wdev, status->cookie, + status->ack); else - trace_cfg80211_control_port_tx_status(wdev, cookie, ack); + trace_cfg80211_control_port_tx_status(wdev, status->cookie, + status->ack); - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + status->len, gfp); if (!msg) return; @@ -18426,10 +18428,16 @@ static void nl80211_frame_tx_status(struct wireless_dev *wdev, u64 cookie, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || - nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie, + nla_put(msg, NL80211_ATTR_FRAME, status->len, status->buf) || + nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, status->cookie, NL80211_ATTR_PAD) || - (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) + (status->ack && nla_put_flag(msg, NL80211_ATTR_ACK)) || + (status->tx_tstamp && + nla_put_u64_64bit(msg, NL80211_ATTR_TX_HW_TIMESTAMP, + status->tx_tstamp, NL80211_ATTR_PAD)) || + (status->ack_tstamp && + nla_put_u64_64bit(msg, NL80211_ATTR_RX_HW_TIMESTAMP, + status->ack_tstamp, NL80211_ATTR_PAD))) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -18446,18 +18454,24 @@ void cfg80211_control_port_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { - nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = buf, + .len = len, + .ack = ack + }; + + nl80211_frame_tx_status(wdev, &status, gfp, NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS); } EXPORT_SYMBOL(cfg80211_control_port_tx_status); -void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp) +void cfg80211_mgmt_tx_status_ext(struct wireless_dev *wdev, + struct cfg80211_tx_status *status, gfp_t gfp) { - nl80211_frame_tx_status(wdev, cookie, buf, len, ack, gfp, - NL80211_CMD_FRAME_TX_STATUS); + nl80211_frame_tx_status(wdev, status, gfp, NL80211_CMD_FRAME_TX_STATUS); } -EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +EXPORT_SYMBOL(cfg80211_mgmt_tx_status_ext); static int __nl80211_rx_control_port(struct net_device *dev, struct sk_buff *skb, -- cgit v1.2.3 From 00b3d8401019e6abf89ea577cb1de060ea65e3fd Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Sun, 30 Jan 2022 18:17:51 +0200 Subject: wifi: cfg80211/nl80211: move rx management data into a struct The functions for reporting rx management take many arguments. Collect all the arguments into a struct, which also make it easier to add more arguments if needed. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- net/wireless/mlme.c | 21 +++++++++--------- net/wireless/nl80211.c | 19 ++++++++-------- net/wireless/nl80211.h | 5 ++--- net/wireless/trace.h | 8 +++---- 5 files changed, 81 insertions(+), 32 deletions(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 43d54f5c84f9..535e326a35b0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7792,6 +7792,39 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, enum nl80211_connect_failed_reason reason, gfp_t gfp); +/** + * struct cfg80211_rx_info - received management frame info + * + * @freq: Frequency on which the frame was received in kHz + * @sig_dbm: signal strength in dBm, or 0 if unknown + * @buf: Management frame (header + body) + * @len: length of the frame data + * @flags: flags, as defined in enum nl80211_rxmgmt_flags + */ +struct cfg80211_rx_info { + int freq; + int sig_dbm; + const u8 *buf; + size_t len; + u32 flags; +}; + +/** + * cfg80211_rx_mgmt_ext - management frame notification with extended info + * @wdev: wireless device receiving the frame + * @info: RX info as defined in struct cfg80211_rx_info + * + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + * + * Return: %true if a user space application has registered for this frame. + * For action frames, that makes it responsible for rejecting unrecognized + * action frames; %false otherwise, in which case for action frames the + * driver is responsible for rejecting the frame. + */ +bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev, + struct cfg80211_rx_info *info); + /** * cfg80211_rx_mgmt_khz - notification of received, unprocessed management frame * @wdev: wireless device receiving the frame @@ -7809,8 +7842,20 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * action frames; %false otherwise, in which case for action frames the * driver is responsible for rejecting the frame. */ -bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags); +static inline bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, + int sig_dbm, const u8 *buf, size_t len, + u32 flags) +{ + struct cfg80211_rx_info info = { + .freq = freq, + .sig_dbm = sig_dbm, + .buf = buf, + .len = len, + .flags = flags + }; + + return cfg80211_rx_mgmt_ext(wdev, &info); +} /** * cfg80211_rx_mgmt - notification of received, unprocessed management frame @@ -7833,8 +7878,15 @@ static inline bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, const u8 *buf, size_t len, u32 flags) { - return cfg80211_rx_mgmt_khz(wdev, MHZ_TO_KHZ(freq), sig_dbm, buf, len, - flags); + struct cfg80211_rx_info info = { + .freq = MHZ_TO_KHZ(freq), + .sig_dbm = sig_dbm, + .buf = buf, + .len = len, + .flags = flags + }; + + return cfg80211_rx_mgmt_ext(wdev, &info); } /** diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 003c57504583..581df7f4c524 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -4,7 +4,7 @@ * * Copyright (c) 2009, Jouni Malinen * Copyright (c) 2015 Intel Deutschland GmbH - * Copyright (C) 2019-2020 Intel Corporation + * Copyright (C) 2019-2020, 2022 Intel Corporation */ #include @@ -791,15 +791,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return rdev_mgmt_tx(rdev, wdev, params, cookie); } -bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags) +bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev, + struct cfg80211_rx_info *info) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_mgmt_registration *reg; const struct ieee80211_txrx_stypes *stypes = &wiphy->mgmt_stypes[wdev->iftype]; - struct ieee80211_mgmt *mgmt = (void *)buf; + struct ieee80211_mgmt *mgmt = (void *)info->buf; const u8 *data; int data_len; bool result = false; @@ -807,7 +807,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); u16 stype; - trace_cfg80211_rx_mgmt(wdev, freq, sig_dbm); + trace_cfg80211_rx_mgmt(wdev, info); stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; if (!(stypes->rx & BIT(stype))) { @@ -815,8 +815,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, return false; } - data = buf + ieee80211_hdrlen(mgmt->frame_control); - data_len = len - ieee80211_hdrlen(mgmt->frame_control); + data = info->buf + ieee80211_hdrlen(mgmt->frame_control); + data_len = info->len - ieee80211_hdrlen(mgmt->frame_control); spin_lock_bh(&rdev->mgmt_registrations_lock); @@ -833,9 +833,8 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, - freq, sig_dbm, - buf, len, flags, GFP_ATOMIC)) + if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, info, + GFP_ATOMIC)) continue; result = true; @@ -847,7 +846,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, trace_cfg80211_return_bool(result); return result; } -EXPORT_SYMBOL(cfg80211_rx_mgmt_khz); +EXPORT_SYMBOL(cfg80211_rx_mgmt_ext); void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a3934f443a84..80d3471041d1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18356,14 +18356,13 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlportid, - int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp) + struct cfg80211_rx_info *info, gfp_t gfp) { struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + info->len, gfp); if (!msg) return -ENOMEM; @@ -18378,13 +18377,13 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq)) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, freq % 1000) || - (sig_dbm && - nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || - (flags && - nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags))) + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(info->freq)) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, info->freq % 1000) || + (info->sig_dbm && + nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) || + nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) || + (info->flags && + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags))) goto nla_put_failure; genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index a7e8e0917c1c..855d540ddfb9 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Portions of this file - * Copyright (C) 2018, 2020-2021 Intel Corporation + * Copyright (C) 2018, 2020-2022 Intel Corporation */ #ifndef __NET_WIRELESS_NL80211_H #define __NET_WIRELESS_NL80211_H @@ -105,8 +105,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlpid, - int freq, int sig_dbm, - const u8 *buf, size_t len, u32 flags, gfp_t gfp); + struct cfg80211_rx_info *info, gfp_t gfp); void nl80211_radar_notify(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 592b9e9e821a..10b2fd9bacb5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3096,8 +3096,8 @@ DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_del_sta, ); TRACE_EVENT(cfg80211_rx_mgmt, - TP_PROTO(struct wireless_dev *wdev, int freq, int sig_dbm), - TP_ARGS(wdev, freq, sig_dbm), + TP_PROTO(struct wireless_dev *wdev, struct cfg80211_rx_info *info), + TP_ARGS(wdev, info), TP_STRUCT__entry( WDEV_ENTRY __field(int, freq) @@ -3105,8 +3105,8 @@ TRACE_EVENT(cfg80211_rx_mgmt, ), TP_fast_assign( WDEV_ASSIGN; - __entry->freq = freq; - __entry->sig_dbm = sig_dbm; + __entry->freq = info->freq; + __entry->sig_dbm = info->sig_dbm; ), TP_printk(WDEV_PR_FMT ", freq: "KHZ_F", sig dbm: %d", WDEV_PR_ARG, PR_KHZ(__entry->freq), __entry->sig_dbm) -- cgit v1.2.3 From 1ff715ffa0ec1b5af9093c43185e686f575f15cc Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 27 Jan 2022 13:56:29 +0200 Subject: wifi: cfg80211: add hardware timestamps to frame RX info Add hardware timestamps to management frame RX info. This shall be used by drivers that support hardware timestamping for Timing measurement and Fine timing measurement action frames RX. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ net/wireless/nl80211.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 535e326a35b0..2f5c271bcde1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7800,6 +7800,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @buf: Management frame (header + body) * @len: length of the frame data * @flags: flags, as defined in enum nl80211_rxmgmt_flags + * @rx_tstamp: Hardware timestamp of frame RX in nanoseconds + * @ack_tstamp: Hardware timestamp of ack TX in nanoseconds */ struct cfg80211_rx_info { int freq; @@ -7807,6 +7809,8 @@ struct cfg80211_rx_info { const u8 *buf; size_t len; u32 flags; + u64 rx_tstamp; + u64 ack_tstamp; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 80d3471041d1..e5ed0950ef0b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18383,7 +18383,15 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, info->sig_dbm)) || nla_put(msg, NL80211_ATTR_FRAME, info->len, info->buf) || (info->flags && - nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags))) + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, info->flags)) || + (info->rx_tstamp && nla_put_u64_64bit(msg, + NL80211_ATTR_RX_HW_TIMESTAMP, + info->rx_tstamp, + NL80211_ATTR_PAD)) || + (info->ack_tstamp && nla_put_u64_64bit(msg, + NL80211_ATTR_TX_HW_TIMESTAMP, + info->ack_tstamp, + NL80211_ATTR_PAD))) goto nla_put_failure; genlmsg_end(msg, hdr); -- cgit v1.2.3 From f9202638df34474f862109731203e71d8e71f85e Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 26 Jan 2022 11:15:31 +0200 Subject: wifi: mac80211: add hardware timestamps for RX and TX When the low level driver reports hardware timestamps for frame TX status or frame RX, pass the timestamps to cfg80211. Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/net/mac80211.h | 28 +++++++++++++++++++++++++++- net/mac80211/rx.c | 30 ++++++++++++++++++++++-------- net/mac80211/status.c | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 19 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6f856da28d71..e9f8be7ba9a6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -125,6 +125,22 @@ * via the usual ieee80211_tx_dequeue). */ +/** + * DOC: HW timestamping + * + * Timing Measurement and Fine Timing Measurement require accurate timestamps + * of the action frames TX/RX and their respective acks. + * + * To report hardware timestamps for Timing Measurement or Fine Timing + * Measurement frame RX, the low level driver should set the SKB's hwtstamp + * field to the frame RX timestamp and report the ack TX timestamp in the + * ieee80211_rx_status struct. + * + * Similarly, To report hardware timestamps for Timing Measurement or Fine + * Timing Measurement frame TX, the driver should set the SKB's hwtstamp field + * to the frame TX timestamp and report the ack RX timestamp in the + * ieee80211_tx_status struct. + */ struct device; /** @@ -1176,12 +1192,16 @@ struct ieee80211_rate_status { * @rates: Mrr stages that were used when sending the packet * @n_rates: Number of mrr stages (count of instances for @rates) * @free_list: list where processed skbs are stored to be free'd by the driver + * @ack_hwtstamp: Hardware timestamp of the received ack in nanoseconds + * Only needed for Timing measurement and Fine timing measurement action + * frames. Only reported by devices that have timestamping enabled. */ struct ieee80211_tx_status { struct ieee80211_sta *sta; struct ieee80211_tx_info *info; struct sk_buff *skb; struct ieee80211_rate_status *rates; + ktime_t ack_hwtstamp; u8 n_rates; struct list_head *free_list; @@ -1419,6 +1439,9 @@ enum mac80211_rx_encoding { * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @boottime_ns: CLOCK_BOOTTIME timestamp the frame was received at, this is * needed only for beacons and probe responses that update the scan cache. + * @ack_tx_hwtstamp: Hardware timestamp for the ack TX in nanoseconds. Only + * needed for Timing measurement and Fine timing measurement action frames. + * Only reported by devices that have timestamping enabled. * @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use * it but can store it and pass it back to the driver for synchronisation * @band: the active band when this frame was received @@ -1452,7 +1475,10 @@ enum mac80211_rx_encoding { */ struct ieee80211_rx_status { u64 mactime; - u64 boottime_ns; + union { + u64 boottime_ns; + ktime_t ack_tx_hwtstamp; + }; u32 device_timestamp; u32 ampdu_reference; u32 flag; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9054a1e0b0d8..ef9c2fcd68f5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3644,7 +3644,11 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int sig = 0; + struct cfg80211_rx_info info = { + .freq = ieee80211_rx_status_to_khz(status), + .buf = rx->skb->data, + .len = rx->skb->len + }; /* skip known-bad action frames and return them in the next handler */ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) @@ -3659,11 +3663,15 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) - sig = status->signal; + info.sig_dbm = status->signal; + + if (ieee80211_is_timing_measurement(rx->skb) || + ieee80211_is_ftm(rx->skb)) { + info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp); + info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp); + } - if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev, - ieee80211_rx_status_to_khz(status), sig, - rx->skb->data, rx->skb->len, 0)) { + if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) { if (rx->sta) rx->sta->deflink.rx_stats.packets++; dev_kfree_skb(rx->skb); @@ -4758,8 +4766,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, } if (!consume) { - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) { + struct skb_shared_hwtstamps *shwt; + + rx->skb = skb_copy(skb, GFP_ATOMIC); + if (!rx->skb) { if (net_ratelimit()) wiphy_debug(local->hw.wiphy, "failed to copy skb for %s\n", @@ -4767,7 +4777,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, return true; } - rx->skb = skb; + /* skb_copy() does not copy the hw timestamps, so copy it + * explicitly + */ + shwt = skb_hwtstamps(rx->skb); + shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp; } if (unlikely(link_sta)) { diff --git a/net/mac80211/status.c b/net/mac80211/status.c index fad457f99711..8e77fd2e9fdf 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -624,9 +624,11 @@ ieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb) } static void ieee80211_report_ack_skb(struct ieee80211_local *local, - struct ieee80211_tx_info *info, - bool acked, bool dropped) + struct sk_buff *orig_skb, + bool acked, bool dropped, + ktime_t ack_hwtstamp) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(orig_skb); struct sk_buff *skb; unsigned long flags; @@ -643,6 +645,19 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, struct ieee80211_hdr *hdr = (void *)skb->data; bool is_valid_ack_signal = !!(info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID); + struct cfg80211_tx_status status = { + .cookie = cookie, + .buf = skb->data, + .len = skb->len, + .ack = acked, + }; + + if (ieee80211_is_timing_measurement(orig_skb) || + ieee80211_is_ftm(orig_skb)) { + status.tx_tstamp = + ktime_to_ns(skb_hwtstamps(orig_skb)->hwtstamp); + status.ack_tstamp = ktime_to_ns(ack_hwtstamp); + } rcu_read_lock(); sdata = ieee80211_sdata_from_skb(local, skb); @@ -662,9 +677,9 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, is_valid_ack_signal, GFP_ATOMIC); else if (ieee80211_is_mgmt(hdr->frame_control)) - cfg80211_mgmt_tx_status(&sdata->wdev, cookie, - skb->data, skb->len, - acked, GFP_ATOMIC); + cfg80211_mgmt_tx_status_ext(&sdata->wdev, + &status, + GFP_ATOMIC); else pr_warn("Unknown status report in ack skb\n"); @@ -681,7 +696,8 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, } static void ieee80211_report_used_skb(struct ieee80211_local *local, - struct sk_buff *skb, bool dropped) + struct sk_buff *skb, bool dropped, + ktime_t ack_hwtstamp) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 tx_time_est = ieee80211_info_get_tx_time_est(info); @@ -744,7 +760,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, rcu_read_unlock(); } else if (info->ack_frame_id) { - ieee80211_report_ack_skb(local, info, acked, dropped); + ieee80211_report_ack_skb(local, skb, acked, dropped, + ack_hwtstamp); } if (!dropped && skb->destructor) { @@ -1038,7 +1055,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, jiffies + msecs_to_jiffies(10)); } - ieee80211_report_used_skb(local, skb, false); + ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); @@ -1201,7 +1218,7 @@ free: if (!skb) return; - ieee80211_report_used_skb(local, skb, false); + ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); if (status->free_list) list_add_tail(&skb->list, status->free_list); else @@ -1262,8 +1279,9 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); + ktime_t kt = ktime_set(0, 0); - ieee80211_report_used_skb(local, skb, true); + ieee80211_report_used_skb(local, skb, true, kt); dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb); -- cgit v1.2.3 From 6074c9e5747158ab1e6aebedb87f64be77401fd8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 10:40:44 +0200 Subject: wifi: cfg80211: report link ID in NL80211_CMD_FRAME If given by the underlying driver, report the link ID for MLO in NL80211_CMD_FRAME. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 +++++ net/wireless/nl80211.c | 2 ++ 2 files changed, 7 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2f5c271bcde1..8545ed098d90 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7797,6 +7797,9 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * * @freq: Frequency on which the frame was received in kHz * @sig_dbm: signal strength in dBm, or 0 if unknown + * @have_link_id: indicates the frame was received on a link of + * an MLD, i.e. the @link_id field is valid + * @link_id: the ID of the link the frame was received on * @buf: Management frame (header + body) * @len: length of the frame data * @flags: flags, as defined in enum nl80211_rxmgmt_flags @@ -7806,6 +7809,8 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, struct cfg80211_rx_info { int freq; int sig_dbm; + bool have_link_id; + u8 link_id; const u8 *buf; size_t len; u32 flags; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e5ed0950ef0b..60b8406b8d7e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18377,6 +18377,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, netdev->ifindex)) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || + (info->have_link_id && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, info->link_id)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(info->freq)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET, info->freq % 1000) || (info->sig_dbm && -- cgit v1.2.3 From 95f498bb49f7030c1f40236107e5241e50f79ade Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 12:13:46 +0200 Subject: wifi: nl80211: add MLO link ID to the NL80211_CMD_FRAME TX API Allow optionally specifying the link ID to transmit on, which can be done instead of the link frequency, on an MLD addressed frame. Both can also be omitted in which case the frame must be MLD addressed and link selection (and address translation) will be done on lower layers. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 4 ++++ net/wireless/nl80211.c | 12 ++++++++++++ 3 files changed, 20 insertions(+) (limited to 'include/net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 8545ed098d90..908d58393484 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3411,6 +3411,9 @@ struct cfg80211_update_ft_ies_params { * @dont_wait_for_ack: tells the low level not to wait for an ack * @n_csa_offsets: length of csa_offsets array * @csa_offsets: array of all the csa offsets in the frame + * @link_id: for MLO, the link ID to transmit on, -1 if not given; note + * that the link ID isn't validated (much), it's in range but the + * link might not exist (or be used by the receiver STA) */ struct cfg80211_mgmt_tx_params { struct ieee80211_channel *chan; @@ -3422,6 +3425,7 @@ struct cfg80211_mgmt_tx_params { bool dont_wait_for_ack; int n_csa_offsets; const u16 *csa_offsets; + int link_id; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5275dcbc5ee8..ffb7c573e299 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -764,6 +764,10 @@ * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA * counters which will be updated to the current value. This attribute * is used during CSA period. + * For TX on an MLD, the frequency can be omitted and the link ID be + * specified, or if transmitting to a known peer MLD (with MLD addresses + * in the frame) both can be omitted and the link will be selected by + * lower layers. * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may * be included to indicate the ack TX timestamp. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 60b8406b8d7e..2705e3ee8fc4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12256,6 +12256,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) wdev_unlock(wdev); return -EBUSY; } + + params.link_id = nl80211_link_id_or_invalid(info->attrs); + /* + * This now races due to the unlock, but we cannot check + * the valid links for the _station_ anyway, so that's up + * to the driver. + */ + if (params.link_id >= 0 && + !(wdev->valid_links & BIT(params.link_id))) { + wdev_unlock(wdev); + return -EINVAL; + } wdev_unlock(wdev); params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); -- cgit v1.2.3 From e1e68b14c5f85f2ad43d06a1b2f0d0fcc8dbdd62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jul 2022 21:36:08 +0200 Subject: wifi: mac80211: expand ieee80211_mgmt_tx() for MLO There are a couple of new things that should be possible with MLO: * selecting the link to transmit to a station by link ID, which a previous patch added to the nl80211 API * selecting the link by frequency, similarly * allowing transmittion to an MLD without specifying any channel or link ID, with MLD addresses Enable these use cases. Also fix the address comparison in client mode to use the AP (MLD) address. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 +++- net/mac80211/agg-tx.c | 4 ++-- net/mac80211/ieee80211_i.h | 8 ++++---- net/mac80211/offchannel.c | 47 ++++++++++++++++++++++++++++++++-------------- net/mac80211/rx.c | 2 +- net/mac80211/tx.c | 11 ++++++++--- 6 files changed, 51 insertions(+), 25 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e9f8be7ba9a6..1afd45239fe6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -885,7 +885,9 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this * frame should be transmitted on the specific link. This really is * only relevant for frames that do not have data present, and is - * also not used for 802.3 format frames. + * also not used for 802.3 format frames. Note that even if the frame + * is on a specific link, address translation might still apply if + * it's intended for an MLD. * * These flags are used in tx_info->control.flags. */ diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b13f4b7b740d..07c892aa8c73 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -106,7 +106,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(start_seq_num << 4); - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb_tid(sdata, skb, tid, -1); } void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) @@ -135,7 +135,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | IEEE80211_TX_CTL_REQ_TX_STATUS; - ieee80211_tx_skb_tid(sdata, skb, tid); + ieee80211_tx_skb_tid(sdata, skb, tid, -1); } EXPORT_SYMBOL(ieee80211_send_bar); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5fc4392ba507..4ec6fb96ba41 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2141,7 +2141,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct sk_buff *skb); void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid, + struct sk_buff *skb, int tid, int link_id, enum nl80211_band band); /* sta_out needs to be checked for ERR_PTR() before using */ @@ -2155,18 +2155,18 @@ ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, enum nl80211_band band) { rcu_read_lock(); - __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + __ieee80211_tx_skb_tid_band(sdata, skb, tid, -1, band); rcu_read_unlock(); } void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid); + struct sk_buff *skb, int tid, int link_id); static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ - ieee80211_tx_skb_tid(sdata, skb, 7); + ieee80211_tx_skb_tid(sdata, skb, 7, -1); } /** diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index be79ae68754e..d78c82d6b696 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -769,9 +769,11 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; - struct sta_info *sta; + struct sta_info *sta = NULL; const struct ieee80211_mgmt *mgmt = (void *)params->buf; bool need_offchan = false; + bool mlo_sta = false; + int link_id = -1; u32 flags; int ret; u8 *data; @@ -804,16 +806,30 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, !ieee80211_vif_is_mesh(&sdata->vif) && !sdata->bss->active) need_offchan = true; + + rcu_read_lock(); + sta = sta_info_get_bss(sdata, mgmt->da); + mlo_sta = sta && sta->sta.mlo; + if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED || - mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) + mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { + rcu_read_unlock(); break; - rcu_read_lock(); - sta = sta_info_get_bss(sdata, mgmt->da); - rcu_read_unlock(); - if (!sta) + } + + if (!sta) { + rcu_read_unlock(); return -ENOLINK; + } + if (params->link_id >= 0 && + !(sta->sta.valid_links & BIT(params->link_id))) { + rcu_read_unlock(); + return -ENOLINK; + } + link_id = params->link_id; + rcu_read_unlock(); break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -821,8 +837,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (!sdata->u.mgd.associated || (params->offchan && params->wait && local->ops->remain_on_channel && - memcmp(sdata->deflink.u.mgd.bssid, - mgmt->bssid, ETH_ALEN))) + memcmp(sdata->vif.cfg.ap_addr, mgmt->bssid, ETH_ALEN))) need_offchan = true; sdata_unlock(sdata); break; @@ -843,7 +858,9 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, mutex_lock(&local->mtx); /* Check if the operating channel is the requested channel */ - if (!need_offchan) { + if (!params->chan && mlo_sta) { + need_offchan = false; + } else if (!need_offchan) { struct ieee80211_chanctx_conf *chanctx_conf = NULL; int i; @@ -860,6 +877,12 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, if (!chanctx_conf) continue; + if (mlo_sta && params->chan == chanctx_conf->def.chan && + ether_addr_equal(sdata->vif.addr, mgmt->sa)) { + link_id = i; + break; + } + if (ether_addr_equal(conf->addr, mgmt->sa)) break; @@ -870,10 +893,6 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, need_offchan = params->chan && (params->chan != chanctx_conf->def.chan); - } else if (!params->chan) { - ret = -EINVAL; - rcu_read_unlock(); - goto out_unlock; } else { need_offchan = true; } @@ -943,7 +962,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, } if (!need_offchan) { - ieee80211_tx_skb(sdata, skb); + ieee80211_tx_skb_tid(sdata, skb, 7, link_id); ret = 0; goto out_unlock; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6cb5989c6ae2..58ff2cc7bcc9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3774,7 +3774,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) local->hw.offchannel_tx_hw_queue; } - __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, + __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1, status->band); } dev_kfree_skb(rx->skb); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 06ec152e8188..f24565064f08 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5647,7 +5647,7 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) EXPORT_SYMBOL(ieee80211_unreserve_tid); void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid, + struct sk_buff *skb, int tid, int link_id, enum nl80211_band band) { const struct ieee80211_hdr *hdr = (void *)skb->data; @@ -5666,6 +5666,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, if (!sdata->vif.valid_links) { link = 0; + } else if (link_id >= 0) { + link = link_id; } else if (memcmp(sdata->vif.addr, hdr->addr2, ETH_ALEN) == 0) { /* address from the MLD */ link = IEEE80211_LINK_UNSPECIFIED; @@ -5702,13 +5704,14 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, } void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid) + struct sk_buff *skb, int tid, int link_id) { struct ieee80211_chanctx_conf *chanctx_conf; enum nl80211_band band; rcu_read_lock(); if (!sdata->vif.valid_links) { + WARN_ON(link_id >= 0); chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { @@ -5718,11 +5721,13 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, } band = chanctx_conf->def.chan->band; } else { + WARN_ON(link_id >= 0 && + !(sdata->vif.valid_links & BIT(link_id))); /* MLD transmissions must not rely on the band */ band = 0; } - __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + __ieee80211_tx_skb_tid_band(sdata, skb, tid, link_id, band); rcu_read_unlock(); } -- cgit v1.2.3 From 963d0e8d08d97f9133b9fd00354ebc1a2467484b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jul 2022 10:56:48 +0200 Subject: wifi: mac80211: optionally implement MLO multicast TX For drivers using software encryption for multicast TX, such as mac80211_hwsim, mac80211 needs to duplicate the multicast frames on each link, if MLO is enabled. Do this, but don't just make it dependent on the key but provide a separate flag for drivers to opt out of this. This is not very efficient, I expect that drivers will do it in firmware/hardware or at least with DMA engine assistence, so this is mostly for hwsim. To make this work, also implement the SNS11 sequence number space that an AP MLD shall have, and modify the API to the __ieee80211_subif_start_xmit() function to always require the link ID bits to be set. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 10 +++++ net/mac80211/debugfs.c | 3 +- net/mac80211/ieee80211_i.h | 1 + net/mac80211/tdls.c | 3 +- net/mac80211/tx.c | 91 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 97 insertions(+), 11 deletions(-) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1afd45239fe6..1e04961148bf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -882,6 +882,8 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_DONT_REORDER: This frame should not be reordered * relative to other frames that have this flag set, independent * of their QoS TID or other priority field values. + * @IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX: first MLO TX, used mostly internally + * for sequence number assignment * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this * frame should be transmitted on the specific link. This really is * only relevant for frames that do not have data present, and is @@ -901,10 +903,14 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6), IEEE80211_TX_CTRL_NO_SEQNO = BIT(7), IEEE80211_TX_CTRL_DONT_REORDER = BIT(8), + IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX = BIT(9), IEEE80211_TX_CTRL_MLO_LINK = 0xf0000000, }; #define IEEE80211_LINK_UNSPECIFIED 0xf +#define IEEE80211_TX_CTRL_MLO_LINK_UNSPEC \ + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, \ + IEEE80211_TX_CTRL_MLO_LINK) /** * enum mac80211_tx_status_flags - flags to describe transmit status @@ -2524,6 +2530,9 @@ struct ieee80211_txq { * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color * collision detection and doesn't need it in software. * + * @IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX: Hardware/driver handles transmitting + * multicast frames on all links, mac80211 should not do that. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2580,6 +2589,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP, IEEE80211_HW_DETECTS_COLOR_COLLISION, + IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 4d4341249759..78c7d60e8667 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -4,7 +4,7 @@ * * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018 - 2019, 2021 Intel Corporation + * Copyright (C) 2018 - 2019, 2021-2022 Intel Corporation */ #include @@ -495,6 +495,7 @@ static const char *hw_flag_names[] = { FLAG(SUPPORTS_RX_DECAP_OFFLOAD), FLAG(SUPPORTS_CONC_MON_RX_DECAP), FLAG(DETECTS_COLOR_COLLISION), + FLAG(MLO_MCAST_MULTI_LINK_TX), #undef FLAG }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4ec6fb96ba41..f93b57799e94 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1029,6 +1029,7 @@ struct ieee80211_sub_if_data { struct ieee80211_key __rcu *default_unicast_key; u16 sequence_number; + u16 mld_mcast_seq; __be16 control_port_protocol; bool control_port_no_encrypt; bool control_port_no_preauth; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 36bfc54b3d2d..f4b4d25eef95 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1054,7 +1054,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, /* disable bottom halves when entering the Tx path */ local_bh_disable(); - __ieee80211_subif_start_xmit(skb, dev, flags, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, flags, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL); local_bh_enable(); return ret; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f24565064f08..45df9932d0ba 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -822,6 +822,16 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) if (info->control.flags & IEEE80211_TX_CTRL_NO_SEQNO) return TX_CONTINUE; + /* SNS11 from 802.11be 10.3.2.14 */ + if (unlikely(is_multicast_ether_addr(hdr->addr1) && + info->control.vif->valid_links && + info->control.vif->type == NL80211_IFTYPE_AP)) { + if (info->control.flags & IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX) + tx->sdata->mld_mcast_seq += 0x10; + hdr->seq_ctrl = cpu_to_le16(tx->sdata->mld_mcast_seq); + return TX_CONTINUE; + } + /* * Anything but QoS data that has a sequence number field * (is long enough) gets a sequence number from the global @@ -2570,7 +2580,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; - u8 link_id = IEEE80211_LINK_UNSPECIFIED; + u8 link_id = u32_get_bits(ctrl_flags, IEEE80211_TX_CTRL_MLO_LINK); if (IS_ERR(sta)) sta = NULL; @@ -2630,8 +2640,18 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, goto free; } memcpy(hdr.addr2, link->conf->addr, ETH_ALEN); - } else { + } else if (link_id == IEEE80211_LINK_UNSPECIFIED) { memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + } else { + struct ieee80211_bss_conf *conf; + + conf = rcu_dereference(sdata->vif.link_conf[link_id]); + if (unlikely(!conf)) { + ret = -ENOLINK; + goto free; + } + + memcpy(hdr.addr2, conf->addr, ETH_ALEN); } memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); @@ -4222,9 +4242,6 @@ static bool ieee80211_multicast_to_unicast(struct sk_buff *skb, const struct vlan_ethhdr *ethvlan = (void *)skb->data; __be16 ethertype; - if (likely(!is_multicast_ether_addr(eth->h_dest))) - return false; - switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: if (sdata->u.vlan.sta) @@ -4308,6 +4325,44 @@ out: rcu_read_unlock(); } +static void ieee80211_mlo_multicast_tx_one(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, u32 ctrl_flags, + unsigned int link_id) +{ + struct sk_buff *out; + + out = skb_copy(skb, GFP_ATOMIC); + if (!out) + return; + + ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + __ieee80211_subif_start_xmit(out, sdata->dev, 0, ctrl_flags, NULL); +} + +static void ieee80211_mlo_multicast_tx(struct net_device *dev, + struct sk_buff *skb) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + unsigned long links = sdata->vif.valid_links; + unsigned int link; + u32 ctrl_flags = IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX; + + if (hweight16(links) == 1) { + ctrl_flags |= u32_encode_bits(ffs(links) - 1, + IEEE80211_TX_CTRL_MLO_LINK); + + __ieee80211_subif_start_xmit(skb, sdata->dev, 0, ctrl_flags, + NULL); + return; + } + + for_each_set_bit(link, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + ieee80211_mlo_multicast_tx_one(sdata, skb, ctrl_flags, link); + ctrl_flags = 0; + } + kfree_skb(skb); +} + /** * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs * @skb: packet to be sent @@ -4318,15 +4373,30 @@ out: netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + const struct ethhdr *eth = (void *)skb->data; + + if (likely(!is_multicast_ether_addr(eth->h_dest))) + goto normal; + if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) { struct sk_buff_head queue; __skb_queue_head_init(&queue); ieee80211_convert_to_unicast(skb, dev, &queue); while ((skb = __skb_dequeue(&queue))) - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); + } else if (sdata->vif.valid_links && + sdata->vif.type == NL80211_IFTYPE_AP && + !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) { + ieee80211_mlo_multicast_tx(dev, skb); } else { - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); +normal: + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); } return NETDEV_TX_OK; @@ -4410,7 +4480,9 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, if (tid_tx) { if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { /* fall back to non-offload slow path */ - __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); + __ieee80211_subif_start_xmit(skb, dev, 0, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, + NULL); return; } @@ -4512,7 +4584,8 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, goto out; } - skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0, NULL); + skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, + IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL); if (IS_ERR(skb)) goto out; -- cgit v1.2.3 From 9f781533bb028edb3e8e10e79fb87e85a4dc6987 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 12 Jul 2022 12:22:50 +0300 Subject: wifi: mac80211: add macros to loop over active links Add a preliminary version which will be updated later to loop over vif's and sta's active links. Signed-off-by: Gregory Greenman Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include/net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1e04961148bf..f198af600b5e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1856,6 +1856,13 @@ struct ieee80211_vif { u8 drv_priv[] __aligned(sizeof(void *)); }; +/* FIXME: for now loop over all the available links; later will be changed + * to loop only over the active links. + */ +#define for_each_vif_active_link(vif, link, link_id) \ + for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \ + if ((link = rcu_dereference((vif)->link_conf[link_id]))) + static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) { #ifdef CONFIG_MAC80211_MESH @@ -2248,6 +2255,14 @@ struct ieee80211_sta { u8 drv_priv[] __aligned(sizeof(void *)); }; +/* FIXME: need to loop only over links which are active and check the actual + * lock + */ +#define for_each_sta_active_link(sta, link_sta, link_id) \ + for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \ + if (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\ + 1))) \ + /** * enum sta_notify_cmd - sta notify command * -- cgit v1.2.3 From ec2904c259c56fbe50aacd838da9553a6eea6683 Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Thu, 21 Jul 2022 16:22:23 -0700 Subject: Bluetooth: Remove dead code from hci_request.c The discov_update work queue is no longer used as a result of the hci_sync rework. The __hci_req_hci_power_on() function is no longer referenced in the code as a result of the hci_sync rework. Signed-off-by: Brian Gix Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_request.c | 287 --------------------------------------- net/bluetooth/hci_request.h | 2 - 3 files changed, 290 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index df7dac4a5bbd..83bbeffe71e9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -517,7 +517,6 @@ struct hci_dev { struct work_struct cmd_work; struct work_struct tx_work; - struct work_struct discov_update; struct work_struct scan_update; struct delayed_work le_scan_disable; struct delayed_work le_scan_restart; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 38ecaf9264ee..5a01bf997500 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -2227,146 +2227,6 @@ unlock: hci_dev_unlock(hdev); } -static int active_scan(struct hci_request *req, unsigned long opt) -{ - uint16_t interval = opt; - struct hci_dev *hdev = req->hdev; - u8 own_addr_type; - /* Accept list is not used for discovery */ - u8 filter_policy = 0x00; - /* Default is to enable duplicates filter */ - u8 filter_dup = LE_SCAN_FILTER_DUP_ENABLE; - /* Discovery doesn't require controller address resolution */ - bool addr_resolv = false; - int err; - - bt_dev_dbg(hdev, ""); - - /* If controller is scanning, it means the background scanning is - * running. Thus, we should temporarily stop it in order to set the - * discovery scanning parameters. - */ - if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) { - hci_req_add_le_scan_disable(req, false); - cancel_interleave_scan(hdev); - } - - /* All active scans will be done with either a resolvable private - * address (when privacy feature has been enabled) or non-resolvable - * private address. - */ - err = hci_update_random_address(req, true, scan_use_rpa(hdev), - &own_addr_type); - if (err < 0) - own_addr_type = ADDR_LE_DEV_PUBLIC; - - hci_dev_lock(hdev); - if (hci_is_adv_monitoring(hdev)) { - /* Duplicate filter should be disabled when some advertisement - * monitor is activated, otherwise AdvMon can only receive one - * advertisement for one peer(*) during active scanning, and - * might report loss to these peers. - * - * Note that different controllers have different meanings of - * |duplicate|. Some of them consider packets with the same - * address as duplicate, and others consider packets with the - * same address and the same RSSI as duplicate. Although in the - * latter case we don't need to disable duplicate filter, but - * it is common to have active scanning for a short period of - * time, the power impact should be neglectable. - */ - filter_dup = LE_SCAN_FILTER_DUP_DISABLE; - } - hci_dev_unlock(hdev); - - hci_req_start_scan(req, LE_SCAN_ACTIVE, interval, - hdev->le_scan_window_discovery, own_addr_type, - filter_policy, filter_dup, addr_resolv); - return 0; -} - -static int interleaved_discov(struct hci_request *req, unsigned long opt) -{ - int err; - - bt_dev_dbg(req->hdev, ""); - - err = active_scan(req, opt); - if (err) - return err; - - return bredr_inquiry(req, DISCOV_BREDR_INQUIRY_LEN); -} - -static void start_discovery(struct hci_dev *hdev, u8 *status) -{ - unsigned long timeout; - - bt_dev_dbg(hdev, "type %u", hdev->discovery.type); - - switch (hdev->discovery.type) { - case DISCOV_TYPE_BREDR: - if (!hci_dev_test_flag(hdev, HCI_INQUIRY)) - hci_req_sync(hdev, bredr_inquiry, - DISCOV_BREDR_INQUIRY_LEN, HCI_CMD_TIMEOUT, - status); - return; - case DISCOV_TYPE_INTERLEAVED: - /* When running simultaneous discovery, the LE scanning time - * should occupy the whole discovery time sine BR/EDR inquiry - * and LE scanning are scheduled by the controller. - * - * For interleaving discovery in comparison, BR/EDR inquiry - * and LE scanning are done sequentially with separate - * timeouts. - */ - if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, - &hdev->quirks)) { - timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); - /* During simultaneous discovery, we double LE scan - * interval. We must leave some time for the controller - * to do BR/EDR inquiry. - */ - hci_req_sync(hdev, interleaved_discov, - hdev->le_scan_int_discovery * 2, HCI_CMD_TIMEOUT, - status); - break; - } - - timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout); - hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery, - HCI_CMD_TIMEOUT, status); - break; - case DISCOV_TYPE_LE: - timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); - hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery, - HCI_CMD_TIMEOUT, status); - break; - default: - *status = HCI_ERROR_UNSPECIFIED; - return; - } - - if (*status) - return; - - bt_dev_dbg(hdev, "timeout %u ms", jiffies_to_msecs(timeout)); - - /* When service discovery is used and the controller has a - * strict duplicate filter, it is important to remember the - * start and duration of the scan. This is required for - * restarting scanning during the discovery phase. - */ - if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) && - hdev->discovery.result_filtering) { - hdev->discovery.scan_start = jiffies; - hdev->discovery.scan_duration = timeout; - } - - queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_disable, - timeout); -} - bool hci_req_stop_discovery(struct hci_request *req) { struct hci_dev *hdev = req->hdev; @@ -2462,42 +2322,6 @@ error: return err; } -static int stop_discovery(struct hci_request *req, unsigned long opt) -{ - hci_dev_lock(req->hdev); - hci_req_stop_discovery(req); - hci_dev_unlock(req->hdev); - - return 0; -} - -static void discov_update(struct work_struct *work) -{ - struct hci_dev *hdev = container_of(work, struct hci_dev, - discov_update); - u8 status = 0; - - switch (hdev->discovery.state) { - case DISCOVERY_STARTING: - start_discovery(hdev, &status); - mgmt_start_discovery_complete(hdev, status); - if (status) - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - else - hci_discovery_set_state(hdev, DISCOVERY_FINDING); - break; - case DISCOVERY_STOPPING: - hci_req_sync(hdev, stop_discovery, 0, HCI_CMD_TIMEOUT, &status); - mgmt_stop_discovery_complete(hdev, status); - if (!status) - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - break; - case DISCOVERY_STOPPED: - default: - return; - } -} - static void discov_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, @@ -2522,118 +2346,8 @@ static void discov_off(struct work_struct *work) mgmt_new_settings(hdev); } -static int powered_update_hci(struct hci_request *req, unsigned long opt) -{ - struct hci_dev *hdev = req->hdev; - u8 link_sec; - - hci_dev_lock(hdev); - - if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) && - !lmp_host_ssp_capable(hdev)) { - u8 mode = 0x01; - - hci_req_add(req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); - - if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) { - u8 support = 0x01; - - hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, - sizeof(support), &support); - } - } - - if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) && - lmp_bredr_capable(hdev)) { - struct hci_cp_write_le_host_supported cp; - - cp.le = 0x01; - cp.simul = 0x00; - - /* Check first if we already have the right - * host state (host features set) - */ - if (cp.le != lmp_host_le_capable(hdev) || - cp.simul != lmp_host_le_br_capable(hdev)) - hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(cp), &cp); - } - - if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { - /* Make sure the controller has a good default for - * advertising data. This also applies to the case - * where BR/EDR was toggled during the AUTO_OFF phase. - */ - if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || - list_empty(&hdev->adv_instances)) { - int err; - - if (ext_adv_capable(hdev)) { - err = __hci_req_setup_ext_adv_instance(req, - 0x00); - if (!err) - __hci_req_update_scan_rsp_data(req, - 0x00); - } else { - err = 0; - __hci_req_update_adv_data(req, 0x00); - __hci_req_update_scan_rsp_data(req, 0x00); - } - - if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) { - if (!ext_adv_capable(hdev)) - __hci_req_enable_advertising(req); - else if (!err) - __hci_req_enable_ext_advertising(req, - 0x00); - } - } else if (!list_empty(&hdev->adv_instances)) { - struct adv_info *adv_instance; - - adv_instance = list_first_entry(&hdev->adv_instances, - struct adv_info, list); - __hci_req_schedule_adv_instance(req, - adv_instance->instance, - true); - } - } - - link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY); - if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) - hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, - sizeof(link_sec), &link_sec); - - if (lmp_bredr_capable(hdev)) { - if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) - __hci_req_write_fast_connectable(req, true); - else - __hci_req_write_fast_connectable(req, false); - __hci_req_update_scan(req); - __hci_req_update_class(req); - __hci_req_update_name(req); - __hci_req_update_eir(req); - } - - hci_dev_unlock(hdev); - return 0; -} - -int __hci_req_hci_power_on(struct hci_dev *hdev) -{ - /* Register the available SMP channels (BR/EDR and LE) only when - * successfully powering on the controller. This late - * registration is required so that LE SMP can clearly decide if - * the public address or static address is used. - */ - smp_register(hdev); - - return __hci_req_sync(hdev, powered_update_hci, 0, HCI_CMD_TIMEOUT, - NULL); -} - void hci_request_setup(struct hci_dev *hdev) { - INIT_WORK(&hdev->discov_update, discov_update); INIT_WORK(&hdev->scan_update, scan_update_work); INIT_DELAYED_WORK(&hdev->discov_off, discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); @@ -2646,7 +2360,6 @@ void hci_request_cancel_all(struct hci_dev *hdev) { __hci_cmd_sync_cancel(hdev, ENODEV); - cancel_work_sync(&hdev->discov_update); cancel_work_sync(&hdev->scan_update); cancel_delayed_work_sync(&hdev->discov_off); cancel_delayed_work_sync(&hdev->le_scan_disable); diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 7f8df258e295..2b2fba278510 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -68,8 +68,6 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req, struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param); -int __hci_req_hci_power_on(struct hci_dev *hdev); - void __hci_req_write_fast_connectable(struct hci_request *req, bool enable); void __hci_req_update_name(struct hci_request *req); void __hci_req_update_eir(struct hci_request *req); -- cgit v1.2.3 From bb87672562f871edd7a220222dd2480a87294580 Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Thu, 21 Jul 2022 16:22:24 -0700 Subject: Bluetooth: Remove update_scan hci_request dependancy This removes the remaining calls to HCI_OP_WRITE_SCAN_ENABLE from hci_request call chains, and converts them to hci_sync calls. Signed-off-by: Brian Gix Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 1 - include/net/bluetooth/hci_sync.h | 1 + net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_request.c | 17 ----------------- net/bluetooth/hci_request.h | 5 ----- net/bluetooth/hci_sync.c | 10 ++++++++++ net/bluetooth/mgmt.c | 8 ++++---- 7 files changed, 17 insertions(+), 29 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 83bbeffe71e9..df65b107b596 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -517,7 +517,6 @@ struct hci_dev { struct work_struct cmd_work; struct work_struct tx_work; - struct work_struct scan_update; struct delayed_work le_scan_disable; struct delayed_work le_scan_restart; diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 544e949b5dbf..5c4d4cace9c3 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -78,6 +78,7 @@ int hci_read_clock_sync(struct hci_dev *hdev, struct hci_cp_read_clock *cp); int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable); int hci_update_scan_sync(struct hci_dev *hdev); +int hci_update_scan(struct hci_dev *hdev); int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul); int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 34bec7446d00..b32ca92fc692 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3173,7 +3173,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); - hci_req_update_scan(hdev); + hci_update_scan(hdev); } /* Set packet type for incoming connection */ @@ -3371,7 +3371,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) hci_remove_link_key(hdev, &conn->dst); - hci_req_update_scan(hdev); + hci_update_scan(hdev); } params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 5a01bf997500..0ce486afbf43 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1835,21 +1835,6 @@ void __hci_req_update_scan(struct hci_request *req) hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } -static int update_scan(struct hci_request *req, unsigned long opt) -{ - hci_dev_lock(req->hdev); - __hci_req_update_scan(req); - hci_dev_unlock(req->hdev); - return 0; -} - -static void scan_update_work(struct work_struct *work) -{ - struct hci_dev *hdev = container_of(work, struct hci_dev, scan_update); - - hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL); -} - static u8 get_service_classes(struct hci_dev *hdev) { struct bt_uuid *uuid; @@ -2348,7 +2333,6 @@ static void discov_off(struct work_struct *work) void hci_request_setup(struct hci_dev *hdev) { - INIT_WORK(&hdev->scan_update, scan_update_work); INIT_DELAYED_WORK(&hdev->discov_off, discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); @@ -2360,7 +2344,6 @@ void hci_request_cancel_all(struct hci_dev *hdev) { __hci_cmd_sync_cancel(hdev, ENODEV); - cancel_work_sync(&hdev->scan_update); cancel_delayed_work_sync(&hdev->discov_off); cancel_delayed_work_sync(&hdev->le_scan_disable); cancel_delayed_work_sync(&hdev->le_scan_restart); diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 2b2fba278510..821244ad9d73 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -108,11 +108,6 @@ bool hci_req_stop_discovery(struct hci_request *req); int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec); -static inline void hci_req_update_scan(struct hci_dev *hdev) -{ - queue_work(hdev->req_workqueue, &hdev->scan_update); -} - void __hci_req_update_scan(struct hci_request *req); int hci_update_random_address(struct hci_request *req, bool require_privacy, diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 1fbeee970aa7..46a04488d614 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2236,6 +2236,16 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev) return err; } +static int update_scan_sync(struct hci_dev *hdev, void *data) +{ + return hci_update_scan_sync(hdev); +} + +int hci_update_scan(struct hci_dev *hdev) +{ + return hci_cmd_sync_queue(hdev, update_scan_sync, NULL, NULL); +} + static int update_passive_scan_sync(struct hci_dev *hdev, void *data) { return hci_update_passive_scan_sync(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index aa651129b714..153206763f00 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1611,7 +1611,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev, return err; if (changed) { - hci_req_update_scan(hdev); + hci_update_scan(hdev); hci_update_passive_scan(hdev); return new_settings(hdev, sk); } @@ -7081,7 +7081,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, if (err) goto unlock; - hci_req_update_scan(hdev); + hci_update_scan(hdev); goto added; } @@ -7193,7 +7193,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - hci_req_update_scan(hdev); + hci_update_scan(hdev); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); @@ -7257,7 +7257,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, kfree(b); } - hci_req_update_scan(hdev); + hci_update_scan(hdev); list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_DISABLED) -- cgit v1.2.3 From dfe6d5c3ec23c5b999261d989059aa35403d791d Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 4 Feb 2022 13:04:38 -0800 Subject: Bluetooth: hci_core: Introduce hci_recv_event_data This introduces hci_recv_event_data to make it simpler to access the contents of last received event rather than having to pass its contents to the likes of *_ind/*_cfm callbacks. Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 32 ++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 3 +++ 3 files changed, 37 insertions(+) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index df65b107b596..6569b123b49e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -525,6 +525,7 @@ struct hci_dev { struct sk_buff_head cmd_q; struct sk_buff *sent_cmd; + struct sk_buff *recv_event; struct mutex req_lock; wait_queue_head_t req_wait_q; @@ -1747,6 +1748,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); +void *hci_recv_event_data(struct hci_dev *hdev, __u8 event); u32 hci_conn_get_phy(struct hci_conn *conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e42824e82758..924c29517918 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2712,6 +2712,7 @@ void hci_release_dev(struct hci_dev *hdev) ida_simple_remove(&hci_index_ida, hdev->id); kfree_skb(hdev->sent_cmd); + kfree_skb(hdev->recv_event); kfree(hdev); } EXPORT_SYMBOL(hci_release_dev); @@ -3018,6 +3019,37 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; } +/* Get data from last received event */ +void *hci_recv_event_data(struct hci_dev *hdev, __u8 event) +{ + struct hci_event_hdr *hdr; + int offset; + + if (!hdev->recv_event) + return NULL; + + hdr = (void *)hdev->recv_event->data; + offset = sizeof(*hdr); + + if (hdr->evt != event) { + /* In case of LE metaevent check the subevent match */ + if (hdr->evt == HCI_EV_LE_META) { + struct hci_ev_le_meta *ev; + + ev = (void *)hdev->recv_event->data + offset; + offset += sizeof(*ev); + if (ev->subevent == event) + goto found; + } + return NULL; + } + +found: + bt_dev_dbg(hdev, "event 0x%2.2x", event); + + return hdev->recv_event->data + offset; +} + /* Send ACL data */ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b32ca92fc692..bab52ee99b11 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6936,6 +6936,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) goto done; } + kfree_skb(hdev->recv_event); + hdev->recv_event = skb_clone(skb, GFP_KERNEL); + event = hdr->evt; if (!event) { bt_dev_warn(hdev, "Received unexpected HCI Event 0x%2.2x", -- cgit v1.2.3 From 26afbd826ee326e63a334c37fd45e82e50a615ec Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 29 Jul 2019 18:15:43 +0300 Subject: Bluetooth: Add initial implementation of CIS connections This adds the initial implementation of CIS connections and introduces the ISO packets/links. == Central: Set CIG Parameters, create a CIS and Setup Data Path == > tools/isotest -s
< HCI Command: LE Extended Create... (0x08|0x0043) plen 26 ... > HCI Event: Command Status (0x0f) plen 4 LE Extended Create Connection (0x08|0x0043) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 31 LE Enhanced Connection Complete (0x0a) ... < HCI Command: LE Create Connected... (0x08|0x0064) plen 5 ... > HCI Event: Command Status (0x0f) plen 4 LE Create Connected Isochronous Stream (0x08|0x0064) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 29 LE Connected Isochronous Stream Established (0x19) ... < HCI Command: LE Setup Isochronou.. (0x08|0x006e) plen 13 ... > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 257 < HCI Command: LE Setup Isochronou.. (0x08|0x006e) plen 13 ... > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 257 == Peripheral: Accept CIS and Setup Data Path == > tools/isotest -d HCI Event: LE Meta Event (0x3e) plen 7 LE Connected Isochronous Stream Request (0x1a) ... < HCI Command: LE Accept Co.. (0x08|0x0066) plen 2 ... > HCI Event: LE Meta Event (0x3e) plen 29 LE Connected Isochronous Stream Established (0x19) ... < HCI Command: LE Setup Is.. (0x08|0x006e) plen 13 ... > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 257 < HCI Command: LE Setup Is.. (0x08|0x006e) plen 13 ... > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 257 Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 33 ++- include/net/bluetooth/hci.h | 28 ++- include/net/bluetooth/hci_core.h | 107 ++++++++- include/net/bluetooth/hci_sock.h | 2 + include/net/bluetooth/hci_sync.h | 3 + net/bluetooth/Kconfig | 1 + net/bluetooth/hci_conn.c | 440 ++++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_core.c | 230 ++++++++++++++++---- net/bluetooth/hci_event.c | 307 +++++++++++++++++++++++++- net/bluetooth/hci_sync.c | 49 ++++- 10 files changed, 1145 insertions(+), 55 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 686ce2591bb2..72af9722244a 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -55,6 +55,8 @@ #define BTPROTO_CMTP 5 #define BTPROTO_HIDP 6 #define BTPROTO_AVDTP 7 +#define BTPROTO_ISO 8 +#define BTPROTO_LAST BTPROTO_ISO #define SOL_HCI 0 #define SOL_L2CAP 6 @@ -149,10 +151,39 @@ struct bt_voice { #define BT_MODE_LE_FLOWCTL 0x03 #define BT_MODE_EXT_FLOWCTL 0x04 -#define BT_PKT_STATUS 16 +#define BT_PKT_STATUS 16 #define BT_SCM_PKT_STATUS 0x03 +#define BT_ISO_QOS 17 + +#define BT_ISO_QOS_CIG_UNSET 0xff +#define BT_ISO_QOS_CIS_UNSET 0xff + +struct bt_iso_io_qos { + __u32 interval; + __u16 latency; + __u16 sdu; + __u8 phy; + __u8 rtn; +}; + +struct bt_iso_qos { + __u8 cig; + __u8 cis; + __u8 sca; + __u8 packing; + __u8 framing; + struct bt_iso_io_qos in; + struct bt_iso_io_qos out; +}; + +#define BT_ISO_PHY_1M 0x01 +#define BT_ISO_PHY_2M 0x02 +#define BT_ISO_PHY_CODED 0x04 +#define BT_ISO_PHY_ANY (BT_ISO_PHY_1M | BT_ISO_PHY_2M | \ + BT_ISO_PHY_CODED) + #define BT_CODEC 19 struct bt_codec_caps { diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 927f51b92854..027f1bc6e4f1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1989,7 +1989,7 @@ struct hci_rp_le_read_iso_tx_sync { struct hci_cis_params { __u8 cis_id; __le16 c_sdu; - __le16 p_pdu; + __le16 p_sdu; __u8 c_phy; __u8 p_phy; __u8 c_rtn; @@ -2000,7 +2000,7 @@ struct hci_cp_le_set_cig_params { __u8 cig_id; __u8 c_interval[3]; __u8 p_interval[3]; - __u8 wc_sca; + __u8 sca; __u8 packing; __u8 framing; __le16 c_latency; @@ -2043,6 +2043,30 @@ struct hci_cp_le_reject_cis { __u8 reason; } __packed; +#define HCI_OP_LE_SETUP_ISO_PATH 0x206e +struct hci_cp_le_setup_iso_path { + __le16 handle; + __u8 direction; + __u8 path; + __u8 codec; + __le16 codec_cid; + __le16 codec_vid; + __u8 delay[3]; + __u8 codec_cfg_len; + __u8 codec_cfg[0]; +} __packed; + +struct hci_rp_le_setup_iso_path { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_SET_HOST_FEATURE 0x2074 +struct hci_cp_le_set_host_feature { + __u8 bit_number; + __u8 bit_value; +} __packed; + /* ---- HCI Events ---- */ struct hci_ev_status { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6569b123b49e..5fac013ff2b0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,7 @@ struct hci_conn_hash { unsigned int acl_num; unsigned int amp_num; unsigned int sco_num; + unsigned int iso_num; unsigned int le_num; unsigned int le_num_peripheral; }; @@ -474,13 +475,16 @@ struct hci_dev { unsigned int acl_cnt; unsigned int sco_cnt; unsigned int le_cnt; + unsigned int iso_cnt; unsigned int acl_mtu; unsigned int sco_mtu; unsigned int le_mtu; + unsigned int iso_mtu; unsigned int acl_pkts; unsigned int sco_pkts; unsigned int le_pkts; + unsigned int iso_pkts; __u16 block_len; __u16 block_mtu; @@ -657,6 +661,7 @@ enum conn_reasons { CONN_REASON_PAIR_DEVICE, CONN_REASON_L2CAP_CHAN, CONN_REASON_SCO_CONNECT, + CONN_REASON_ISO_CONNECT, }; struct hci_conn { @@ -709,6 +714,7 @@ struct hci_conn { __s8 rssi; __s8 tx_power; __s8 max_tx_power; + struct bt_iso_qos iso_qos; unsigned long flags; enum conn_reasons conn_reason; @@ -739,6 +745,7 @@ struct hci_conn { struct hci_dev *hdev; void *l2cap_data; void *sco_data; + void *iso_data; struct amp_mgr *amp_mgr; struct hci_conn *link; @@ -747,6 +754,8 @@ struct hci_conn { void (*connect_cfm_cb) (struct hci_conn *conn, u8 status); void (*security_cfm_cb) (struct hci_conn *conn, u8 status); void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason); + + void (*cleanup)(struct hci_conn *conn); }; struct hci_chan { @@ -954,6 +963,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) case ESCO_LINK: h->sco_num++; break; + case ISO_LINK: + h->iso_num++; + break; } } @@ -980,6 +992,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) case ESCO_LINK: h->sco_num--; break; + case ISO_LINK: + h->iso_num--; + break; } } @@ -996,6 +1011,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) case SCO_LINK: case ESCO_LINK: return h->sco_num; + case ISO_LINK: + return h->iso_num; default: return 0; } @@ -1005,7 +1022,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev) { struct hci_conn_hash *c = &hdev->conn_hash; - return c->acl_num + c->amp_num + c->sco_num + c->le_num; + return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num; } static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle) @@ -1091,6 +1108,53 @@ static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev, return NULL; } +static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev, + bdaddr_t *ba, + __u8 ba_type) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type != ISO_LINK) + continue; + + if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) { + rcu_read_unlock(); + return c; + } + } + + rcu_read_unlock(); + + return NULL; +} + +static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev, + __u8 handle) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type != ISO_LINK) + continue; + + if (handle == c->iso_qos.cig) { + rcu_read_unlock(); + return c; + } + } + + rcu_read_unlock(); + + return NULL; +} + static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, __u8 type, __u16 state) { @@ -1111,6 +1175,27 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, return NULL; } +typedef void (*hci_conn_func_t)(struct hci_conn *conn, void *data); +static inline void hci_conn_hash_list_state(struct hci_dev *hdev, + hci_conn_func_t func, __u8 type, + __u16 state, void *data) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + if (!func) + return; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == type && c->state == state) + func(c, data); + } + + rcu_read_unlock(); +} + static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; @@ -1134,6 +1219,8 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev) int hci_disconnect(struct hci_conn *conn, __u8 reason); bool hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_sco_setup(struct hci_conn *conn, __u8 status); +bool hci_iso_setup_path(struct hci_conn *conn); +int hci_le_create_cis(struct hci_conn *conn); struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, u8 role); @@ -1158,6 +1245,10 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, enum conn_reasons conn_reason); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting, struct bt_codec *codec); +struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); +struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, @@ -1525,6 +1616,15 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define use_enhanced_conn_complete(dev) (ll_privacy_capable(dev) || \ ext_adv_capable(dev)) +/* CIS Master/Slave support */ +#define iso_capable(dev) (cis_capable(dev)) +#define cis_capable(dev) \ + (cis_central_capable(dev) || cis_peripheral_capable(dev)) +#define cis_central_capable(dev) \ + ((dev)->le_features[3] & HCI_LE_CIS_CENTRAL) +#define cis_peripheral_capable(dev) \ + ((dev)->le_features[3] & HCI_LE_CIS_PERIPHERAL) + /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 @@ -1539,6 +1639,10 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, case ESCO_LINK: return sco_connect_ind(hdev, bdaddr, flags); + case ISO_LINK: + /* TODO: Handle connection indication */ + return -EINVAL; + default: BT_ERR("unknown link type %d", type); return -EINVAL; @@ -1746,6 +1850,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, const void *param); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); +void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); void *hci_recv_event_data(struct hci_dev *hdev, __u8 event); diff --git a/include/net/bluetooth/hci_sock.h b/include/net/bluetooth/hci_sock.h index 9949870f7d78..0520e21ab698 100644 --- a/include/net/bluetooth/hci_sock.h +++ b/include/net/bluetooth/hci_sock.h @@ -124,6 +124,8 @@ struct hci_dev_info { __u16 acl_pkts; __u16 sco_mtu; __u16 sco_pkts; + __u16 iso_mtu; + __u16 iso_pkts; struct hci_dev_stats stat; }; diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 5c4d4cace9c3..c243cb6869d8 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -109,3 +109,6 @@ struct hci_conn; int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason); int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn); + +int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle); +int hci_le_remove_cig(struct hci_dev *hdev, u8 handle); diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index e0ab4cd7afc3..ae3bdc6dfc92 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -29,6 +29,7 @@ menuconfig BT SCO audio links L2CAP (Logical Link Control and Adaptation Protocol) SMP (Security Manager Protocol) on LE (Low Energy) links + ISO isochronous links HCI Device drivers (Interface to the hardware) RFCOMM Module (RFCOMM Protocol) BNEP Module (Bluetooth Network Encapsulation Protocol) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1ce89c469293..97568723ddb0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -125,6 +125,9 @@ static void hci_conn_cleanup(struct hci_conn *conn) hci_conn_hash_del(hdev, conn); + if (conn->cleanup) + conn->cleanup(conn); + if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { switch (conn->setting & SCO_AIRMODE_MASK) { case SCO_AIRMODE_CVSD: @@ -722,6 +725,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; case LE_LINK: + case ISO_LINK: /* conn->src should reflect the local identity address */ hci_copy_identity_address(hdev, &conn->src, &conn->src_type); break; @@ -1232,6 +1236,442 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, return sco; } +struct iso_list_data { + u8 cig; + u8 cis; + int count; + struct { + struct hci_cp_le_set_cig_params cp; + struct hci_cis_params cis[0x11]; + } pdu; +}; + +static void cis_add(struct iso_list_data *d, struct bt_iso_qos *qos) +{ + struct hci_cis_params *cis = &d->pdu.cis[d->pdu.cp.num_cis]; + + cis->cis_id = qos->cis; + cis->c_sdu = cpu_to_le16(qos->out.sdu); + cis->p_sdu = cpu_to_le16(qos->in.sdu); + cis->c_phy = qos->out.phy; + cis->p_phy = qos->in.phy; + cis->c_rtn = qos->out.rtn; + cis->p_rtn = qos->in.rtn; + + d->pdu.cp.num_cis++; +} + +static void cis_list(struct hci_conn *conn, void *data) +{ + struct iso_list_data *d = data; + + if (d->cig != conn->iso_qos.cig || d->cis == BT_ISO_QOS_CIS_UNSET || + d->cis != conn->iso_qos.cis) + return; + + d->count++; + + if (d->pdu.cp.cig_id == BT_ISO_QOS_CIG_UNSET || + d->count >= ARRAY_SIZE(d->pdu.cis)) + return; + + cis_add(d, &conn->iso_qos); +} + +static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) +{ + struct hci_dev *hdev = conn->hdev; + struct iso_list_data data; + + memset(&data, 0, sizeof(data)); + + /* Allocate a CIG if not set */ + if (qos->cig == BT_ISO_QOS_CIG_UNSET) { + for (data.cig = 0x00; data.cig < 0xff; data.cig++) { + data.count = 0; + data.cis = 0xff; + + hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, + BT_BOUND, &data); + if (data.count) + continue; + + hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, + BT_CONNECTED, &data); + if (!data.count) + break; + } + + if (data.cig == 0xff) + return false; + + /* Update CIG */ + qos->cig = data.cig; + } + + data.pdu.cp.cig_id = qos->cig; + hci_cpu_to_le24(qos->out.interval, data.pdu.cp.c_interval); + hci_cpu_to_le24(qos->in.interval, data.pdu.cp.p_interval); + data.pdu.cp.sca = qos->sca; + data.pdu.cp.packing = qos->packing; + data.pdu.cp.framing = qos->framing; + data.pdu.cp.c_latency = cpu_to_le16(qos->out.latency); + data.pdu.cp.p_latency = cpu_to_le16(qos->in.latency); + + if (qos->cis != BT_ISO_QOS_CIS_UNSET) { + data.count = 0; + data.cig = qos->cig; + data.cis = qos->cis; + + hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, BT_BOUND, + &data); + if (data.count) + return false; + + cis_add(&data, qos); + } + + /* Reprogram all CIS(s) with the same CIG */ + for (data.cig = qos->cig, data.cis = 0x00; data.cis < 0x11; + data.cis++) { + data.count = 0; + + hci_conn_hash_list_state(hdev, cis_list, ISO_LINK, BT_BOUND, + &data); + if (data.count) + continue; + + /* Allocate a CIS if not set */ + if (qos->cis == BT_ISO_QOS_CIS_UNSET) { + /* Update CIS */ + qos->cis = data.cis; + cis_add(&data, qos); + } + } + + if (qos->cis == BT_ISO_QOS_CIS_UNSET || !data.pdu.cp.num_cis) + return false; + + if (hci_send_cmd(hdev, HCI_OP_LE_SET_CIG_PARAMS, + sizeof(data.pdu.cp) + + (data.pdu.cp.num_cis * sizeof(*data.pdu.cis)), + &data.pdu) < 0) + return false; + + return true; +} + +static void find_cis(struct hci_conn *conn, void *data) +{ + struct iso_list_data *d = data; + + /* Ignore broadcast */ + if (!bacmp(&conn->dst, BDADDR_ANY)) + return; + + d->count++; +} + +static int remove_cig_sync(struct hci_dev *hdev, void *data) +{ + u8 handle = PTR_ERR(data); + + return hci_le_remove_cig_sync(hdev, handle); +} + +int hci_le_remove_cig(struct hci_dev *hdev, u8 handle) +{ + bt_dev_dbg(hdev, "handle 0x%2.2x", handle); + + return hci_cmd_sync_queue(hdev, remove_cig_sync, ERR_PTR(handle), NULL); +} + +static void cis_cleanup(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + struct iso_list_data d; + + memset(&d, 0, sizeof(d)); + d.cig = conn->iso_qos.cig; + + /* Check if ISO connection is a CIS and remove CIG if there are + * no other connections using it. + */ + hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d); + if (d.count) + return; + + hci_le_remove_cig(hdev, conn->iso_qos.cig); +} + +struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos) +{ + struct hci_conn *cis; + + cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type); + if (!cis) { + cis = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); + if (!cis) + return ERR_PTR(-ENOMEM); + cis->cleanup = cis_cleanup; + } + + if (cis->state == BT_CONNECTED) + return cis; + + /* Check if CIS has been set and the settings matches */ + if (cis->state == BT_BOUND && + !memcmp(&cis->iso_qos, qos, sizeof(*qos))) + return cis; + + /* Update LINK PHYs according to QoS preference */ + cis->le_tx_phy = qos->out.phy; + cis->le_rx_phy = qos->in.phy; + + /* If output interval is not set use the input interval as it cannot be + * 0x000000. + */ + if (!qos->out.interval) + qos->out.interval = qos->in.interval; + + /* If input interval is not set use the output interval as it cannot be + * 0x000000. + */ + if (!qos->in.interval) + qos->in.interval = qos->out.interval; + + /* If output latency is not set use the input latency as it cannot be + * 0x0000. + */ + if (!qos->out.latency) + qos->out.latency = qos->in.latency; + + /* If input latency is not set use the output latency as it cannot be + * 0x0000. + */ + if (!qos->in.latency) + qos->in.latency = qos->out.latency; + + /* Mirror PHYs that are disabled as SDU will be set to 0 */ + if (!qos->in.phy) + qos->in.phy = qos->out.phy; + + if (!qos->out.phy) + qos->out.phy = qos->in.phy; + + if (!hci_le_set_cig_params(cis, qos)) { + hci_conn_drop(cis); + return ERR_PTR(-EINVAL); + } + + cis->iso_qos = *qos; + cis->state = BT_BOUND; + + return cis; +} + +bool hci_iso_setup_path(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_cp_le_setup_iso_path cmd; + + memset(&cmd, 0, sizeof(cmd)); + + if (conn->iso_qos.out.sdu) { + cmd.handle = cpu_to_le16(conn->handle); + cmd.direction = 0x00; /* Input (Host to Controller) */ + cmd.path = 0x00; /* HCI path if enabled */ + cmd.codec = 0x03; /* Transparent Data */ + + if (hci_send_cmd(hdev, HCI_OP_LE_SETUP_ISO_PATH, sizeof(cmd), + &cmd) < 0) + return false; + } + + if (conn->iso_qos.in.sdu) { + cmd.handle = cpu_to_le16(conn->handle); + cmd.direction = 0x01; /* Output (Controller to Host) */ + cmd.path = 0x00; /* HCI path if enabled */ + cmd.codec = 0x03; /* Transparent Data */ + + if (hci_send_cmd(hdev, HCI_OP_LE_SETUP_ISO_PATH, sizeof(cmd), + &cmd) < 0) + return false; + } + + return true; +} + +static int hci_create_cis_sync(struct hci_dev *hdev, void *data) +{ + struct { + struct hci_cp_le_create_cis cp; + struct hci_cis cis[0x1f]; + } cmd; + struct hci_conn *conn = data; + u8 cig; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cis[0].acl_handle = cpu_to_le16(conn->link->handle); + cmd.cis[0].cis_handle = cpu_to_le16(conn->handle); + cmd.cp.num_cis++; + cig = conn->iso_qos.cig; + + hci_dev_lock(hdev); + + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { + struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis]; + + if (conn == data || conn->type != ISO_LINK || + conn->state == BT_CONNECTED || conn->iso_qos.cig != cig) + continue; + + /* Check if all CIS(s) belonging to a CIG are ready */ + if (conn->link->state != BT_CONNECTED || + conn->state != BT_CONNECT) { + cmd.cp.num_cis = 0; + break; + } + + /* Group all CIS with state BT_CONNECT since the spec don't + * allow to send them individually: + * + * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E + * page 2566: + * + * If the Host issues this command before all the + * HCI_LE_CIS_Established events from the previous use of the + * command have been generated, the Controller shall return the + * error code Command Disallowed (0x0C). + */ + cis->acl_handle = cpu_to_le16(conn->link->handle); + cis->cis_handle = cpu_to_le16(conn->handle); + cmd.cp.num_cis++; + } + + rcu_read_unlock(); + + hci_dev_unlock(hdev); + + if (!cmd.cp.num_cis) + return 0; + + return hci_send_cmd(hdev, HCI_OP_LE_CREATE_CIS, sizeof(cmd.cp) + + sizeof(cmd.cis[0]) * cmd.cp.num_cis, &cmd); +} + +int hci_le_create_cis(struct hci_conn *conn) +{ + struct hci_conn *cis; + struct hci_dev *hdev = conn->hdev; + int err; + + switch (conn->type) { + case LE_LINK: + if (!conn->link || conn->state != BT_CONNECTED) + return -EINVAL; + cis = conn->link; + break; + case ISO_LINK: + cis = conn; + break; + default: + return -EINVAL; + } + + if (cis->state == BT_CONNECT) + return 0; + + /* Queue Create CIS */ + err = hci_cmd_sync_queue(hdev, hci_create_cis_sync, cis, NULL); + if (err) + return err; + + cis->state = BT_CONNECT; + + return 0; +} + +static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, + struct bt_iso_io_qos *qos, __u8 phy) +{ + /* Only set MTU if PHY is enabled */ + if (!qos->sdu && qos->phy) { + if (hdev->iso_mtu > 0) + qos->sdu = hdev->iso_mtu; + else if (hdev->le_mtu > 0) + qos->sdu = hdev->le_mtu; + else + qos->sdu = hdev->acl_mtu; + } + + /* Use the same PHY as ACL if set to any */ + if (qos->phy == BT_ISO_PHY_ANY) + qos->phy = phy; + + /* Use LE ACL connection interval if not set */ + if (!qos->interval) + /* ACL interval unit in 1.25 ms to us */ + qos->interval = conn->le_conn_interval * 1250; + + /* Use LE ACL connection latency if not set */ + if (!qos->latency) + qos->latency = conn->le_conn_latency; +} + +struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos) +{ + struct hci_conn *le; + struct hci_conn *cis; + + /* Convert from ISO socket address type to HCI address type */ + if (dst_type == BDADDR_LE_PUBLIC) + dst_type = ADDR_LE_DEV_PUBLIC; + else + dst_type = ADDR_LE_DEV_RANDOM; + + if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) + le = hci_connect_le(hdev, dst, dst_type, false, + BT_SECURITY_LOW, + HCI_LE_CONN_TIMEOUT, + HCI_ROLE_SLAVE); + else + le = hci_connect_le_scan(hdev, dst, dst_type, + BT_SECURITY_LOW, + HCI_LE_CONN_TIMEOUT, + CONN_REASON_ISO_CONNECT); + if (IS_ERR(le)) + return le; + + hci_iso_qos_setup(hdev, le, &qos->out, + le->le_tx_phy ? le->le_tx_phy : hdev->le_tx_def_phys); + hci_iso_qos_setup(hdev, le, &qos->in, + le->le_rx_phy ? le->le_rx_phy : hdev->le_rx_def_phys); + + cis = hci_bind_cis(hdev, dst, dst_type, qos); + if (IS_ERR(cis)) { + hci_conn_drop(le); + return cis; + } + + le->link = cis; + cis->link = le; + + hci_conn_hold(cis); + + /* If LE is already connected and CIS handle is already set proceed to + * Create CIS immediately. + */ + if (le->state == BT_CONNECTED && cis->handle != HCI_CONN_HANDLE_UNSET) + hci_le_create_cis(le); + + return cis; +} + /* Check link security requirement */ int hci_conn_check_link_mode(struct hci_conn *conn) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 924c29517918..2b7947dca14d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -616,7 +616,10 @@ static int hci_dev_do_reset(struct hci_dev *hdev) hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); atomic_set(&hdev->cmd_cnt, 1); - hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; + hdev->acl_cnt = 0; + hdev->sco_cnt = 0; + hdev->le_cnt = 0; + hdev->iso_cnt = 0; ret = hci_reset_sync(hdev); @@ -3157,9 +3160,117 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) queue_work(hdev->workqueue, &hdev->tx_work); } +/* Send ISO data */ +static void hci_add_iso_hdr(struct sk_buff *skb, __u16 handle, __u8 flags) +{ + struct hci_iso_hdr *hdr; + int len = skb->len; + + skb_push(skb, HCI_ISO_HDR_SIZE); + skb_reset_transport_header(skb); + hdr = (struct hci_iso_hdr *)skb_transport_header(skb); + hdr->handle = cpu_to_le16(hci_handle_pack(handle, flags)); + hdr->dlen = cpu_to_le16(len); +} + +static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, + struct sk_buff *skb) +{ + struct hci_dev *hdev = conn->hdev; + struct sk_buff *list; + __u16 flags; + + skb->len = skb_headlen(skb); + skb->data_len = 0; + + hci_skb_pkt_type(skb) = HCI_ISODATA_PKT; + + list = skb_shinfo(skb)->frag_list; + + flags = hci_iso_flags_pack(list ? ISO_START : ISO_SINGLE, 0x00); + hci_add_iso_hdr(skb, conn->handle, flags); + + if (!list) { + /* Non fragmented */ + BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); + + skb_queue_tail(queue, skb); + } else { + /* Fragmented */ + BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + skb_shinfo(skb)->frag_list = NULL; + + __skb_queue_tail(queue, skb); + + do { + skb = list; list = list->next; + + hci_skb_pkt_type(skb) = HCI_ISODATA_PKT; + flags = hci_iso_flags_pack(list ? ISO_CONT : ISO_END, + 0x00); + hci_add_iso_hdr(skb, conn->handle, flags); + + BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + __skb_queue_tail(queue, skb); + } while (list); + } +} + +void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("%s len %d", hdev->name, skb->len); + + hci_queue_iso(conn, &conn->data_q, skb); + + queue_work(hdev->workqueue, &hdev->tx_work); +} + /* ---- HCI TX task (outgoing data) ---- */ /* HCI Connection scheduler */ +static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) +{ + struct hci_dev *hdev; + int cnt, q; + + if (!conn) { + *quote = 0; + return; + } + + hdev = conn->hdev; + + switch (conn->type) { + case ACL_LINK: + cnt = hdev->acl_cnt; + break; + case AMP_LINK: + cnt = hdev->block_cnt; + break; + case SCO_LINK: + case ESCO_LINK: + cnt = hdev->sco_cnt; + break; + case LE_LINK: + cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; + break; + case ISO_LINK: + cnt = hdev->iso_mtu ? hdev->iso_cnt : + hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; + break; + default: + cnt = 0; + bt_dev_err(hdev, "unknown link type %d", conn->type); + } + + q = cnt / num; + *quote = q ? q : 1; +} + static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) { @@ -3192,29 +3303,7 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, rcu_read_unlock(); - if (conn) { - int cnt, q; - - switch (conn->type) { - case ACL_LINK: - cnt = hdev->acl_cnt; - break; - case SCO_LINK: - case ESCO_LINK: - cnt = hdev->sco_cnt; - break; - case LE_LINK: - cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; - break; - default: - cnt = 0; - bt_dev_err(hdev, "unknown link type %d", conn->type); - } - - q = cnt / num; - *quote = q ? q : 1; - } else - *quote = 0; + hci_quote_sent(conn, num, quote); BT_DBG("conn %p quote %d", conn, *quote); return conn; @@ -3248,7 +3337,7 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, struct hci_chan *chan = NULL; unsigned int num = 0, min = ~0, cur_prio = 0; struct hci_conn *conn; - int cnt, q, conn_num = 0; + int conn_num = 0; BT_DBG("%s", hdev->name); @@ -3298,27 +3387,8 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, if (!chan) return NULL; - switch (chan->conn->type) { - case ACL_LINK: - cnt = hdev->acl_cnt; - break; - case AMP_LINK: - cnt = hdev->block_cnt; - break; - case SCO_LINK: - case ESCO_LINK: - cnt = hdev->sco_cnt; - break; - case LE_LINK: - cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; - break; - default: - cnt = 0; - bt_dev_err(hdev, "unknown link type %d", chan->conn->type); - } + hci_quote_sent(chan->conn, num, quote); - q = cnt / num; - *quote = q ? q : 1; BT_DBG("chan %p quote %d", chan, *quote); return chan; } @@ -3607,18 +3677,46 @@ static void hci_sched_le(struct hci_dev *hdev) hci_prio_recalculate(hdev, LE_LINK); } +/* Schedule CIS */ +static void hci_sched_iso(struct hci_dev *hdev) +{ + struct hci_conn *conn; + struct sk_buff *skb; + int quote, *cnt; + + BT_DBG("%s", hdev->name); + + if (!hci_conn_num(hdev, ISO_LINK)) + return; + + cnt = hdev->iso_pkts ? &hdev->iso_cnt : + hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt; + while (*cnt && (conn = hci_low_sent(hdev, ISO_LINK, "e))) { + while (quote-- && (skb = skb_dequeue(&conn->data_q))) { + BT_DBG("skb %p len %d", skb, skb->len); + hci_send_frame(hdev, skb); + + conn->sent++; + if (conn->sent == ~0) + conn->sent = 0; + (*cnt)--; + } + } +} + static void hci_tx_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); struct sk_buff *skb; - BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, - hdev->sco_cnt, hdev->le_cnt); + BT_DBG("%s acl %d sco %d le %d iso %d", hdev->name, hdev->acl_cnt, + hdev->sco_cnt, hdev->le_cnt, hdev->iso_cnt); if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { /* Schedule queues and send stuff to HCI driver */ hci_sched_sco(hdev); hci_sched_esco(hdev); + hci_sched_iso(hdev); hci_sched_acl(hdev); hci_sched_le(hdev); } @@ -3701,6 +3799,39 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); } +static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_iso_hdr *hdr; + struct hci_conn *conn; + __u16 handle, flags; + + hdr = skb_pull_data(skb, sizeof(*hdr)); + if (!hdr) { + bt_dev_err(hdev, "ISO packet too small"); + goto drop; + } + + handle = __le16_to_cpu(hdr->handle); + flags = hci_flags(handle); + handle = hci_handle(handle); + + bt_dev_dbg(hdev, "len %d handle 0x%4.4x flags 0x%4.4x", skb->len, + handle, flags); + + hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_handle(hdev, handle); + hci_dev_unlock(hdev); + + /* TODO: Send to upper protocol */ + if (!conn) { + bt_dev_err(hdev, "ISO packet for unknown connection handle %d", + handle); + } + +drop: + kfree_skb(skb); +} + static bool hci_req_is_complete(struct hci_dev *hdev) { struct sk_buff *skb; @@ -3862,6 +3993,11 @@ static void hci_rx_work(struct work_struct *work) hci_scodata_packet(hdev, skb); break; + case HCI_ISODATA_PKT: + BT_DBG("%s ISO data packet", hdev->name); + hci_isodata_packet(hdev, skb); + break; + default: kfree_skb(skb); break; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bab52ee99b11..37177d7051d5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3775,6 +3775,124 @@ static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev, u8 ncmd) } } +static u8 hci_cc_le_read_buffer_size_v2(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_rp_le_read_buffer_size_v2 *rp = data; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); + + if (rp->status) + return rp->status; + + hdev->le_mtu = __le16_to_cpu(rp->acl_mtu); + hdev->le_pkts = rp->acl_max_pkt; + hdev->iso_mtu = __le16_to_cpu(rp->iso_mtu); + hdev->iso_pkts = rp->iso_max_pkt; + + hdev->le_cnt = hdev->le_pkts; + hdev->iso_cnt = hdev->iso_pkts; + + BT_DBG("%s acl mtu %d:%d iso mtu %d:%d", hdev->name, hdev->acl_mtu, + hdev->acl_pkts, hdev->iso_mtu, hdev->iso_pkts); + + return rp->status; +} + +static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_rp_le_set_cig_params *rp = data; + struct hci_conn *conn; + int i = 0; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); + + hci_dev_lock(hdev); + + if (rp->status) { + while ((conn = hci_conn_hash_lookup_cig(hdev, rp->cig_id))) { + conn->state = BT_CLOSED; + hci_connect_cfm(conn, rp->status); + hci_conn_del(conn); + } + goto unlock; + } + + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { + if (conn->type != ISO_LINK || conn->iso_qos.cig != rp->cig_id || + conn->state == BT_CONNECTED) + continue; + + conn->handle = __le16_to_cpu(rp->handle[i++]); + + bt_dev_dbg(hdev, "%p handle 0x%4.4x link %p", conn, + conn->handle, conn->link); + + /* Create CIS if LE is already connected */ + if (conn->link && conn->link->state == BT_CONNECTED) + hci_le_create_cis(conn->link); + + if (i == rp->num_handles) + break; + } + + rcu_read_unlock(); + +unlock: + hci_dev_unlock(hdev); + + return rp->status; +} + +static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_rp_le_setup_iso_path *rp = data; + struct hci_cp_le_setup_iso_path *cp; + struct hci_conn *conn; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SETUP_ISO_PATH); + if (!cp) + return rp->status; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (!conn) + goto unlock; + + if (rp->status) { + hci_connect_cfm(conn, rp->status); + hci_conn_del(conn); + goto unlock; + } + + switch (cp->direction) { + /* Input (Host to Controller) */ + case 0x00: + /* Only confirm connection if output only */ + if (conn->iso_qos.out.sdu && !conn->iso_qos.in.sdu) + hci_connect_cfm(conn, rp->status); + break; + /* Output (Controller to Host) */ + case 0x01: + /* Confirm connection since conn->iso_qos is always configured + * last. + */ + hci_connect_cfm(conn, rp->status); + break; + } + +unlock: + hci_dev_unlock(hdev); + return rp->status; +} + #define HCI_CC_VL(_op, _func, _min, _max) \ { \ .op = _op, \ @@ -3950,7 +4068,13 @@ static const struct hci_cc { HCI_CC_STATUS(HCI_OP_LE_CLEAR_ADV_SETS, hci_cc_le_clear_adv_sets), HCI_CC(HCI_OP_LE_READ_TRANSMIT_POWER, hci_cc_le_read_transmit_power, sizeof(struct hci_rp_le_read_transmit_power)), - HCI_CC_STATUS(HCI_OP_LE_SET_PRIVACY_MODE, hci_cc_le_set_privacy_mode) + HCI_CC_STATUS(HCI_OP_LE_SET_PRIVACY_MODE, hci_cc_le_set_privacy_mode), + HCI_CC(HCI_OP_LE_READ_BUFFER_SIZE_V2, hci_cc_le_read_buffer_size_v2, + sizeof(struct hci_rp_le_read_buffer_size_v2)), + HCI_CC_VL(HCI_OP_LE_SET_CIG_PARAMS, hci_cc_le_set_cig_params, + sizeof(struct hci_rp_le_set_cig_params), HCI_MAX_EVENT_SIZE), + HCI_CC(HCI_OP_LE_SETUP_ISO_PATH, hci_cc_le_setup_iso_path, + sizeof(struct hci_rp_le_setup_iso_path)), }; static u8 hci_cc_func(struct hci_dev *hdev, const struct hci_cc *cc, @@ -4013,6 +4137,40 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data, queue_work(hdev->workqueue, &hdev->cmd_work); } +static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_le_create_cis *cp; + int i; + + bt_dev_dbg(hdev, "status 0x%2.2x", status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CIS); + if (!cp) + return; + + hci_dev_lock(hdev); + + /* Remove connection if command failed */ + for (i = 0; cp->num_cis; cp->num_cis--, i++) { + struct hci_conn *conn; + u16 handle; + + handle = __le16_to_cpu(cp->cis[i].cis_handle); + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (conn) { + conn->state = BT_CLOSED; + hci_connect_cfm(conn, status); + hci_conn_del(conn); + } + } + + hci_dev_unlock(hdev); +} + #define HCI_CS(_op, _func) \ { \ .op = _op, \ @@ -4042,7 +4200,8 @@ static const struct hci_cs { HCI_CS(HCI_OP_LE_CREATE_CONN, hci_cs_le_create_conn), HCI_CS(HCI_OP_LE_READ_REMOTE_FEATURES, hci_cs_le_read_remote_features), HCI_CS(HCI_OP_LE_START_ENC, hci_cs_le_start_enc), - HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn) + HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn), + HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis), }; static void hci_cmd_status_evt(struct hci_dev *hdev, void *data, @@ -4178,6 +4337,22 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, hdev->sco_cnt = hdev->sco_pkts; break; + case ISO_LINK: + if (hdev->iso_pkts) { + hdev->iso_cnt += count; + if (hdev->iso_cnt > hdev->iso_pkts) + hdev->iso_cnt = hdev->iso_pkts; + } else if (hdev->le_pkts) { + hdev->le_cnt += count; + if (hdev->le_cnt > hdev->le_pkts) + hdev->le_cnt = hdev->le_pkts; + } else { + hdev->acl_cnt += count; + if (hdev->acl_cnt > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; + } + break; + default: bt_dev_err(hdev, "unknown type %d conn %p", conn->type, conn); @@ -6480,6 +6655,127 @@ unlock: hci_dev_unlock(hdev); } +static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_cis_established *ev = data; + struct hci_conn *conn; + u16 handle = __le16_to_cpu(ev->handle); + + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (!conn) { + bt_dev_err(hdev, + "Unable to find connection with handle 0x%4.4x", + handle); + goto unlock; + } + + if (conn->role == HCI_ROLE_SLAVE) { + __le32 interval; + + memset(&interval, 0, sizeof(interval)); + + memcpy(&interval, ev->c_latency, sizeof(ev->c_latency)); + conn->iso_qos.in.interval = le32_to_cpu(interval); + memcpy(&interval, ev->p_latency, sizeof(ev->p_latency)); + conn->iso_qos.out.interval = le32_to_cpu(interval); + conn->iso_qos.in.latency = le16_to_cpu(ev->interval); + conn->iso_qos.out.latency = le16_to_cpu(ev->interval); + conn->iso_qos.in.sdu = le16_to_cpu(ev->c_mtu); + conn->iso_qos.out.sdu = le16_to_cpu(ev->p_mtu); + conn->iso_qos.in.phy = ev->c_phy; + conn->iso_qos.out.phy = ev->p_phy; + } + + if (!ev->status) { + conn->state = BT_CONNECTED; + hci_debugfs_create_conn(conn); + hci_conn_add_sysfs(conn); + hci_iso_setup_path(conn); + goto unlock; + } + + hci_connect_cfm(conn, ev->status); + hci_conn_del(conn); + +unlock: + hci_dev_unlock(hdev); +} + +static void hci_le_reject_cis(struct hci_dev *hdev, __le16 handle) +{ + struct hci_cp_le_reject_cis cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = handle; + cp.reason = HCI_ERROR_REJ_BAD_ADDR; + hci_send_cmd(hdev, HCI_OP_LE_REJECT_CIS, sizeof(cp), &cp); +} + +static void hci_le_accept_cis(struct hci_dev *hdev, __le16 handle) +{ + struct hci_cp_le_accept_cis cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = handle; + hci_send_cmd(hdev, HCI_OP_LE_ACCEPT_CIS, sizeof(cp), &cp); +} + +static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_cis_req *ev = data; + u16 acl_handle, cis_handle; + struct hci_conn *acl, *cis; + int mask; + __u8 flags = 0; + + acl_handle = __le16_to_cpu(ev->acl_handle); + cis_handle = __le16_to_cpu(ev->cis_handle); + + bt_dev_dbg(hdev, "acl 0x%4.4x handle 0x%4.4x cig 0x%2.2x cis 0x%2.2x", + acl_handle, cis_handle, ev->cig_id, ev->cis_id); + + hci_dev_lock(hdev); + + acl = hci_conn_hash_lookup_handle(hdev, acl_handle); + if (!acl) + goto unlock; + + mask = hci_proto_connect_ind(hdev, &acl->dst, ISO_LINK, &flags); + if (!(mask & HCI_LM_ACCEPT)) { + hci_le_reject_cis(hdev, ev->cis_handle); + goto unlock; + } + + cis = hci_conn_hash_lookup_handle(hdev, cis_handle); + if (!cis) { + cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE); + if (!cis) { + hci_le_reject_cis(hdev, ev->cis_handle); + goto unlock; + } + cis->handle = cis_handle; + } + + cis->iso_qos.cig = ev->cig_id; + cis->iso_qos.cis = ev->cis_id; + + if (!(flags & HCI_PROTO_DEFER)) { + hci_le_accept_cis(hdev, ev->cis_handle); + } else { + cis->state = BT_CONNECT2; + hci_connect_cfm(cis, 0); + } + +unlock: + hci_dev_unlock(hdev); +} + #define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \ [_op] = { \ .func = _func, \ @@ -6543,6 +6839,12 @@ static const struct hci_le_ev { /* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */ HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt, sizeof(struct hci_evt_le_ext_adv_set_term)), + /* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */ + HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_estabilished_evt, + sizeof(struct hci_evt_le_cis_established)), + /* [0x1a = HCI_EVT_LE_CIS_REQ] */ + HCI_LE_EV(HCI_EVT_LE_CIS_REQ, hci_le_cis_req_evt, + sizeof(struct hci_evt_le_cis_req)), }; static void hci_le_meta_evt(struct hci_dev *hdev, void *data, @@ -6581,7 +6883,6 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data, if (skb->len > subev->max_len) bt_dev_warn(hdev, "unexpected subevent 0x%2.2x length: %u > %u", ev->subevent, skb->len, subev->max_len); - data = hci_le_ev_skb_pull(hdev, skb, ev->subevent, subev->min_len); if (!data) return; diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 46a04488d614..ac0f2cc0e44c 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2800,6 +2800,12 @@ static const struct hci_init_stage amp_init2[] = { /* Read Buffer Size (ACL mtu, max pkt, etc.) */ static int hci_read_buffer_size_sync(struct hci_dev *hdev) { + /* Use Read LE Buffer Size V2 if supported */ + if (hdev->commands[41] & 0x20) + return __hci_cmd_sync_status(hdev, + HCI_OP_LE_READ_BUFFER_SIZE_V2, + 0, NULL, HCI_CMD_TIMEOUT); + return __hci_cmd_sync_status(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL, HCI_CMD_TIMEOUT); } @@ -3051,6 +3057,10 @@ static int hci_init2_sync(struct hci_dev *hdev) if (hdev->dev_type == HCI_AMP) return hci_init_stage_sync(hdev, amp_init2); + err = hci_init_stage_sync(hdev, hci_init2); + if (err) + return err; + if (lmp_bredr_capable(hdev)) { err = hci_init_stage_sync(hdev, br_init2); if (err) @@ -3068,7 +3078,7 @@ static int hci_init2_sync(struct hci_dev *hdev) hci_dev_set_flag(hdev, HCI_LE_ENABLED); } - return hci_init_stage_sync(hdev, hci_init2); + return 0; } static int hci_set_event_mask_sync(struct hci_dev *hdev) @@ -3389,6 +3399,12 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev) if (ext_adv_capable(hdev)) events[2] |= 0x02; /* LE Advertising Set Terminated */ + if (cis_capable(hdev)) { + events[3] |= 0x01; /* LE CIS Established */ + if (cis_peripheral_capable(hdev)) + events[3] |= 0x02; /* LE CIS Request */ + } + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events, HCI_CMD_TIMEOUT); } @@ -3529,6 +3545,24 @@ static int hci_set_le_support_sync(struct hci_dev *hdev) sizeof(cp), &cp, HCI_CMD_TIMEOUT); } +/* LE Set Host Feature */ +static int hci_le_set_host_feature_sync(struct hci_dev *hdev) +{ + struct hci_cp_le_set_host_feature cp; + + if (!iso_capable(hdev)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + /* Isochronous Channels (Host Support) */ + cp.bit_number = 32; + cp.bit_value = 1; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_HOST_FEATURE, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + /* LE Controller init stage 3 command sequence */ static const struct hci_init_stage le_init3[] = { /* HCI_OP_LE_SET_EVENT_MASK */ @@ -3555,6 +3589,8 @@ static const struct hci_init_stage le_init3[] = { HCI_INIT(hci_le_read_num_support_adv_sets_sync), /* HCI_OP_WRITE_LE_HOST_SUPPORTED */ HCI_INIT(hci_set_le_support_sync), + /* HCI_OP_LE_SET_HOST_FEATURE */ + HCI_INIT(hci_le_set_host_feature_sync), {} }; @@ -5437,3 +5473,14 @@ done: hci_resume_advertising_sync(hdev); return err; } + +int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle) +{ + struct hci_cp_le_remove_cig cp; + + memset(&cp, 0, sizeof(cp)); + cp.cig_id = handle; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_REMOVE_CIG, sizeof(cp), + &cp, HCI_CMD_TIMEOUT); +} -- cgit v1.2.3 From ccf74f2390d60a2f9a75ef496d2564abb478f46a Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 16 Jan 2020 15:55:57 -0800 Subject: Bluetooth: Add BTPROTO_ISO socket type This introduces a new socket type BTPROTO_ISO which can be enabled with use of ISO Socket experiemental UUID, it can used to initiate/accept connections and transfer packets between userspace and kernel similarly to how BTPROTO_SCO works: Central -> uses connect with address set to destination bdaddr: > tools/isotest -s 00:AA:01:00:00:00 Peripheral -> uses listen: > tools/isotest -d Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 21 + include/net/bluetooth/hci_core.h | 18 +- include/net/bluetooth/iso.h | 21 + net/bluetooth/Makefile | 1 + net/bluetooth/af_bluetooth.c | 4 +- net/bluetooth/hci_core.c | 6 +- net/bluetooth/iso.c | 1501 +++++++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 69 +- 8 files changed, 1636 insertions(+), 5 deletions(-) create mode 100644 include/net/bluetooth/iso.h create mode 100644 net/bluetooth/iso.c (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 72af9722244a..df2c006fc6a9 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -590,6 +590,27 @@ static inline void sco_exit(void) } #endif +#if IS_ENABLED(CONFIG_BT_LE) +int iso_init(void); +int iso_exit(void); +bool iso_enabled(void); +#else +static inline int iso_init(void) +{ + return 0; +} + +static inline int iso_exit(void) +{ + return 0; +} + +static inline bool iso_enabled(void) +{ + return false; +} +#endif + int mgmt_init(void); void mgmt_exit(void); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5fac013ff2b0..3457c24e9b19 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -843,6 +843,21 @@ static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) } #endif +#if IS_ENABLED(CONFIG_BT_LE) +int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); +void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); +#else +static inline int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 *flags) +{ + return 0; +} +static inline void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, + u16 flags) +{ +} +#endif + /* ----- Inquiry cache ----- */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ #define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ @@ -1640,8 +1655,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, return sco_connect_ind(hdev, bdaddr, flags); case ISO_LINK: - /* TODO: Handle connection indication */ - return -EINVAL; + return iso_connect_ind(hdev, bdaddr, flags); default: BT_ERR("unknown link type %d", type); diff --git a/include/net/bluetooth/iso.h b/include/net/bluetooth/iso.h new file mode 100644 index 000000000000..13b22d54aab5 --- /dev/null +++ b/include/net/bluetooth/iso.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation + */ + +#ifndef __ISO_H +#define __ISO_H + +/* ISO defaults */ +#define ISO_DEFAULT_MTU 251 + +/* ISO socket address */ +struct sockaddr_iso { + sa_family_t iso_family; + bdaddr_t iso_bdaddr; + __u8 iso_bdaddr_type; +}; + +#endif /* __ISO_H */ diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index a52bba8500e1..0e7b7db42750 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -18,6 +18,7 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ eir.o hci_sync.o bluetooth-$(CONFIG_BT_BREDR) += sco.o +bluetooth-$(CONFIG_BT_LE) += iso.o bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o bluetooth-$(CONFIG_BT_LEDS) += leds.o bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index b506409bb498..dc65974f5adb 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -38,7 +38,7 @@ #include "selftest.h" /* Bluetooth sockets */ -#define BT_MAX_PROTO 8 +#define BT_MAX_PROTO (BTPROTO_LAST + 1) static const struct net_proto_family *bt_proto[BT_MAX_PROTO]; static DEFINE_RWLOCK(bt_proto_lock); @@ -52,6 +52,7 @@ static const char *const bt_key_strings[BT_MAX_PROTO] = { "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP", "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP", "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", + "sk_lock-AF_BLUETOOTH-BTPROTO_ISO", }; static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; @@ -64,6 +65,7 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_CMTP", "slock-AF_BLUETOOTH-BTPROTO_HIDP", "slock-AF_BLUETOOTH-BTPROTO_AVDTP", + "slock-AF_BLUETOOTH-BTPROTO_ISO", }; void bt_sock_reclassify_lock(struct sock *sk, int proto) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2b7947dca14d..193d4e664acd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3822,12 +3822,16 @@ static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_handle(hdev, handle); hci_dev_unlock(hdev); - /* TODO: Send to upper protocol */ if (!conn) { bt_dev_err(hdev, "ISO packet for unknown connection handle %d", handle); + goto drop; } + /* Send to upper protocol */ + iso_recv(conn, skb, flags); + return; + drop: kfree_skb(skb); } diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c new file mode 100644 index 000000000000..caaaa670cc2c --- /dev/null +++ b/net/bluetooth/iso.c @@ -0,0 +1,1501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation + */ + +#include +#include +#include +#include + +#include +#include +#include + +static const struct proto_ops iso_sock_ops; + +static struct bt_sock_list iso_sk_list = { + .lock = __RW_LOCK_UNLOCKED(iso_sk_list.lock) +}; + +/* ---- ISO connections ---- */ +struct iso_conn { + struct hci_conn *hcon; + + /* @lock: spinlock protecting changes to iso_conn fields */ + spinlock_t lock; + struct sock *sk; + + struct delayed_work timeout_work; + + struct sk_buff *rx_skb; + __u32 rx_len; + __u16 tx_sn; +}; + +#define iso_conn_lock(c) spin_lock(&(c)->lock) +#define iso_conn_unlock(c) spin_unlock(&(c)->lock) + +static void iso_sock_close(struct sock *sk); +static void iso_sock_kill(struct sock *sk); + +/* ----- ISO socket info ----- */ +#define iso_pi(sk) ((struct iso_pinfo *)sk) + +struct iso_pinfo { + struct bt_sock bt; + bdaddr_t src; + __u8 src_type; + bdaddr_t dst; + __u8 dst_type; + __u32 flags; + struct bt_iso_qos qos; + struct iso_conn *conn; +}; + +/* ---- ISO timers ---- */ +#define ISO_CONN_TIMEOUT (HZ * 40) +#define ISO_DISCONN_TIMEOUT (HZ * 2) + +static void iso_sock_timeout(struct work_struct *work) +{ + struct iso_conn *conn = container_of(work, struct iso_conn, + timeout_work.work); + struct sock *sk; + + iso_conn_lock(conn); + sk = conn->sk; + if (sk) + sock_hold(sk); + iso_conn_unlock(conn); + + if (!sk) + return; + + BT_DBG("sock %p state %d", sk, sk->sk_state); + + lock_sock(sk); + sk->sk_err = ETIMEDOUT; + sk->sk_state_change(sk); + release_sock(sk); + sock_put(sk); +} + +static void iso_sock_set_timer(struct sock *sk, long timeout) +{ + if (!iso_pi(sk)->conn) + return; + + BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout); + cancel_delayed_work(&iso_pi(sk)->conn->timeout_work); + schedule_delayed_work(&iso_pi(sk)->conn->timeout_work, timeout); +} + +static void iso_sock_clear_timer(struct sock *sk) +{ + if (!iso_pi(sk)->conn) + return; + + BT_DBG("sock %p state %d", sk, sk->sk_state); + cancel_delayed_work(&iso_pi(sk)->conn->timeout_work); +} + +/* ---- ISO connections ---- */ +static struct iso_conn *iso_conn_add(struct hci_conn *hcon) +{ + struct iso_conn *conn = hcon->iso_data; + + if (conn) + return conn; + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return NULL; + + spin_lock_init(&conn->lock); + INIT_DELAYED_WORK(&conn->timeout_work, iso_sock_timeout); + + hcon->iso_data = conn; + conn->hcon = hcon; + conn->tx_sn = 0; + + BT_DBG("hcon %p conn %p", hcon, conn); + + return conn; +} + +/* Delete channel. Must be called on the locked socket. */ +static void iso_chan_del(struct sock *sk, int err) +{ + struct iso_conn *conn; + + conn = iso_pi(sk)->conn; + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + iso_conn_lock(conn); + conn->sk = NULL; + iso_pi(sk)->conn = NULL; + iso_conn_unlock(conn); + + if (conn->hcon) + hci_conn_drop(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_state_change(sk); + + sock_set_flag(sk, SOCK_ZAPPED); +} + +static void iso_conn_del(struct hci_conn *hcon, int err) +{ + struct iso_conn *conn = hcon->iso_data; + struct sock *sk; + + if (!conn) + return; + + BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); + + /* Kill socket */ + iso_conn_lock(conn); + sk = conn->sk; + if (sk) + sock_hold(sk); + iso_conn_unlock(conn); + + if (sk) { + lock_sock(sk); + iso_sock_clear_timer(sk); + iso_chan_del(sk, err); + release_sock(sk); + sock_put(sk); + } + + /* Ensure no more work items will run before freeing conn. */ + cancel_delayed_work_sync(&conn->timeout_work); + + hcon->iso_data = NULL; + kfree(conn); +} + +static int __iso_chan_add(struct iso_conn *conn, struct sock *sk, + struct sock *parent) +{ + BT_DBG("conn %p", conn); + + if (iso_pi(sk)->conn == conn && conn->sk == sk) + return 0; + + if (conn->sk) { + BT_ERR("conn->sk already set"); + return -EBUSY; + } + + iso_pi(sk)->conn = conn; + conn->sk = sk; + + if (parent) + bt_accept_enqueue(parent, sk, true); + + return 0; +} + +static int iso_chan_add(struct iso_conn *conn, struct sock *sk, + struct sock *parent) +{ + int err; + + iso_conn_lock(conn); + err = __iso_chan_add(conn, sk, parent); + iso_conn_unlock(conn); + + return err; +} + +static int iso_connect(struct sock *sk) +{ + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + int err; + + BT_DBG("%pMR -> %pMR", &iso_pi(sk)->src, &iso_pi(sk)->dst); + + hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, + iso_pi(sk)->src_type); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); + + if (!cis_central_capable(hdev)) { + err = -EOPNOTSUPP; + goto done; + } + + /* Fail if either PHYs are marked as disabled */ + if (!iso_pi(sk)->qos.in.phy && !iso_pi(sk)->qos.out.phy) { + err = -EINVAL; + goto done; + } + + /* Just bind if DEFER_SETUP has been set */ + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + hcon = hci_bind_cis(hdev, &iso_pi(sk)->dst, + iso_pi(sk)->dst_type, &iso_pi(sk)->qos); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto done; + } + } else { + hcon = hci_connect_cis(hdev, &iso_pi(sk)->dst, + iso_pi(sk)->dst_type, &iso_pi(sk)->qos); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto done; + } + } + + conn = iso_conn_add(hcon); + if (!conn) { + hci_conn_drop(hcon); + err = -ENOMEM; + goto done; + } + + /* Update source addr of the socket */ + bacpy(&iso_pi(sk)->src, &hcon->src); + + err = iso_chan_add(conn, sk, NULL); + if (err) + goto done; + + if (hcon->state == BT_CONNECTED) { + iso_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + } else if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + iso_sock_clear_timer(sk); + sk->sk_state = BT_CONNECT; + } else { + sk->sk_state = BT_CONNECT; + iso_sock_set_timer(sk, sk->sk_sndtimeo); + } + +done: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; +} + +static int iso_send_frame(struct sock *sk, struct sk_buff *skb) +{ + struct iso_conn *conn = iso_pi(sk)->conn; + struct hci_iso_data_hdr *hdr; + int len = 0; + + BT_DBG("sk %p len %d", sk, skb->len); + + if (skb->len > iso_pi(sk)->qos.out.sdu) + return -EMSGSIZE; + + len = skb->len; + + /* Push ISO data header */ + hdr = skb_push(skb, HCI_ISO_DATA_HDR_SIZE); + hdr->sn = cpu_to_le16(conn->tx_sn++); + hdr->slen = cpu_to_le16(hci_iso_data_len_pack(len, + HCI_ISO_STATUS_VALID)); + + if (sk->sk_state == BT_CONNECTED) + hci_send_iso(conn->hcon, skb); + else + len = -ENOTCONN; + + return len; +} + +static void iso_recv_frame(struct iso_conn *conn, struct sk_buff *skb) +{ + struct sock *sk; + + iso_conn_lock(conn); + sk = conn->sk; + iso_conn_unlock(conn); + + if (!sk) + goto drop; + + BT_DBG("sk %p len %d", sk, skb->len); + + if (sk->sk_state != BT_CONNECTED) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + return; + +drop: + kfree_skb(skb); +} + +/* -------- Socket interface ---------- */ +static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba) +{ + struct sock *sk; + + sk_for_each(sk, &iso_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; + + if (!bacmp(&iso_pi(sk)->src, ba)) + return sk; + } + + return NULL; +} + +/* Find socket listening on source bdaddr. + * Returns closest match. + */ +static struct sock *iso_get_sock_listen(bdaddr_t *src) +{ + struct sock *sk = NULL, *sk1 = NULL; + + read_lock(&iso_sk_list.lock); + + sk_for_each(sk, &iso_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; + + /* Exact match. */ + if (!bacmp(&iso_pi(sk)->src, src)) + break; + + /* Closest match */ + if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY)) + sk1 = sk; + } + + read_unlock(&iso_sk_list.lock); + + return sk ? sk : sk1; +} + +static void iso_sock_destruct(struct sock *sk) +{ + BT_DBG("sk %p", sk); + + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); +} + +static void iso_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + BT_DBG("parent %p", parent); + + /* Close not yet accepted channels */ + while ((sk = bt_accept_dequeue(parent, NULL))) { + iso_sock_close(sk); + iso_sock_kill(sk); + } + + parent->sk_state = BT_CLOSED; + sock_set_flag(parent, SOCK_ZAPPED); +} + +/* Kill socket (only if zapped and orphan) + * Must be called on unlocked socket. + */ +static void iso_sock_kill(struct sock *sk) +{ + if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket || + sock_flag(sk, SOCK_DEAD)) + return; + + BT_DBG("sk %p state %d", sk, sk->sk_state); + + /* Kill poor orphan */ + bt_sock_unlink(&iso_sk_list, sk); + sock_set_flag(sk, SOCK_DEAD); + sock_put(sk); +} + +static void iso_conn_defer_reject(struct hci_conn *conn) +{ + struct hci_cp_le_reject_cis cp; + + BT_DBG("conn %p", conn); + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(conn->handle); + cp.reason = HCI_ERROR_REJ_BAD_ADDR; + hci_send_cmd(conn->hdev, HCI_OP_LE_REJECT_CIS, sizeof(cp), &cp); +} + +static void __iso_sock_close(struct sock *sk) +{ + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); + + switch (sk->sk_state) { + case BT_LISTEN: + iso_sock_cleanup_listen(sk); + break; + + case BT_CONNECTED: + case BT_CONFIG: + if (iso_pi(sk)->conn->hcon) { + sk->sk_state = BT_DISCONN; + iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT); + iso_conn_lock(iso_pi(sk)->conn); + hci_conn_drop(iso_pi(sk)->conn->hcon); + iso_pi(sk)->conn->hcon = NULL; + iso_conn_unlock(iso_pi(sk)->conn); + } else { + iso_chan_del(sk, ECONNRESET); + } + break; + + case BT_CONNECT2: + if (iso_pi(sk)->conn->hcon) + iso_conn_defer_reject(iso_pi(sk)->conn->hcon); + iso_chan_del(sk, ECONNRESET); + break; + case BT_CONNECT: + /* In case of DEFER_SETUP the hcon would be bound to CIG which + * needs to be removed so just call hci_conn_del so the cleanup + * callback do what is needed. + */ + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags) && + iso_pi(sk)->conn->hcon) { + hci_conn_del(iso_pi(sk)->conn->hcon); + iso_pi(sk)->conn->hcon = NULL; + } + + iso_chan_del(sk, ECONNRESET); + break; + case BT_DISCONN: + iso_chan_del(sk, ECONNRESET); + break; + + default: + sock_set_flag(sk, SOCK_ZAPPED); + break; + } +} + +/* Must be called on unlocked socket. */ +static void iso_sock_close(struct sock *sk) +{ + iso_sock_clear_timer(sk); + lock_sock(sk); + __iso_sock_close(sk); + release_sock(sk); + iso_sock_kill(sk); +} + +static void iso_sock_init(struct sock *sk, struct sock *parent) +{ + BT_DBG("sk %p", sk); + + if (parent) { + sk->sk_type = parent->sk_type; + bt_sk(sk)->flags = bt_sk(parent)->flags; + security_sk_clone(parent, sk); + } +} + +static struct proto iso_proto = { + .name = "ISO", + .owner = THIS_MODULE, + .obj_size = sizeof(struct iso_pinfo) +}; + +#define DEFAULT_IO_QOS \ +{ \ + .interval = 10000u, \ + .latency = 10u, \ + .sdu = 40u, \ + .phy = BT_ISO_PHY_2M, \ + .rtn = 2u, \ +} + +static struct bt_iso_qos default_qos = { + .cig = BT_ISO_QOS_CIG_UNSET, + .cis = BT_ISO_QOS_CIS_UNSET, + .sca = 0x00, + .packing = 0x00, + .framing = 0x00, + .in = DEFAULT_IO_QOS, + .out = DEFAULT_IO_QOS, +}; + +static struct sock *iso_sock_alloc(struct net *net, struct socket *sock, + int proto, gfp_t prio, int kern) +{ + struct sock *sk; + + sk = sk_alloc(net, PF_BLUETOOTH, prio, &iso_proto, kern); + if (!sk) + return NULL; + + sock_init_data(sock, sk); + INIT_LIST_HEAD(&bt_sk(sk)->accept_q); + + sk->sk_destruct = iso_sock_destruct; + sk->sk_sndtimeo = ISO_CONN_TIMEOUT; + + sock_reset_flag(sk, SOCK_ZAPPED); + + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; + + /* Set address type as public as default src address is BDADDR_ANY */ + iso_pi(sk)->src_type = BDADDR_LE_PUBLIC; + + iso_pi(sk)->qos = default_qos; + + bt_sock_link(&iso_sk_list, sk); + return sk; +} + +static int iso_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + struct sock *sk; + + BT_DBG("sock %p", sock); + + sock->state = SS_UNCONNECTED; + + if (sock->type != SOCK_SEQPACKET) + return -ESOCKTNOSUPPORT; + + sock->ops = &iso_sock_ops; + + sk = iso_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); + if (!sk) + return -ENOMEM; + + iso_sock_init(sk, NULL); + return 0; +} + +static int iso_sock_bind(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + struct sockaddr_iso *sa = (struct sockaddr_iso *)addr; + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sk %p %pMR type %u", sk, &sa->iso_bdaddr, sa->iso_bdaddr_type); + + if (!addr || addr_len < sizeof(struct sockaddr_iso) || + addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + lock_sock(sk); + + if (sk->sk_state != BT_OPEN) { + err = -EBADFD; + goto done; + } + + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + + /* Check if the address type is of LE type */ + if (!bdaddr_type_is_le(sa->iso_bdaddr_type)) { + err = -EINVAL; + goto done; + } + + bacpy(&iso_pi(sk)->src, &sa->iso_bdaddr); + iso_pi(sk)->src_type = sa->iso_bdaddr_type; + + sk->sk_state = BT_BOUND; + +done: + release_sock(sk); + return err; +} + +static int iso_sock_connect(struct socket *sock, struct sockaddr *addr, + int alen, int flags) +{ + struct sockaddr_iso *sa = (struct sockaddr_iso *)addr; + struct sock *sk = sock->sk; + int err; + + BT_DBG("sk %p", sk); + + if (alen < sizeof(struct sockaddr_iso) || + addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) + return -EBADFD; + + if (sk->sk_type != SOCK_SEQPACKET) + return -EINVAL; + + /* Check if the address type is of LE type */ + if (!bdaddr_type_is_le(sa->iso_bdaddr_type)) + return -EINVAL; + + lock_sock(sk); + + bacpy(&iso_pi(sk)->dst, &sa->iso_bdaddr); + iso_pi(sk)->dst_type = sa->iso_bdaddr_type; + + err = iso_connect(sk); + if (err) + goto done; + + if (!test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + err = bt_sock_wait_state(sk, BT_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); + } + +done: + release_sock(sk); + return err; +} + +static int iso_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + bdaddr_t *src = &iso_pi(sk)->src; + int err = 0; + + BT_DBG("sk %p backlog %d", sk, backlog); + + lock_sock(sk); + + if (sk->sk_state != BT_BOUND) { + err = -EBADFD; + goto done; + } + + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + + write_lock(&iso_sk_list.lock); + + if (__iso_get_sock_listen_by_addr(src)) { + err = -EADDRINUSE; + goto unlock; + } + + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + + sk->sk_state = BT_LISTEN; + +unlock: + write_unlock(&iso_sk_list.lock); + +done: + release_sock(sk); + return err; +} + +static int iso_sock_accept(struct socket *sock, struct socket *newsock, + int flags, bool kern) +{ + DEFINE_WAIT_FUNC(wait, woken_wake_function); + struct sock *sk = sock->sk, *ch; + long timeo; + int err = 0; + + lock_sock(sk); + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + BT_DBG("sk %p timeo %ld", sk, timeo); + + /* Wait for an incoming connection. (wake-one). */ + add_wait_queue_exclusive(sk_sleep(sk), &wait); + while (1) { + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; + break; + } + + ch = bt_accept_dequeue(sk, newsock); + if (ch) + break; + + if (!timeo) { + err = -EAGAIN; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + + timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); + lock_sock(sk); + } + remove_wait_queue(sk_sleep(sk), &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + + BT_DBG("new socket %p", ch); + +done: + release_sock(sk); + return err; +} + +static int iso_sock_getname(struct socket *sock, struct sockaddr *addr, + int peer) +{ + struct sockaddr_iso *sa = (struct sockaddr_iso *)addr; + struct sock *sk = sock->sk; + + BT_DBG("sock %p, sk %p", sock, sk); + + addr->sa_family = AF_BLUETOOTH; + + if (peer) { + bacpy(&sa->iso_bdaddr, &iso_pi(sk)->dst); + sa->iso_bdaddr_type = iso_pi(sk)->dst_type; + } else { + bacpy(&sa->iso_bdaddr, &iso_pi(sk)->src); + sa->iso_bdaddr_type = iso_pi(sk)->src_type; + } + + return sizeof(struct sockaddr_iso); +} + +static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg, + size_t len) +{ + struct sock *sk = sock->sk; + struct iso_conn *conn = iso_pi(sk)->conn; + struct sk_buff *skb, **frag; + int err; + + BT_DBG("sock %p, sk %p", sock, sk); + + err = sock_error(sk); + if (err) + return err; + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + if (sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + + skb = bt_skb_sendmsg(sk, msg, len, conn->hcon->hdev->iso_mtu, + HCI_ISO_DATA_HDR_SIZE, 0); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + len -= skb->len; + + BT_DBG("skb %p len %d", sk, skb->len); + + /* Continuation fragments */ + frag = &skb_shinfo(skb)->frag_list; + while (len) { + struct sk_buff *tmp; + + tmp = bt_skb_sendmsg(sk, msg, len, conn->hcon->hdev->iso_mtu, + 0, 0); + if (IS_ERR(tmp)) { + kfree_skb(skb); + return PTR_ERR(tmp); + } + + *frag = tmp; + + len -= tmp->len; + + skb->len += tmp->len; + skb->data_len += tmp->len; + + BT_DBG("frag %p len %d", *frag, tmp->len); + + frag = &(*frag)->next; + } + + lock_sock(sk); + + if (sk->sk_state == BT_CONNECTED) + err = iso_send_frame(sk, skb); + else + err = -ENOTCONN; + + release_sock(sk); + + if (err < 0) + kfree_skb(skb); + return err; +} + +static void iso_conn_defer_accept(struct hci_conn *conn) +{ + struct hci_cp_le_accept_cis cp; + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p", conn); + + conn->state = BT_CONFIG; + + cp.handle = cpu_to_le16(conn->handle); + + hci_send_cmd(hdev, HCI_OP_LE_ACCEPT_CIS, sizeof(cp), &cp); +} + +static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, + size_t len, int flags) +{ + struct sock *sk = sock->sk; + struct iso_pinfo *pi = iso_pi(sk); + int err; + + BT_DBG("sk %p", sk); + + lock_sock(sk); + + if (test_and_clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + switch (sk->sk_state) { + case BT_CONNECT2: + iso_conn_defer_accept(pi->conn->hcon); + sk->sk_state = BT_CONFIG; + release_sock(sk); + return 0; + case BT_CONNECT: + err = iso_connect(sk); + release_sock(sk); + return err; + } + } + + release_sock(sk); + + return bt_sock_recvmsg(sock, msg, len, flags); +} + +static bool check_io_qos(struct bt_iso_io_qos *qos) +{ + /* If no PHY is enable SDU must be 0 */ + if (!qos->phy && qos->sdu) + return false; + + if (qos->interval && (qos->interval < 0xff || qos->interval > 0xfffff)) + return false; + + if (qos->latency && (qos->latency < 0x05 || qos->latency > 0xfa0)) + return false; + + if (qos->phy > BT_ISO_PHY_ANY) + return false; + + return true; +} + +static bool check_qos(struct bt_iso_qos *qos) +{ + /* CIS shall not be set */ + if (qos->cis != BT_ISO_QOS_CIS_UNSET) + return false; + + if (qos->sca > 0x07) + return false; + + if (qos->packing > 0x01) + return false; + + if (qos->framing > 0x01) + return false; + + if (!check_io_qos(&qos->in)) + return false; + + if (!check_io_qos(&qos->out)) + return false; + + return true; +} + +static int iso_sock_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) +{ + struct sock *sk = sock->sk; + int len, err = 0; + struct bt_iso_qos qos; + u32 opt; + + BT_DBG("sk %p", sk); + + lock_sock(sk); + + switch (optname) { + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (copy_from_sockptr(&opt, optval, sizeof(u32))) { + err = -EFAULT; + break; + } + + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; + + case BT_ISO_QOS: + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && + sk->sk_state != BT_CONNECT2) { + err = -EINVAL; + break; + } + + len = min_t(unsigned int, sizeof(qos), optlen); + if (len != sizeof(qos)) + return -EINVAL; + + memset(&qos, 0, sizeof(qos)); + + if (copy_from_sockptr(&qos, optval, len)) { + err = -EFAULT; + break; + } + + if (!check_qos(&qos)) { + err = -EINVAL; + break; + } + + iso_pi(sk)->qos = qos; + + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int iso_sock_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + int len, err = 0; + struct bt_iso_qos qos; + + BT_DBG("sk %p", sk); + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *)optval)) + err = -EFAULT; + + break; + + case BT_ISO_QOS: + if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONNECT2) + qos = iso_pi(sk)->conn->hcon->iso_qos; + else + qos = iso_pi(sk)->qos; + + len = min_t(unsigned int, len, sizeof(qos)); + if (copy_to_user(optval, (char *)&qos, len)) + err = -EFAULT; + + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int iso_sock_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + sock_hold(sk); + lock_sock(sk); + + if (!sk->sk_shutdown) { + sk->sk_shutdown = SHUTDOWN_MASK; + iso_sock_clear_timer(sk); + __iso_sock_close(sk); + + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) + err = bt_sock_wait_state(sk, BT_CLOSED, + sk->sk_lingertime); + } + + release_sock(sk); + sock_put(sk); + + return err; +} + +static int iso_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + iso_sock_close(sk); + + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) { + lock_sock(sk); + err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); + release_sock(sk); + } + + sock_orphan(sk); + iso_sock_kill(sk); + return err; +} + +static void iso_sock_ready(struct sock *sk) +{ + BT_DBG("sk %p", sk); + + if (!sk) + return; + + lock_sock(sk); + iso_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + release_sock(sk); +} + +struct iso_list_data { + struct hci_conn *hcon; + int count; +}; + +static void iso_conn_ready(struct iso_conn *conn) +{ + struct sock *parent; + struct sock *sk = conn->sk; + + BT_DBG("conn %p", conn); + + if (sk) { + iso_sock_ready(conn->sk); + } else { + iso_conn_lock(conn); + + if (!conn->hcon) { + iso_conn_unlock(conn); + return; + } + + parent = iso_get_sock_listen(&conn->hcon->src); + if (!parent) { + iso_conn_unlock(conn); + return; + } + + lock_sock(parent); + + sk = iso_sock_alloc(sock_net(parent), NULL, + BTPROTO_ISO, GFP_ATOMIC, 0); + if (!sk) { + release_sock(parent); + iso_conn_unlock(conn); + return; + } + + iso_sock_init(sk, parent); + + bacpy(&iso_pi(sk)->src, &conn->hcon->src); + iso_pi(sk)->src_type = conn->hcon->src_type; + bacpy(&iso_pi(sk)->dst, &conn->hcon->dst); + iso_pi(sk)->dst_type = conn->hcon->dst_type; + + hci_conn_hold(conn->hcon); + __iso_chan_add(conn, sk, parent); + + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) + sk->sk_state = BT_CONNECT2; + else + sk->sk_state = BT_CONNECTED; + + /* Wake up parent */ + parent->sk_data_ready(parent); + + release_sock(parent); + + iso_conn_unlock(conn); + } +} + +/* ----- ISO interface with lower layer (HCI) ----- */ +int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) +{ + struct sock *sk; + int lm = 0; + + BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr); + + /* Find listening sockets */ + read_lock(&iso_sk_list.lock); + sk_for_each(sk, &iso_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; + + if (!bacmp(&iso_pi(sk)->src, &hdev->bdaddr) || + !bacmp(&iso_pi(sk)->src, BDADDR_ANY)) { + lm |= HCI_LM_ACCEPT; + + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) + *flags |= HCI_PROTO_DEFER; + break; + } + } + read_unlock(&iso_sk_list.lock); + + return lm; +} + +static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) +{ + if (hcon->type != ISO_LINK) { + if (hcon->type != LE_LINK) + return; + + /* Check if LE link has failed */ + if (status) { + if (hcon->link) + iso_conn_del(hcon->link, bt_to_errno(status)); + return; + } + + /* Create CIS if pending */ + hci_le_create_cis(hcon); + return; + } + + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); + + if (!status) { + struct iso_conn *conn; + + conn = iso_conn_add(hcon); + if (conn) + iso_conn_ready(conn); + } else { + iso_conn_del(hcon, bt_to_errno(status)); + } +} + +static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason) +{ + if (hcon->type != ISO_LINK) + return; + + BT_DBG("hcon %p reason %d", hcon, reason); + + iso_conn_del(hcon, bt_to_errno(reason)); +} + +void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) +{ + struct iso_conn *conn = hcon->iso_data; + struct hci_iso_data_hdr *hdr; + __u16 pb, ts, len; + + if (!conn) + goto drop; + + pb = hci_iso_flags_pb(flags); + ts = hci_iso_flags_ts(flags); + + BT_DBG("conn %p len %d pb 0x%x ts 0x%x", conn, skb->len, pb, ts); + + switch (pb) { + case ISO_START: + case ISO_SINGLE: + if (conn->rx_len) { + BT_ERR("Unexpected start frame (len %d)", skb->len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + } + + if (ts) { + /* TODO: add timestamp to the packet? */ + hdr = skb_pull_data(skb, HCI_ISO_TS_DATA_HDR_SIZE); + if (!hdr) { + BT_ERR("Frame is too short (len %d)", skb->len); + goto drop; + } + + } else { + hdr = skb_pull_data(skb, HCI_ISO_DATA_HDR_SIZE); + if (!hdr) { + BT_ERR("Frame is too short (len %d)", skb->len); + goto drop; + } + } + + len = __le16_to_cpu(hdr->slen); + flags = hci_iso_data_flags(len); + len = hci_iso_data_len(len); + + BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x", len, + skb->len, flags); + + if (len == skb->len) { + /* Complete frame received */ + iso_recv_frame(conn, skb); + return; + } + + if (pb == ISO_SINGLE) { + BT_ERR("Frame malformed (len %d, expected len %d)", + skb->len, len); + goto drop; + } + + if (skb->len > len) { + BT_ERR("Frame is too long (len %d, expected len %d)", + skb->len, len); + goto drop; + } + + /* Allocate skb for the complete frame (with header) */ + conn->rx_skb = bt_skb_alloc(len, GFP_KERNEL); + if (!conn->rx_skb) + goto drop; + + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len = len - skb->len; + break; + + case ISO_CONT: + BT_DBG("Cont: frag len %d (expecting %d)", skb->len, + conn->rx_len); + + if (!conn->rx_len) { + BT_ERR("Unexpected continuation frame (len %d)", + skb->len); + goto drop; + } + + if (skb->len > conn->rx_len) { + BT_ERR("Fragment is too long (len %d, expected %d)", + skb->len, conn->rx_len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + goto drop; + } + + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len -= skb->len; + return; + + case ISO_END: + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len -= skb->len; + + if (!conn->rx_len) { + struct sk_buff *rx_skb = conn->rx_skb; + + /* Complete frame received. iso_recv_frame + * takes ownership of the skb so set the global + * rx_skb pointer to NULL first. + */ + conn->rx_skb = NULL; + iso_recv_frame(conn, rx_skb); + } + break; + } + +drop: + kfree_skb(skb); +} + +static struct hci_cb iso_cb = { + .name = "ISO", + .connect_cfm = iso_connect_cfm, + .disconn_cfm = iso_disconn_cfm, +}; + +static int iso_debugfs_show(struct seq_file *f, void *p) +{ + struct sock *sk; + + read_lock(&iso_sk_list.lock); + + sk_for_each(sk, &iso_sk_list.head) { + seq_printf(f, "%pMR %pMR %d\n", &iso_pi(sk)->src, + &iso_pi(sk)->dst, sk->sk_state); + } + + read_unlock(&iso_sk_list.lock); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(iso_debugfs); + +static struct dentry *iso_debugfs; + +static const struct proto_ops iso_sock_ops = { + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .release = iso_sock_release, + .bind = iso_sock_bind, + .connect = iso_sock_connect, + .listen = iso_sock_listen, + .accept = iso_sock_accept, + .getname = iso_sock_getname, + .sendmsg = iso_sock_sendmsg, + .recvmsg = iso_sock_recvmsg, + .poll = bt_sock_poll, + .ioctl = bt_sock_ioctl, + .mmap = sock_no_mmap, + .socketpair = sock_no_socketpair, + .shutdown = iso_sock_shutdown, + .setsockopt = iso_sock_setsockopt, + .getsockopt = iso_sock_getsockopt +}; + +static const struct net_proto_family iso_sock_family_ops = { + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .create = iso_sock_create, +}; + +static bool iso_inited; + +bool iso_enabled(void) +{ + return iso_inited; +} + +int iso_init(void) +{ + int err; + + BUILD_BUG_ON(sizeof(struct sockaddr_iso) > sizeof(struct sockaddr)); + + if (iso_inited) + return -EALREADY; + + err = proto_register(&iso_proto, 0); + if (err < 0) + return err; + + err = bt_sock_register(BTPROTO_ISO, &iso_sock_family_ops); + if (err < 0) { + BT_ERR("ISO socket registration failed"); + goto error; + } + + err = bt_procfs_init(&init_net, "iso", &iso_sk_list, NULL); + if (err < 0) { + BT_ERR("Failed to create ISO proc file"); + bt_sock_unregister(BTPROTO_ISO); + goto error; + } + + BT_INFO("ISO socket layer initialized"); + + hci_register_cb(&iso_cb); + + if (IS_ERR_OR_NULL(bt_debugfs)) + return 0; + + if (!iso_debugfs) { + iso_debugfs = debugfs_create_file("iso", 0444, bt_debugfs, + NULL, &iso_debugfs_fops); + } + + iso_inited = true; + + return 0; + +error: + proto_unregister(&iso_proto); + return err; +} + +int iso_exit(void) +{ + if (!iso_inited) + return -EALREADY; + + bt_procfs_cleanup(&init_net, "iso"); + + debugfs_remove(iso_debugfs); + iso_debugfs = NULL; + + hci_unregister_cb(&iso_cb); + + bt_sock_unregister(BTPROTO_ISO); + + proto_unregister(&iso_proto); + + iso_inited = false; + + return 0; +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a97fafe7fd4a..08688117d700 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3985,10 +3985,16 @@ static const u8 rpa_resolution_uuid[16] = { 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, }; +/* 6fbaf188-05e0-496a-9885-d6ddfdb4e03e */ +static const u8 iso_socket_uuid[16] = { + 0x3e, 0xe0, 0xb4, 0xfd, 0xdd, 0xd6, 0x85, 0x98, + 0x6a, 0x49, 0xe0, 0x05, 0x88, 0xf1, 0xba, 0x6f, +}; + static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { - char buf[102]; /* Enough space for 5 features: 2 + 20 * 5 */ + char buf[122]; /* Enough space for 6 features: 2 + 20 * 6 */ struct mgmt_rp_read_exp_features_info *rp = (void *)buf; u16 idx = 0; u32 flags; @@ -4052,6 +4058,13 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, idx++; } + if (IS_ENABLED(CONFIG_BT_LE)) { + flags = iso_enabled() ? BIT(0) : 0; + memcpy(rp->features[idx].uuid, iso_socket_uuid, 16); + rp->features[idx].flags = cpu_to_le32(flags); + idx++; + } + rp->feature_count = cpu_to_le16(idx); /* After reading the experimental features information, enable @@ -4444,6 +4457,57 @@ static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev, return err; } +#ifdef CONFIG_BT_LE +static int set_iso_socket_func(struct sock *sk, struct hci_dev *hdev, + struct mgmt_cp_set_exp_feature *cp, u16 data_len) +{ + struct mgmt_rp_set_exp_feature rp; + bool val, changed = false; + int err; + + /* Command requires to use the non-controller index */ + if (hdev) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_INDEX); + + /* Parameters are limited to a single octet */ + if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_PARAMS); + + /* Only boolean on/off is supported */ + if (cp->param[0] != 0x00 && cp->param[0] != 0x01) + return mgmt_cmd_status(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, + MGMT_STATUS_INVALID_PARAMS); + + val = cp->param[0] ? true : false; + if (val) + err = iso_init(); + else + err = iso_exit(); + + if (!err) + changed = true; + + memcpy(rp.uuid, iso_socket_uuid, 16); + rp.flags = cpu_to_le32(val ? BIT(0) : 0); + + hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); + + err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, + MGMT_OP_SET_EXP_FEATURE, 0, + &rp, sizeof(rp)); + + if (changed) + exp_feature_changed(hdev, iso_socket_uuid, val, sk); + + return err; +} +#endif + static const struct mgmt_exp_feature { const u8 *uuid; int (*set_func)(struct sock *sk, struct hci_dev *hdev, @@ -4457,6 +4521,9 @@ static const struct mgmt_exp_feature { EXP_FEAT(quality_report_uuid, set_quality_report_func), EXP_FEAT(offload_codecs_uuid, set_offload_codec_func), EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func), +#ifdef CONFIG_BT_LE + EXP_FEAT(iso_socket_uuid, set_iso_socket_func), +#endif /* end with a null feature */ EXP_FEAT(NULL, NULL) -- cgit v1.2.3 From eca0ae4aea66914515e5e3098ea051b518ee5316 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 9 Mar 2022 13:22:20 -0800 Subject: Bluetooth: Add initial implementation of BIS connections This adds initial support for BIS/BIG which includes: == Broadcaster role: Setup a periodic advertising and create a BIG == > tools/isotest -s 00:00:00:00:00:00 isotest[63]: Connected [00:00:00:00:00:00] isotest[63]: QoS BIG 0x00 BIS 0x00 Packing 0x00 Framing 0x00] isotest[63]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2] isotest[63]: Sending ... isotest[63]: Number of packets: 1 isotest[63]: Socket jitter buffer: 80 buffer < HCI Command: LE Set Perio.. (0x08|0x003e) plen 7 ... > HCI Event: Command Complete (0x0e) plen 4 LE Set Periodic Advertising Parameters (0x08|0x003e) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Perio.. (0x08|0x003f) plen 7 ... > HCI Event: Command Complete (0x0e) plen 4 LE Set Periodic Advertising Data (0x08|0x003f) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Perio.. (0x08|0x0040) plen 2 ... > HCI Event: Command Complete (0x0e) plen 4 LE Set Periodic Advertising Enable (0x08|0x0040) ncmd 1 Status: Success (0x00) < HCI Command: LE Create B.. (0x08|0x0068) plen 31 ... > HCI Event: Command Status (0x0f) plen 4 LE Create Broadcast Isochronous Group (0x08|0x0068) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 21 LE Broadcast Isochronous Group Complete (0x1b) ... == Broadcast Receiver role: Create a PA Sync and BIG Sync == > tools/isotest -i hci1 -d 00:AA:01:00:00:00 isotest[66]: Waiting for connection 00:AA:01:00:00:00... < HCI Command: LE Periodic Advert.. (0x08|0x0044) plen 14 ... > HCI Event: Command Status (0x0f) plen 4 LE Periodic Advertising Create Sync (0x08|0x0044) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Extended Sca.. (0x08|0x0041) plen 8 ... > HCI Event: Command Complete (0x0e) plen 4 LE Set Extended Scan Parameters (0x08|0x0041) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Extended Sca.. (0x08|0x0042) plen 6 ... > HCI Event: Command Complete (0x0e) plen 4 LE Set Extended Scan Enable (0x08|0x0042) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 29 LE Extended Advertising Report (0x0d) ... > HCI Event: LE Meta Event (0x3e) plen 16 LE Periodic Advertising Sync Established (0x0e) ... < HCI Command: LE Broadcast Isoch.. (0x08|0x006b) plen 25 ... > HCI Event: Command Status (0x0f) plen 4 LE Broadcast Isochronous Group Create Sync (0x08|0x006b) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 17 LE Broadcast Isochronous Group Sync Estabilished (0x1d) ... Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 18 +- include/net/bluetooth/hci.h | 162 ++++++++++- include/net/bluetooth/hci_core.h | 89 +++++- include/net/bluetooth/hci_sync.h | 12 +- net/bluetooth/eir.c | 21 ++ net/bluetooth/eir.h | 1 + net/bluetooth/hci_conn.c | 561 ++++++++++++++++++++++++++++++++++---- net/bluetooth/hci_core.c | 80 ++++-- net/bluetooth/hci_event.c | 206 ++++++++++++++ net/bluetooth/hci_request.c | 36 ++- net/bluetooth/hci_request.h | 9 + net/bluetooth/hci_sync.c | 249 ++++++++++++++++- net/bluetooth/mgmt.c | 15 +- 13 files changed, 1333 insertions(+), 126 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index df2c006fc6a9..bcc6e098f1f6 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -160,6 +160,9 @@ struct bt_voice { #define BT_ISO_QOS_CIG_UNSET 0xff #define BT_ISO_QOS_CIS_UNSET 0xff +#define BT_ISO_QOS_BIG_UNSET 0xff +#define BT_ISO_QOS_BIS_UNSET 0xff + struct bt_iso_io_qos { __u32 interval; __u16 latency; @@ -169,9 +172,18 @@ struct bt_iso_io_qos { }; struct bt_iso_qos { - __u8 cig; - __u8 cis; - __u8 sca; + union { + __u8 cig; + __u8 big; + }; + union { + __u8 cis; + __u8 bis; + }; + union { + __u8 sca; + __u8 sync_interval; + }; __u8 packing; __u8 framing; struct bt_iso_io_qos in; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 027f1bc6e4f1..cf29511b25a8 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -316,6 +316,7 @@ enum { HCI_USER_CHANNEL, HCI_EXT_CONFIGURED, HCI_LE_ADV, + HCI_LE_PER_ADV, HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_SC_ENABLED, @@ -338,6 +339,7 @@ enum { HCI_LE_SCAN_INTERRUPTED, HCI_WIDEBAND_SPEECH_ENABLED, HCI_EVENT_FILTER_CONFIGURED, + HCI_PA_SYNC, HCI_DUT_MODE, HCI_VENDOR_DIAG, @@ -519,9 +521,11 @@ enum { #define HCI_LE_PHY_2M 0x01 #define HCI_LE_PHY_CODED 0x08 #define HCI_LE_EXT_ADV 0x10 +#define HCI_LE_PERIODIC_ADV 0x20 #define HCI_LE_CHAN_SEL_ALG2 0x40 #define HCI_LE_CIS_CENTRAL 0x10 #define HCI_LE_CIS_PERIPHERAL 0x20 +#define HCI_LE_ISO_BROADCASTER 0x40 /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 @@ -1865,6 +1869,22 @@ struct hci_cp_le_ext_conn_param { __le16 max_ce_len; } __packed; +#define HCI_OP_LE_PA_CREATE_SYNC 0x2044 +struct hci_cp_le_pa_create_sync { + __u8 options; + __u8 sid; + __u8 addr_type; + bdaddr_t addr; + __le16 skip; + __le16 sync_timeout; + __u8 sync_cte_type; +} __packed; + +#define HCI_OP_LE_PA_TERM_SYNC 0x2046 +struct hci_cp_le_pa_term_sync { + __le16 handle; +} __packed; + #define HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS 0x203b struct hci_rp_le_read_num_supported_adv_sets { __u8 status; @@ -1899,13 +1919,6 @@ struct hci_rp_le_set_ext_adv_params { __u8 tx_power; } __packed; -#define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039 -struct hci_cp_le_set_ext_adv_enable { - __u8 enable; - __u8 num_of_sets; - __u8 data[]; -} __packed; - struct hci_cp_ext_adv_set { __u8 handle; __le16 duration; @@ -1932,6 +1945,37 @@ struct hci_cp_le_set_ext_scan_rsp_data { __u8 data[]; } __packed; +#define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039 +struct hci_cp_le_set_ext_adv_enable { + __u8 enable; + __u8 num_of_sets; + __u8 data[]; +} __packed; + +#define HCI_OP_LE_SET_PER_ADV_PARAMS 0x203e +struct hci_cp_le_set_per_adv_params { + __u8 handle; + __le16 min_interval; + __le16 max_interval; + __le16 periodic_properties; +} __packed; + +#define HCI_MAX_PER_AD_LENGTH 252 + +#define HCI_OP_LE_SET_PER_ADV_DATA 0x203f +struct hci_cp_le_set_per_adv_data { + __u8 handle; + __u8 operation; + __u8 length; + __u8 data[]; +} __packed; + +#define HCI_OP_LE_SET_PER_ADV_ENABLE 0x2040 +struct hci_cp_le_set_per_adv_enable { + __u8 enable; + __u8 handle; +} __packed; + #define LE_SET_ADV_DATA_OP_COMPLETE 0x03 #define LE_SET_ADV_DATA_NO_FRAG 0x01 @@ -2043,6 +2087,49 @@ struct hci_cp_le_reject_cis { __u8 reason; } __packed; +#define HCI_OP_LE_CREATE_BIG 0x2068 +struct hci_bis { + __u8 sdu_interval[3]; + __le16 sdu; + __le16 latency; + __u8 rtn; + __u8 phy; + __u8 packing; + __u8 framing; + __u8 encryption; + __u8 bcode[16]; +} __packed; + +struct hci_cp_le_create_big { + __u8 handle; + __u8 adv_handle; + __u8 num_bis; + struct hci_bis bis; +} __packed; + +#define HCI_OP_LE_TERM_BIG 0x206a +struct hci_cp_le_term_big { + __u8 handle; + __u8 reason; +} __packed; + +#define HCI_OP_LE_BIG_CREATE_SYNC 0x206b +struct hci_cp_le_big_create_sync { + __u8 handle; + __le16 sync_handle; + __u8 encryption; + __u8 bcode[16]; + __u8 mse; + __le16 timeout; + __u8 num_bis; + __u8 bis[0]; +} __packed; + +#define HCI_OP_LE_BIG_TERM_SYNC 0x206c +struct hci_cp_le_big_term_sync { + __u8 handle; +} __packed; + #define HCI_OP_LE_SETUP_ISO_PATH 0x206e struct hci_cp_le_setup_iso_path { __le16 handle; @@ -2595,6 +2682,18 @@ struct hci_ev_le_ext_adv_report { struct hci_ev_le_ext_adv_info info[]; } __packed; +#define HCI_EV_LE_PA_SYNC_ESTABLISHED 0x0e +struct hci_ev_le_pa_sync_established { + __u8 status; + __le16 handle; + __u8 sid; + __u8 bdaddr_type; + bdaddr_t bdaddr; + __u8 phy; + __le16 interval; + __u8 clock_accuracy; +} __packed; + #define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a struct hci_ev_le_enh_conn_complete { __u8 status; @@ -2646,6 +2745,55 @@ struct hci_evt_le_cis_req { __u8 cis_id; } __packed; +#define HCI_EVT_LE_CREATE_BIG_COMPLETE 0x1b +struct hci_evt_le_create_big_complete { + __u8 status; + __u8 handle; + __u8 sync_delay[3]; + __u8 transport_delay[3]; + __u8 phy; + __u8 nse; + __u8 bn; + __u8 pto; + __u8 irc; + __le16 max_pdu; + __le16 interval; + __u8 num_bis; + __le16 bis_handle[]; +} __packed; + +#define HCI_EVT_LE_BIG_SYNC_ESTABILISHED 0x1d +struct hci_evt_le_big_sync_estabilished { + __u8 status; + __u8 handle; + __u8 latency[3]; + __u8 nse; + __u8 bn; + __u8 pto; + __u8 irc; + __le16 max_pdu; + __le16 interval; + __u8 num_bis; + __le16 bis[]; +} __packed; + +#define HCI_EVT_LE_BIG_INFO_ADV_REPORT 0x22 +struct hci_evt_le_big_info_adv_report { + __le16 sync_handle; + __u8 num_bis; + __u8 nse; + __le16 iso_interval; + __u8 bn; + __u8 pto; + __u8 irc; + __le16 max_pdu; + __u8 sdu_interval[3]; + __le16 max_sdu; + __u8 phy; + __u8 framing; + __u8 encryption; +} __packed; + #define HCI_EV_VENDOR 0xff /* Internal events generated by Bluetooth stack */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3457c24e9b19..e7862903187d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -235,8 +235,9 @@ struct oob_data { struct adv_info { struct list_head list; - bool enabled; - bool pending; + bool enabled; + bool pending; + bool periodic; __u8 instance; __u32 flags; __u16 timeout; @@ -248,6 +249,8 @@ struct adv_info { __u16 scan_rsp_len; __u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH]; bool scan_rsp_changed; + __u16 per_adv_data_len; + __u8 per_adv_data[HCI_MAX_PER_AD_LENGTH]; __s8 tx_power; __u32 min_interval; __u32 max_interval; @@ -594,6 +597,8 @@ struct hci_dev { __u8 adv_data_len; __u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH]; __u8 scan_rsp_data_len; + __u8 per_adv_data[HCI_MAX_PER_AD_LENGTH]; + __u8 per_adv_data_len; struct list_head adv_instances; unsigned int adv_instance_cnt; @@ -679,6 +684,7 @@ struct hci_conn { __u8 resp_addr_type; __u8 adv_instance; __u16 handle; + __u16 sync_handle; __u16 state; __u8 mode; __u8 type; @@ -709,6 +715,8 @@ struct hci_conn { __u16 le_supv_timeout; __u8 le_adv_data[HCI_MAX_AD_LENGTH]; __u8 le_adv_data_len; + __u8 le_per_adv_data[HCI_MAX_PER_AD_LENGTH]; + __u8 le_per_adv_data_len; __u8 le_tx_phy; __u8 le_rx_phy; __s8 rssi; @@ -942,6 +950,7 @@ enum { HCI_CONN_NEW_LINK_KEY, HCI_CONN_SCANNING, HCI_CONN_AUTH_FAILURE, + HCI_CONN_PER_ADV, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) @@ -1060,6 +1069,29 @@ static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle) return type; } +static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev, + bdaddr_t *ba, + __u8 big, __u8 bis) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (bacmp(&c->dst, ba) || c->type != ISO_LINK) + continue; + + if (c->iso_qos.big == big && c->iso_qos.bis == bis) { + rcu_read_unlock(); + return c; + } + } + rcu_read_unlock(); + + return NULL; +} + static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, __u16 handle) { @@ -1170,6 +1202,29 @@ static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev, return NULL; } +static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev, + __u8 handle) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK) + continue; + + if (handle == c->iso_qos.big) { + rcu_read_unlock(); + return c; + } + } + + rcu_read_unlock(); + + return NULL; +} + static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, __u8 type, __u16 state) { @@ -1264,6 +1319,13 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos); struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos); +struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos, + __u8 data_len, __u8 *data); +int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, + __u8 sid); +int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos, + __u16 sync_handle, __u8 num_bis, __u8 bis[]); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, @@ -1510,11 +1572,14 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, void hci_adv_instances_clear(struct hci_dev *hdev); struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance); struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); -int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, - u16 adv_data_len, u8 *adv_data, - u16 scan_rsp_len, u8 *scan_rsp_data, - u16 timeout, u16 duration, s8 tx_power, - u32 min_interval, u32 max_interval); +struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, + u32 flags, u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data, + u16 timeout, u16 duration, s8 tx_power, + u32 min_interval, u32 max_interval); +struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, + u32 flags, u8 data_len, u8 *data, + u32 min_interval, u32 max_interval); int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance, u16 adv_data_len, u8 *adv_data, u16 scan_rsp_len, u8 *scan_rsp_data); @@ -1631,14 +1696,18 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define use_enhanced_conn_complete(dev) (ll_privacy_capable(dev) || \ ext_adv_capable(dev)) -/* CIS Master/Slave support */ -#define iso_capable(dev) (cis_capable(dev)) +/* Periodic advertising support */ +#define per_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_PERIODIC_ADV)) + +/* CIS Master/Slave and BIS support */ +#define iso_capable(dev) (cis_capable(dev) || bis_capable(dev)) #define cis_capable(dev) \ (cis_central_capable(dev) || cis_peripheral_capable(dev)) #define cis_central_capable(dev) \ ((dev)->le_features[3] & HCI_LE_CIS_CENTRAL) #define cis_peripheral_capable(dev) \ ((dev)->le_features[3] & HCI_LE_CIS_PERIPHERAL) +#define bis_capable(dev) ((dev)->le_features[3] & HCI_LE_ISO_BROADCASTER) /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 @@ -1926,6 +1995,8 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c); #define DISCOV_LE_RESTART_DELAY msecs_to_jiffies(200) /* msec */ #define DISCOV_LE_FAST_ADV_INT_MIN 0x00A0 /* 100 msec */ #define DISCOV_LE_FAST_ADV_INT_MAX 0x00F0 /* 150 msec */ +#define DISCOV_LE_PER_ADV_INT_MIN 0x00A0 /* 200 msec */ +#define DISCOV_LE_PER_ADV_INT_MAX 0x00A0 /* 200 msec */ #define NAME_RESOLVE_DURATION msecs_to_jiffies(10240) /* 10.24 sec */ diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index c243cb6869d8..3843f5060c73 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -65,6 +65,10 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance); int hci_enable_advertising_sync(struct hci_dev *hdev); int hci_enable_advertising(struct hci_dev *hdev); +int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, + u8 *data, u32 flags, u16 min_interval, + u16 max_interval, u16 sync_interval); + int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk, u8 instance, bool force); int hci_disable_advertising_sync(struct hci_dev *hdev); @@ -83,6 +87,7 @@ int hci_update_scan(struct hci_dev *hdev); int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul); int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance, struct sock *sk); +int hci_remove_ext_adv_instance(struct hci_dev *hdev, u8 instance); struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev, bool ext, struct sock *sk); @@ -111,4 +116,9 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason); int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn); int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle); -int hci_le_remove_cig(struct hci_dev *hdev, u8 handle); + +int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason); + +int hci_le_big_terminate_sync(struct hci_dev *hdev, u8 handle); + +int hci_le_pa_terminate_sync(struct hci_dev *hdev, u16 handle); diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c index 776d27f7e18d..8a85f6cdfbc1 100644 --- a/net/bluetooth/eir.c +++ b/net/bluetooth/eir.c @@ -236,6 +236,27 @@ void eir_create(struct hci_dev *hdev, u8 *data) ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); } +u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) +{ + struct adv_info *adv = NULL; + u8 ad_len = 0; + + /* Return 0 when the current instance identifier is invalid. */ + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + if (!adv) + return 0; + } + + if (adv) { + memcpy(ptr, adv->per_adv_data, adv->per_adv_data_len); + ad_len += adv->per_adv_data_len; + ptr += adv->per_adv_data_len; + } + + return ad_len; +} + u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) { struct adv_info *adv = NULL; diff --git a/net/bluetooth/eir.h b/net/bluetooth/eir.h index 62f2374078f2..0df19f2f4af9 100644 --- a/net/bluetooth/eir.h +++ b/net/bluetooth/eir.h @@ -11,6 +11,7 @@ void eir_create(struct hci_dev *hdev, u8 *data); u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr); u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr); +u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr); u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len); u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 97568723ddb0..f54864e19866 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -30,10 +30,13 @@ #include #include #include +#include +#include #include "hci_request.h" #include "smp.h" #include "a2mp.h" +#include "eir.h" struct sco_param { u16 pkt_type; @@ -684,6 +687,199 @@ static void le_conn_timeout(struct work_struct *work) hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); } +struct iso_list_data { + union { + u8 cig; + u8 big; + }; + union { + u8 cis; + u8 bis; + u16 sync_handle; + }; + int count; + struct { + struct hci_cp_le_set_cig_params cp; + struct hci_cis_params cis[0x11]; + } pdu; +}; + +static void bis_list(struct hci_conn *conn, void *data) +{ + struct iso_list_data *d = data; + + /* Skip if not broadcast/ANY address */ + if (bacmp(&conn->dst, BDADDR_ANY)) + return; + + if (d->big != conn->iso_qos.big || d->bis == BT_ISO_QOS_BIS_UNSET || + d->bis != conn->iso_qos.bis) + return; + + d->count++; +} + +static void find_bis(struct hci_conn *conn, void *data) +{ + struct iso_list_data *d = data; + + /* Ignore unicast */ + if (bacmp(&conn->dst, BDADDR_ANY)) + return; + + d->count++; +} + +static int terminate_big_sync(struct hci_dev *hdev, void *data) +{ + struct iso_list_data *d = data; + + bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", d->big, d->bis); + + hci_remove_ext_adv_instance_sync(hdev, d->bis, NULL); + + /* Check if ISO connection is a BIS and terminate BIG if there are + * no other connections using it. + */ + hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d); + if (d->count) + return 0; + + return hci_le_terminate_big_sync(hdev, d->big, + HCI_ERROR_LOCAL_HOST_TERM); +} + +static void terminate_big_destroy(struct hci_dev *hdev, void *data, int err) +{ + kfree(data); +} + +static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis) +{ + struct iso_list_data *d; + + bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", big, bis); + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + memset(d, 0, sizeof(*d)); + d->big = big; + d->bis = bis; + + return hci_cmd_sync_queue(hdev, terminate_big_sync, d, + terminate_big_destroy); +} + +static int big_terminate_sync(struct hci_dev *hdev, void *data) +{ + struct iso_list_data *d = data; + + bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", d->big, + d->sync_handle); + + /* Check if ISO connection is a BIS and terminate BIG if there are + * no other connections using it. + */ + hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d); + if (d->count) + return 0; + + hci_le_big_terminate_sync(hdev, d->big); + + return hci_le_pa_terminate_sync(hdev, d->sync_handle); +} + +static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle) +{ + struct iso_list_data *d; + + bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle); + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + memset(d, 0, sizeof(*d)); + d->big = big; + d->sync_handle = sync_handle; + + return hci_cmd_sync_queue(hdev, big_terminate_sync, d, + terminate_big_destroy); +} + +/* Cleanup BIS connection + * + * Detects if there any BIS left connected in a BIG + * broadcaster: Remove advertising instance and terminate BIG. + * broadcaster receiver: Teminate BIG sync and terminate PA sync. + */ +static void bis_cleanup(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + bt_dev_dbg(hdev, "conn %p", conn); + + if (conn->role == HCI_ROLE_MASTER) { + if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags)) + return; + + hci_le_terminate_big(hdev, conn->iso_qos.big, + conn->iso_qos.bis); + } else { + hci_le_big_terminate(hdev, conn->iso_qos.big, + conn->sync_handle); + } +} + +static int remove_cig_sync(struct hci_dev *hdev, void *data) +{ + u8 handle = PTR_ERR(data); + + return hci_le_remove_cig_sync(hdev, handle); +} + +static int hci_le_remove_cig(struct hci_dev *hdev, u8 handle) +{ + bt_dev_dbg(hdev, "handle 0x%2.2x", handle); + + return hci_cmd_sync_queue(hdev, remove_cig_sync, ERR_PTR(handle), NULL); +} + +static void find_cis(struct hci_conn *conn, void *data) +{ + struct iso_list_data *d = data; + + /* Ignore broadcast */ + if (!bacmp(&conn->dst, BDADDR_ANY)) + return; + + d->count++; +} + +/* Cleanup CIS connection: + * + * Detects if there any CIS left connected in a CIG and remove it. + */ +static void cis_cleanup(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + struct iso_list_data d; + + memset(&d, 0, sizeof(d)); + d.cig = conn->iso_qos.cig; + + /* Check if ISO connection is a CIS and remove CIG if there are + * no other connections using it. + */ + hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d); + if (d.count) + return; + + hci_le_remove_cig(hdev, conn->iso_qos.cig); +} + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, u8 role) { @@ -725,9 +921,19 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; case LE_LINK: + /* conn->src should reflect the local identity address */ + hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + break; case ISO_LINK: /* conn->src should reflect the local identity address */ hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + + /* set proper cleanup function */ + if (!bacmp(dst, BDADDR_ANY)) + conn->cleanup = bis_cleanup; + else if (conn->role == HCI_ROLE_MASTER) + conn->cleanup = cis_cleanup; + break; case SCO_LINK: if (lmp_esco_capable(hdev)) @@ -1100,6 +1306,108 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev, return 0; } +static int qos_set_big(struct hci_dev *hdev, struct bt_iso_qos *qos) +{ + struct iso_list_data data; + + /* Allocate a BIG if not set */ + if (qos->big == BT_ISO_QOS_BIG_UNSET) { + for (data.big = 0x00; data.big < 0xef; data.big++) { + data.count = 0; + data.bis = 0xff; + + hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, + BT_BOUND, &data); + if (!data.count) + break; + } + + if (data.big == 0xef) + return -EADDRNOTAVAIL; + + /* Update BIG */ + qos->big = data.big; + } + + return 0; +} + +static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) +{ + struct iso_list_data data; + + /* Allocate BIS if not set */ + if (qos->bis == BT_ISO_QOS_BIS_UNSET) { + /* Find an unused adv set to advertise BIS, skip instance 0x00 + * since it is reserved as general purpose set. + */ + for (data.bis = 0x01; data.bis < hdev->le_num_of_adv_sets; + data.bis++) { + data.count = 0; + + hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, + BT_BOUND, &data); + if (!data.count) + break; + } + + if (data.bis == hdev->le_num_of_adv_sets) + return -EADDRNOTAVAIL; + + /* Update BIS */ + qos->bis = data.bis; + } + + return 0; +} + +/* This function requires the caller holds hdev->lock */ +static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, + struct bt_iso_qos *qos) +{ + struct hci_conn *conn; + struct iso_list_data data; + int err; + + /* Let's make sure that le is enabled.*/ + if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { + if (lmp_le_capable(hdev)) + return ERR_PTR(-ECONNREFUSED); + return ERR_PTR(-EOPNOTSUPP); + } + + err = qos_set_big(hdev, qos); + if (err) + return ERR_PTR(err); + + err = qos_set_bis(hdev, qos); + if (err) + return ERR_PTR(err); + + data.big = qos->big; + data.bis = qos->bis; + data.count = 0; + + /* Check if there is already a matching BIG/BIS */ + hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, BT_BOUND, &data); + if (data.count) + return ERR_PTR(-EADDRINUSE); + + conn = hci_conn_hash_lookup_bis(hdev, dst, qos->big, qos->bis); + if (conn) + return ERR_PTR(-EADDRINUSE); + + conn = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); + if (!conn) + return ERR_PTR(-ENOMEM); + + set_bit(HCI_CONN_PER_ADV, &conn->flags); + conn->state = BT_CONNECT; + + hci_conn_hold(conn); + return conn; +} + /* This function requires the caller holds hdev->lock */ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, @@ -1236,16 +1544,6 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, return sco; } -struct iso_list_data { - u8 cig; - u8 cis; - int count; - struct { - struct hci_cp_le_set_cig_params cp; - struct hci_cis_params cis[0x11]; - } pdu; -}; - static void cis_add(struct iso_list_data *d, struct bt_iso_qos *qos) { struct hci_cis_params *cis = &d->pdu.cis[d->pdu.cp.num_cis]; @@ -1265,6 +1563,10 @@ static void cis_list(struct hci_conn *conn, void *data) { struct iso_list_data *d = data; + /* Skip if broadcast/ANY address */ + if (!bacmp(&conn->dst, BDADDR_ANY)) + return; + if (d->cig != conn->iso_qos.cig || d->cis == BT_ISO_QOS_CIS_UNSET || d->cis != conn->iso_qos.cis) return; @@ -1278,6 +1580,29 @@ static void cis_list(struct hci_conn *conn, void *data) cis_add(d, &conn->iso_qos); } +static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos) +{ + struct hci_dev *hdev = conn->hdev; + struct hci_cp_le_create_big cp; + + memset(&cp, 0, sizeof(cp)); + + cp.handle = qos->big; + cp.adv_handle = qos->bis; + cp.num_bis = 0x01; + hci_cpu_to_le24(qos->out.interval, cp.bis.sdu_interval); + cp.bis.sdu = cpu_to_le16(qos->out.sdu); + cp.bis.latency = cpu_to_le16(qos->out.latency); + cp.bis.rtn = qos->out.rtn; + cp.bis.phy = qos->out.phy; + cp.bis.packing = qos->packing; + cp.bis.framing = qos->framing; + cp.bis.encryption = 0x00; + memset(&cp.bis.bcode, 0, sizeof(cp.bis.bcode)); + + return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp); +} + static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) { struct hci_dev *hdev = conn->hdev; @@ -1361,49 +1686,6 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) return true; } -static void find_cis(struct hci_conn *conn, void *data) -{ - struct iso_list_data *d = data; - - /* Ignore broadcast */ - if (!bacmp(&conn->dst, BDADDR_ANY)) - return; - - d->count++; -} - -static int remove_cig_sync(struct hci_dev *hdev, void *data) -{ - u8 handle = PTR_ERR(data); - - return hci_le_remove_cig_sync(hdev, handle); -} - -int hci_le_remove_cig(struct hci_dev *hdev, u8 handle) -{ - bt_dev_dbg(hdev, "handle 0x%2.2x", handle); - - return hci_cmd_sync_queue(hdev, remove_cig_sync, ERR_PTR(handle), NULL); -} - -static void cis_cleanup(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - struct iso_list_data d; - - memset(&d, 0, sizeof(d)); - d.cig = conn->iso_qos.cig; - - /* Check if ISO connection is a CIS and remove CIG if there are - * no other connections using it. - */ - hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d); - if (d.count) - return; - - hci_le_remove_cig(hdev, conn->iso_qos.cig); -} - struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos) { @@ -1622,6 +1904,179 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, qos->latency = conn->le_conn_latency; } +static struct hci_conn *hci_bind_bis(struct hci_conn *conn, + struct bt_iso_qos *qos) +{ + /* Update LINK PHYs according to QoS preference */ + conn->le_tx_phy = qos->out.phy; + conn->le_tx_phy = qos->out.phy; + conn->iso_qos = *qos; + conn->state = BT_BOUND; + + return conn; +} + +static int create_big_sync(struct hci_dev *hdev, void *data) +{ + struct hci_conn *conn = data; + struct bt_iso_qos *qos = &conn->iso_qos; + u16 interval, sync_interval = 0; + u32 flags = 0; + int err; + + if (qos->out.phy == 0x02) + flags |= MGMT_ADV_FLAG_SEC_2M; + + /* Align intervals */ + interval = qos->out.interval / 1250; + + if (qos->bis) + sync_interval = qos->sync_interval * 1600; + + err = hci_start_per_adv_sync(hdev, qos->bis, conn->le_per_adv_data_len, + conn->le_per_adv_data, flags, interval, + interval, sync_interval); + if (err) + return err; + + return hci_le_create_big(conn, &conn->iso_qos); +} + +static void create_pa_complete(struct hci_dev *hdev, void *data, int err) +{ + struct hci_cp_le_pa_create_sync *cp = data; + + bt_dev_dbg(hdev, ""); + + if (err) + bt_dev_err(hdev, "Unable to create PA: %d", err); + + kfree(cp); +} + +static int create_pa_sync(struct hci_dev *hdev, void *data) +{ + struct hci_cp_le_pa_create_sync *cp = data; + int err; + + err = __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC, + sizeof(*cp), cp, HCI_CMD_TIMEOUT); + if (err) { + hci_dev_clear_flag(hdev, HCI_PA_SYNC); + return err; + } + + return hci_update_passive_scan_sync(hdev); +} + +int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, + __u8 sid) +{ + struct hci_cp_le_pa_create_sync *cp; + + if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC)) + return -EBUSY; + + cp = kmalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) { + hci_dev_clear_flag(hdev, HCI_PA_SYNC); + return -ENOMEM; + } + + /* Convert from ISO socket address type to HCI address type */ + if (dst_type == BDADDR_LE_PUBLIC) + dst_type = ADDR_LE_DEV_PUBLIC; + else + dst_type = ADDR_LE_DEV_RANDOM; + + memset(cp, 0, sizeof(*cp)); + cp->sid = sid; + cp->addr_type = dst_type; + bacpy(&cp->addr, dst); + + /* Queue start pa_create_sync and scan */ + return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete); +} + +int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos, + __u16 sync_handle, __u8 num_bis, __u8 bis[]) +{ + struct _packed { + struct hci_cp_le_big_create_sync cp; + __u8 bis[0x11]; + } pdu; + int err; + + if (num_bis > sizeof(pdu.bis)) + return -EINVAL; + + err = qos_set_big(hdev, qos); + if (err) + return err; + + memset(&pdu, 0, sizeof(pdu)); + pdu.cp.handle = qos->big; + pdu.cp.sync_handle = cpu_to_le16(sync_handle); + pdu.cp.num_bis = num_bis; + memcpy(pdu.bis, bis, num_bis); + + return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC, + sizeof(pdu.cp) + num_bis, &pdu); +} + +static void create_big_complete(struct hci_dev *hdev, void *data, int err) +{ + struct hci_conn *conn = data; + + bt_dev_dbg(hdev, "conn %p", conn); + + if (err) { + bt_dev_err(hdev, "Unable to create BIG: %d", err); + hci_connect_cfm(conn, err); + hci_conn_del(conn); + } +} + +struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, + __u8 dst_type, struct bt_iso_qos *qos, + __u8 base_len, __u8 *base) +{ + struct hci_conn *conn; + int err; + + /* We need hci_conn object using the BDADDR_ANY as dst */ + conn = hci_add_bis(hdev, dst, qos); + if (IS_ERR(conn)) + return conn; + + conn = hci_bind_bis(conn, qos); + if (!conn) { + hci_conn_drop(conn); + return ERR_PTR(-ENOMEM); + } + + /* Add Basic Announcement into Peridic Adv Data if BASE is set */ + if (base_len && base) { + base_len = eir_append_service_data(conn->le_per_adv_data, 0, + 0x1851, base, base_len); + conn->le_per_adv_data_len = base_len; + } + + /* Queue start periodic advertising and create BIG */ + err = hci_cmd_sync_queue(hdev, create_big_sync, conn, + create_big_complete); + if (err < 0) { + hci_conn_drop(conn); + return ERR_PTR(err); + } + + hci_iso_qos_setup(hdev, conn, &qos->out, + conn->le_tx_phy ? conn->le_tx_phy : + hdev->le_tx_def_phys); + + return conn; +} + struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, struct bt_iso_qos *qos) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 193d4e664acd..b3a5a3cc9372 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1702,57 +1702,77 @@ static void adv_instance_rpa_expired(struct work_struct *work) } /* This function requires the caller holds hdev->lock */ -int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, - u16 adv_data_len, u8 *adv_data, - u16 scan_rsp_len, u8 *scan_rsp_data, - u16 timeout, u16 duration, s8 tx_power, - u32 min_interval, u32 max_interval) +struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, + u32 flags, u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data, + u16 timeout, u16 duration, s8 tx_power, + u32 min_interval, u32 max_interval) { - struct adv_info *adv_instance; + struct adv_info *adv; - adv_instance = hci_find_adv_instance(hdev, instance); - if (adv_instance) { - memset(adv_instance->adv_data, 0, - sizeof(adv_instance->adv_data)); - memset(adv_instance->scan_rsp_data, 0, - sizeof(adv_instance->scan_rsp_data)); + adv = hci_find_adv_instance(hdev, instance); + if (adv) { + memset(adv->adv_data, 0, sizeof(adv->adv_data)); + memset(adv->scan_rsp_data, 0, sizeof(adv->scan_rsp_data)); + memset(adv->per_adv_data, 0, sizeof(adv->per_adv_data)); } else { if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets || instance < 1 || instance > hdev->le_num_of_adv_sets) - return -EOVERFLOW; + return ERR_PTR(-EOVERFLOW); - adv_instance = kzalloc(sizeof(*adv_instance), GFP_KERNEL); - if (!adv_instance) - return -ENOMEM; + adv = kzalloc(sizeof(*adv), GFP_KERNEL); + if (!adv) + return ERR_PTR(-ENOMEM); - adv_instance->pending = true; - adv_instance->instance = instance; - list_add(&adv_instance->list, &hdev->adv_instances); + adv->pending = true; + adv->instance = instance; + list_add(&adv->list, &hdev->adv_instances); hdev->adv_instance_cnt++; } - adv_instance->flags = flags; - adv_instance->min_interval = min_interval; - adv_instance->max_interval = max_interval; - adv_instance->tx_power = tx_power; + adv->flags = flags; + adv->min_interval = min_interval; + adv->max_interval = max_interval; + adv->tx_power = tx_power; hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data, scan_rsp_len, scan_rsp_data); - adv_instance->timeout = timeout; - adv_instance->remaining_time = timeout; + adv->timeout = timeout; + adv->remaining_time = timeout; if (duration == 0) - adv_instance->duration = hdev->def_multi_adv_rotation_duration; + adv->duration = hdev->def_multi_adv_rotation_duration; else - adv_instance->duration = duration; + adv->duration = duration; - INIT_DELAYED_WORK(&adv_instance->rpa_expired_cb, - adv_instance_rpa_expired); + INIT_DELAYED_WORK(&adv->rpa_expired_cb, adv_instance_rpa_expired); BT_DBG("%s for %dMR", hdev->name, instance); - return 0; + return adv; +} + +/* This function requires the caller holds hdev->lock */ +struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, + u32 flags, u8 data_len, u8 *data, + u32 min_interval, u32 max_interval) +{ + struct adv_info *adv; + + adv = hci_add_adv_instance(hdev, instance, flags, 0, NULL, 0, NULL, + 0, 0, HCI_ADV_TX_POWER_NO_PREFERENCE, + min_interval, max_interval); + if (IS_ERR(adv)) + return adv; + + adv->periodic = true; + adv->per_adv_data_len = data_len; + + if (data) + memcpy(adv->per_adv_data, data, data_len); + + return adv; } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 37177d7051d5..ea33dd0cd478 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3893,6 +3893,57 @@ unlock: return rp->status; } +static void hci_cs_le_create_big(struct hci_dev *hdev, u8 status) +{ + bt_dev_dbg(hdev, "status 0x%2.2x", status); +} + +static u8 hci_cc_set_per_adv_param(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_ev_status *rp = data; + struct hci_cp_le_set_per_adv_params *cp; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); + + if (rp->status) + return rp->status; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_PER_ADV_PARAMS); + if (!cp) + return rp->status; + + /* TODO: set the conn state */ + return rp->status; +} + +static u8 hci_cc_le_set_per_adv_enable(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_ev_status *rp = data; + __u8 *sent; + + bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); + + if (rp->status) + return rp->status; + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_PER_ADV_ENABLE); + if (!sent) + return rp->status; + + hci_dev_lock(hdev); + + if (*sent) + hci_dev_set_flag(hdev, HCI_LE_PER_ADV); + else + hci_dev_clear_flag(hdev, HCI_LE_PER_ADV); + + hci_dev_unlock(hdev); + + return rp->status; +} + #define HCI_CC_VL(_op, _func, _min, _max) \ { \ .op = _op, \ @@ -4066,6 +4117,9 @@ static const struct hci_cc { hci_cc_le_set_adv_set_random_addr), HCI_CC_STATUS(HCI_OP_LE_REMOVE_ADV_SET, hci_cc_le_remove_adv_set), HCI_CC_STATUS(HCI_OP_LE_CLEAR_ADV_SETS, hci_cc_le_clear_adv_sets), + HCI_CC_STATUS(HCI_OP_LE_SET_PER_ADV_PARAMS, hci_cc_set_per_adv_param), + HCI_CC_STATUS(HCI_OP_LE_SET_PER_ADV_ENABLE, + hci_cc_le_set_per_adv_enable), HCI_CC(HCI_OP_LE_READ_TRANSMIT_POWER, hci_cc_le_read_transmit_power, sizeof(struct hci_rp_le_read_transmit_power)), HCI_CC_STATUS(HCI_OP_LE_SET_PRIVACY_MODE, hci_cc_le_set_privacy_mode), @@ -4202,6 +4256,7 @@ static const struct hci_cs { HCI_CS(HCI_OP_LE_START_ENC, hci_cs_le_start_enc), HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn), HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis), + HCI_CS(HCI_OP_LE_CREATE_BIG, hci_cs_le_create_big), }; static void hci_cmd_status_evt(struct hci_dev *hdev, void *data, @@ -6425,6 +6480,39 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data, hci_dev_unlock(hdev); } +static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle) +{ + struct hci_cp_le_pa_term_sync cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = handle; + + return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp); +} + +static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_ev_le_pa_sync_established *ev = data; + int mask = hdev->link_mode; + __u8 flags = 0; + + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); + + if (ev->status) + return; + + hci_dev_lock(hdev); + + hci_dev_clear_flag(hdev, HCI_PA_SYNC); + + mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ISO_LINK, &flags); + if (!(mask & HCI_LM_ACCEPT)) + hci_le_pa_term_sync(hdev, ev->handle); + + hci_dev_unlock(hdev); +} + static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -6776,6 +6864,105 @@ unlock: hci_dev_unlock(hdev); } +static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_create_big_complete *ev = data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + + if (!hci_le_ev_skb_pull(hdev, skb, HCI_EVT_LE_CREATE_BIG_COMPLETE, + flex_array_size(ev, bis_handle, ev->num_bis))) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_big(hdev, ev->handle); + if (!conn) + goto unlock; + + if (ev->num_bis) + conn->handle = __le16_to_cpu(ev->bis_handle[0]); + + if (!ev->status) { + conn->state = BT_CONNECTED; + hci_debugfs_create_conn(conn); + hci_conn_add_sysfs(conn); + hci_iso_setup_path(conn); + goto unlock; + } + + hci_connect_cfm(conn, ev->status); + hci_conn_del(conn); + +unlock: + hci_dev_unlock(hdev); +} + +static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_big_sync_estabilished *ev = data; + struct hci_conn *bis; + int i; + + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); + + if (!hci_le_ev_skb_pull(hdev, skb, HCI_EVT_LE_BIG_SYNC_ESTABILISHED, + flex_array_size(ev, bis, ev->num_bis))) + return; + + if (ev->status) + return; + + hci_dev_lock(hdev); + + for (i = 0; i < ev->num_bis; i++) { + u16 handle = le16_to_cpu(ev->bis[i]); + __le32 interval; + + bis = hci_conn_hash_lookup_handle(hdev, handle); + if (!bis) { + bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY, + HCI_ROLE_SLAVE); + if (!bis) + continue; + bis->handle = handle; + } + + bis->iso_qos.big = ev->handle; + memset(&interval, 0, sizeof(interval)); + memcpy(&interval, ev->latency, sizeof(ev->latency)); + bis->iso_qos.in.interval = le32_to_cpu(interval); + /* Convert ISO Interval (1.25 ms slots) to latency (ms) */ + bis->iso_qos.in.latency = le16_to_cpu(ev->interval) * 125 / 100; + bis->iso_qos.in.sdu = le16_to_cpu(ev->max_pdu); + + hci_connect_cfm(bis, ev->status); + } + + hci_dev_unlock(hdev); +} + +static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, + struct sk_buff *skb) +{ + struct hci_evt_le_big_info_adv_report *ev = data; + int mask = hdev->link_mode; + __u8 flags = 0; + + bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle)); + + hci_dev_lock(hdev); + + mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags); + if (!(mask & HCI_LM_ACCEPT)) + hci_le_pa_term_sync(hdev, ev->sync_handle); + + hci_dev_unlock(hdev); +} + #define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \ [_op] = { \ .func = _func, \ @@ -6836,6 +7023,10 @@ static const struct hci_le_ev { HCI_LE_EV_VL(HCI_EV_LE_EXT_ADV_REPORT, hci_le_ext_adv_report_evt, sizeof(struct hci_ev_le_ext_adv_report), HCI_MAX_EVENT_SIZE), + /* [0x0e = HCI_EV_LE_PA_SYNC_ESTABLISHED] */ + HCI_LE_EV(HCI_EV_LE_PA_SYNC_ESTABLISHED, + hci_le_pa_sync_estabilished_evt, + sizeof(struct hci_ev_le_pa_sync_established)), /* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */ HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt, sizeof(struct hci_evt_le_ext_adv_set_term)), @@ -6845,6 +7036,21 @@ static const struct hci_le_ev { /* [0x1a = HCI_EVT_LE_CIS_REQ] */ HCI_LE_EV(HCI_EVT_LE_CIS_REQ, hci_le_cis_req_evt, sizeof(struct hci_evt_le_cis_req)), + /* [0x1b = HCI_EVT_LE_CREATE_BIG_COMPLETE] */ + HCI_LE_EV_VL(HCI_EVT_LE_CREATE_BIG_COMPLETE, + hci_le_create_big_complete_evt, + sizeof(struct hci_evt_le_create_big_complete), + HCI_MAX_EVENT_SIZE), + /* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABILISHED] */ + HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABILISHED, + hci_le_big_sync_established_evt, + sizeof(struct hci_evt_le_big_sync_estabilished), + HCI_MAX_EVENT_SIZE), + /* [0x22 = HCI_EVT_LE_BIG_INFO_ADV_REPORT] */ + HCI_LE_EV_VL(HCI_EVT_LE_BIG_INFO_ADV_REPORT, + hci_le_big_info_adv_report_evt, + sizeof(struct hci_evt_le_big_info_adv_report), + HCI_MAX_EVENT_SIZE), }; static void hci_le_meta_evt(struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index d93189f17193..e64d558e5d69 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -827,7 +827,6 @@ void __hci_req_disable_advertising(struct hci_request *req) { if (ext_adv_capable(req->hdev)) { __hci_req_disable_ext_adv_instance(req, 0x00); - } else { u8 enable = 0x00; @@ -1338,15 +1337,15 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) bdaddr_t random_addr; u8 own_addr_type; int err; - struct adv_info *adv_instance; - bool secondary_adv; + struct adv_info *adv; + bool secondary_adv, require_privacy; if (instance > 0) { - adv_instance = hci_find_adv_instance(hdev, instance); - if (!adv_instance) + adv = hci_find_adv_instance(hdev, instance); + if (!adv) return -EINVAL; } else { - adv_instance = NULL; + adv = NULL; } flags = hci_adv_instance_flags(hdev, instance); @@ -1364,18 +1363,24 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) * advertising is used. In that case it is fine to use a * non-resolvable private address. */ - err = hci_get_random_address(hdev, !connectable, - adv_use_rpa(hdev, flags), adv_instance, + require_privacy = !connectable; + + /* Don't require privacy for periodic adv? */ + if (adv && adv->periodic) + require_privacy = false; + + err = hci_get_random_address(hdev, require_privacy, + adv_use_rpa(hdev, flags), adv, &own_addr_type, &random_addr); if (err < 0) return err; memset(&cp, 0, sizeof(cp)); - if (adv_instance) { - hci_cpu_to_le24(adv_instance->min_interval, cp.min_interval); - hci_cpu_to_le24(adv_instance->max_interval, cp.max_interval); - cp.tx_power = adv_instance->tx_power; + if (adv) { + hci_cpu_to_le24(adv->min_interval, cp.min_interval); + hci_cpu_to_le24(adv->max_interval, cp.max_interval); + cp.tx_power = adv->tx_power; } else { hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval); hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval); @@ -1396,7 +1401,8 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) else cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_SCAN_IND); } else { - if (secondary_adv) + /* Secondary and periodic cannot use legacy PDUs */ + if (secondary_adv || (adv && adv->periodic)) cp.evt_properties = cpu_to_le16(LE_EXT_ADV_NON_CONN_IND); else cp.evt_properties = cpu_to_le16(LE_LEGACY_NONCONN_IND); @@ -1426,8 +1432,8 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance) struct hci_cp_le_set_adv_set_rand_addr cp; /* Check if random address need to be updated */ - if (adv_instance) { - if (!bacmp(&random_addr, &adv_instance->random_addr)) + if (adv) { + if (!bacmp(&random_addr, &adv->random_addr)) return 0; } else { if (!bacmp(&random_addr, &hdev->random_addr)) diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 821244ad9d73..39d001fa3acf 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -83,6 +83,9 @@ void __hci_req_enable_advertising(struct hci_request *req); void __hci_req_disable_advertising(struct hci_request *req); void __hci_req_update_adv_data(struct hci_request *req, u8 instance); int hci_req_update_adv_data(struct hci_dev *hdev, u8 instance); +int hci_req_start_per_adv(struct hci_dev *hdev, u8 instance, u32 flags, + u16 min_interval, u16 max_interval, + u16 sync_interval); void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance); int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance, @@ -92,8 +95,14 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk, bool force); int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance); +int __hci_req_setup_per_adv_instance(struct hci_request *req, u8 instance, + u16 min_interval, u16 max_interval); int __hci_req_start_ext_adv(struct hci_request *req, u8 instance); +int __hci_req_start_per_adv(struct hci_request *req, u8 instance, u32 flags, + u16 min_interval, u16 max_interval, + u16 sync_interval); int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance); +int __hci_req_enable_per_advertising(struct hci_request *req, u8 instance); int __hci_req_disable_ext_adv_instance(struct hci_request *req, u8 instance); int __hci_req_remove_ext_adv_instance(struct hci_request *req, u8 instance); void __hci_req_clear_ext_adv_sets(struct hci_request *req); diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index ac0f2cc0e44c..148ce629a59f 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -977,6 +977,187 @@ int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance) return hci_enable_ext_advertising_sync(hdev, instance); } +static int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance) +{ + struct hci_cp_le_set_per_adv_enable cp; + + /* If periodic advertising already disabled there is nothing to do. */ + if (!hci_dev_test_flag(hdev, HCI_LE_PER_ADV)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + cp.enable = 0x00; + cp.handle = instance; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_ENABLE, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + +static int hci_set_per_adv_params_sync(struct hci_dev *hdev, u8 instance, + u16 min_interval, u16 max_interval) +{ + struct hci_cp_le_set_per_adv_params cp; + + memset(&cp, 0, sizeof(cp)); + + if (!min_interval) + min_interval = DISCOV_LE_PER_ADV_INT_MIN; + + if (!max_interval) + max_interval = DISCOV_LE_PER_ADV_INT_MAX; + + cp.handle = instance; + cp.min_interval = cpu_to_le16(min_interval); + cp.max_interval = cpu_to_le16(max_interval); + cp.periodic_properties = 0x0000; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_PARAMS, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + +static int hci_set_per_adv_data_sync(struct hci_dev *hdev, u8 instance) +{ + struct { + struct hci_cp_le_set_per_adv_data cp; + u8 data[HCI_MAX_PER_AD_LENGTH]; + } pdu; + u8 len; + + memset(&pdu, 0, sizeof(pdu)); + + if (instance) { + struct adv_info *adv = hci_find_adv_instance(hdev, instance); + + if (!adv || !adv->periodic) + return 0; + } + + len = eir_create_per_adv_data(hdev, instance, pdu.data); + + pdu.cp.length = len; + pdu.cp.handle = instance; + pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA, + sizeof(pdu.cp) + len, &pdu, + HCI_CMD_TIMEOUT); +} + +static int hci_enable_per_advertising_sync(struct hci_dev *hdev, u8 instance) +{ + struct hci_cp_le_set_per_adv_enable cp; + + /* If periodic advertising already enabled there is nothing to do. */ + if (hci_dev_test_flag(hdev, HCI_LE_PER_ADV)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + cp.enable = 0x01; + cp.handle = instance; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_ENABLE, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + +/* Checks if periodic advertising data contains a Basic Announcement and if it + * does generates a Broadcast ID and add Broadcast Announcement. + */ +static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv) +{ + u8 bid[3]; + u8 ad[4 + 3]; + + /* Skip if NULL adv as instance 0x00 is used for general purpose + * advertising so it cannot used for the likes of Broadcast Announcement + * as it can be overwritten at any point. + */ + if (!adv) + return 0; + + /* Check if PA data doesn't contains a Basic Audio Announcement then + * there is nothing to do. + */ + if (!eir_get_service_data(adv->per_adv_data, adv->per_adv_data_len, + 0x1851, NULL)) + return 0; + + /* Check if advertising data already has a Broadcast Announcement since + * the process may want to control the Broadcast ID directly and in that + * case the kernel shall no interfere. + */ + if (eir_get_service_data(adv->adv_data, adv->adv_data_len, 0x1852, + NULL)) + return 0; + + /* Generate Broadcast ID */ + get_random_bytes(bid, sizeof(bid)); + eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid)); + hci_set_adv_instance_data(hdev, adv->instance, sizeof(ad), ad, 0, NULL); + + return hci_update_adv_data_sync(hdev, adv->instance); +} + +int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, + u8 *data, u32 flags, u16 min_interval, + u16 max_interval, u16 sync_interval) +{ + struct adv_info *adv = NULL; + int err; + bool added = false; + + hci_disable_per_advertising_sync(hdev, instance); + + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + /* Create an instance if that could not be found */ + if (!adv) { + adv = hci_add_per_instance(hdev, instance, flags, + data_len, data, + sync_interval, + sync_interval); + if (IS_ERR(adv)) + return PTR_ERR(adv); + added = true; + } + } + + /* Only start advertising if instance 0 or if a dedicated instance has + * been added. + */ + if (!adv || added) { + err = hci_start_ext_adv_sync(hdev, instance); + if (err < 0) + goto fail; + + err = hci_adv_bcast_annoucement(hdev, adv); + if (err < 0) + goto fail; + } + + err = hci_set_per_adv_params_sync(hdev, instance, min_interval, + max_interval); + if (err < 0) + goto fail; + + err = hci_set_per_adv_data_sync(hdev, instance); + if (err < 0) + goto fail; + + err = hci_enable_per_advertising_sync(hdev, instance); + if (err < 0) + goto fail; + + return 0; + +fail: + if (added) + hci_remove_adv_instance(hdev, instance); + + return err; +} + static int hci_start_adv_sync(struct hci_dev *hdev, u8 instance) { int err; @@ -1116,6 +1297,42 @@ int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance, HCI_CMD_TIMEOUT, sk); } +static int remove_ext_adv_sync(struct hci_dev *hdev, void *data) +{ + struct adv_info *adv = data; + u8 instance = 0; + + if (adv) + instance = adv->instance; + + return hci_remove_ext_adv_instance_sync(hdev, instance, NULL); +} + +int hci_remove_ext_adv_instance(struct hci_dev *hdev, u8 instance) +{ + struct adv_info *adv = NULL; + + if (instance) { + adv = hci_find_adv_instance(hdev, instance); + if (!adv) + return -EINVAL; + } + + return hci_cmd_sync_queue(hdev, remove_ext_adv_sync, adv, NULL); +} + +int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason) +{ + struct hci_cp_le_term_big cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = handle; + cp.reason = reason; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_TERM_BIG, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + static void cancel_adv_timeout(struct hci_dev *hdev) { if (hdev->adv_instance_timeout) { @@ -2201,7 +2418,8 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev) if (list_empty(&hdev->pend_le_conns) && list_empty(&hdev->pend_le_reports) && - !hci_is_adv_monitoring(hdev)) { + !hci_is_adv_monitoring(hdev) && + !hci_dev_test_flag(hdev, HCI_PA_SYNC)) { /* If there is no pending LE connections or devices * to be scanned for or no ADV monitors, we should stop the * background scanning. @@ -3405,6 +3623,13 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev) events[3] |= 0x02; /* LE CIS Request */ } + if (bis_capable(hdev)) { + events[3] |= 0x04; /* LE Create BIG Complete */ + events[3] |= 0x08; /* LE Terminate BIG Complete */ + events[3] |= 0x10; /* LE BIG Sync Established */ + events[3] |= 0x20; /* LE BIG Sync Loss */ + } + return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events, HCI_CMD_TIMEOUT); } @@ -5484,3 +5709,25 @@ int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle) return __hci_cmd_sync_status(hdev, HCI_OP_LE_REMOVE_CIG, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } + +int hci_le_big_terminate_sync(struct hci_dev *hdev, u8 handle) +{ + struct hci_cp_le_big_term_sync cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = handle; + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_BIG_TERM_SYNC, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} + +int hci_le_pa_terminate_sync(struct hci_dev *hdev, u16 handle) +{ + struct hci_cp_le_pa_term_sync cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(handle); + + return __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_TERM_SYNC, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08688117d700..8cfafd7a0576 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8158,7 +8158,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, u16 timeout, duration; unsigned int prev_instance_cnt; u8 schedule_instance = 0; - struct adv_info *next_instance; + struct adv_info *adv, *next_instance; int err; struct mgmt_pending_cmd *cmd; @@ -8209,7 +8209,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, prev_instance_cnt = hdev->adv_instance_cnt; - err = hci_add_adv_instance(hdev, cp->instance, flags, + adv = hci_add_adv_instance(hdev, cp->instance, flags, cp->adv_data_len, cp->data, cp->scan_rsp_len, cp->data + cp->adv_data_len, @@ -8217,7 +8217,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, HCI_ADV_TX_POWER_NO_PREFERENCE, hdev->le_adv_min_interval, hdev->le_adv_max_interval); - if (err < 0) { + if (IS_ERR(adv)) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_FAILED); goto unlock; @@ -8348,6 +8348,7 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev, struct mgmt_cp_add_ext_adv_params *cp = data; struct mgmt_rp_add_ext_adv_params rp; struct mgmt_pending_cmd *cmd = NULL; + struct adv_info *adv; u32 flags, min_interval, max_interval; u16 timeout, duration; u8 status; @@ -8417,11 +8418,11 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev, HCI_ADV_TX_POWER_NO_PREFERENCE; /* Create advertising instance with no advertising or response data */ - err = hci_add_adv_instance(hdev, cp->instance, flags, - 0, NULL, 0, NULL, timeout, duration, - tx_power, min_interval, max_interval); + adv = hci_add_adv_instance(hdev, cp->instance, flags, 0, NULL, 0, NULL, + timeout, duration, tx_power, min_interval, + max_interval); - if (err < 0) { + if (IS_ERR(adv)) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_PARAMS, MGMT_STATUS_FAILED); goto unlock; -- cgit v1.2.3 From f764a6c2c1e446f560faa3232271a0637369170b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 9 Mar 2022 13:14:41 -0800 Subject: Bluetooth: ISO: Add broadcast support This adds broadcast support for BTPROTO_ISO by extending the sockaddr_iso with a new struct sockaddr_iso_bc where the socket user can set the broadcast address when receiving, the SID and the BIS indexes it wants to synchronize. When using BTPROTO_ISO for broadcast the roles are: Broadcaster -> uses connect with address set to BDADDR_ANY: > tools/isotest -s 00:00:00:00:00:00 Broadcast Receiver -> uses listen with address set to broadcaster: > tools/isotest -d 00:AA:01:00:00:00 Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/bluetooth.h | 2 + include/net/bluetooth/iso.h | 11 ++ net/bluetooth/iso.c | 391 ++++++++++++++++++++++++++++++++++---- 3 files changed, 370 insertions(+), 34 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index bcc6e098f1f6..e72f3b247b5e 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -220,6 +220,8 @@ struct bt_codecs { #define BT_CODEC_TRANSPARENT 0x03 #define BT_CODEC_MSBC 0x05 +#define BT_ISO_BASE 20 + __printf(1, 2) void bt_info(const char *fmt, ...); __printf(1, 2) diff --git a/include/net/bluetooth/iso.h b/include/net/bluetooth/iso.h index 13b22d54aab5..3f4fe8b78e1b 100644 --- a/include/net/bluetooth/iso.h +++ b/include/net/bluetooth/iso.h @@ -10,12 +10,23 @@ /* ISO defaults */ #define ISO_DEFAULT_MTU 251 +#define ISO_MAX_NUM_BIS 0x1f + +/* ISO socket broadcast address */ +struct sockaddr_iso_bc { + bdaddr_t bc_bdaddr; + __u8 bc_bdaddr_type; + __u8 bc_sid; + __u8 bc_num_bis; + __u8 bc_bis[ISO_MAX_NUM_BIS]; +}; /* ISO socket address */ struct sockaddr_iso { sa_family_t iso_family; bdaddr_t iso_bdaddr; __u8 iso_bdaddr_type; + struct sockaddr_iso_bc iso_bc[]; }; #endif /* __ISO_H */ diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index caaaa670cc2c..ff09c353e64e 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -50,8 +50,14 @@ struct iso_pinfo { __u8 src_type; bdaddr_t dst; __u8 dst_type; + __u8 bc_sid; + __u8 bc_num_bis; + __u8 bc_bis[ISO_MAX_NUM_BIS]; + __u16 sync_handle; __u32 flags; struct bt_iso_qos qos; + __u8 base_len; + __u8 base[HCI_MAX_PER_AD_LENGTH]; struct iso_conn *conn; }; @@ -130,6 +136,7 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon) static void iso_chan_del(struct sock *sk, int err) { struct iso_conn *conn; + struct sock *parent; conn = iso_pi(sk)->conn; @@ -147,7 +154,14 @@ static void iso_chan_del(struct sock *sk, int err) sk->sk_state = BT_CLOSED; sk->sk_err = err; - sk->sk_state_change(sk); + + parent = bt_sk(sk)->parent; + if (parent) { + bt_accept_unlink(sk); + parent->sk_data_ready(parent); + } else { + sk->sk_state_change(sk); + } sock_set_flag(sk, SOCK_ZAPPED); } @@ -218,7 +232,70 @@ static int iso_chan_add(struct iso_conn *conn, struct sock *sk, return err; } -static int iso_connect(struct sock *sk) +static int iso_connect_bis(struct sock *sk) +{ + struct iso_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + int err; + + BT_DBG("%pMR", &iso_pi(sk)->src); + + hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, + iso_pi(sk)->src_type); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); + + if (!bis_capable(hdev)) { + err = -EOPNOTSUPP; + goto done; + } + + /* Fail if out PHYs are marked as disabled */ + if (!iso_pi(sk)->qos.out.phy) { + err = -EINVAL; + goto done; + } + + hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->dst_type, + &iso_pi(sk)->qos, iso_pi(sk)->base_len, + iso_pi(sk)->base); + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto done; + } + + conn = iso_conn_add(hcon); + if (!conn) { + hci_conn_drop(hcon); + err = -ENOMEM; + goto done; + } + + /* Update source addr of the socket */ + bacpy(&iso_pi(sk)->src, &hcon->src); + + err = iso_chan_add(conn, sk, NULL); + if (err) + goto done; + + if (hcon->state == BT_CONNECTED) { + iso_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + } else { + sk->sk_state = BT_CONNECT; + iso_sock_set_timer(sk, sk->sk_sndtimeo); + } + +done: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; +} + +static int iso_connect_cis(struct sock *sk) { struct iso_conn *conn; struct hci_conn *hcon; @@ -359,10 +436,39 @@ static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba) return NULL; } -/* Find socket listening on source bdaddr. +static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc, + __u8 sid) +{ + struct sock *sk; + + sk_for_each(sk, &iso_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; + + if (bacmp(&iso_pi(sk)->src, ba)) + continue; + + if (bacmp(&iso_pi(sk)->dst, bc)) + continue; + + if (iso_pi(sk)->bc_sid == sid) + return sk; + } + + return NULL; +} + +typedef bool (*iso_sock_match_t)(struct sock *sk, void *data); + +/* Find socket listening: + * source bdaddr (Unicast) + * destination bdaddr (Broadcast only) + * match func - pass NULL to ignore + * match func data - pass -1 to ignore * Returns closest match. */ -static struct sock *iso_get_sock_listen(bdaddr_t *src) +static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst, + iso_sock_match_t match, void *data) { struct sock *sk = NULL, *sk1 = NULL; @@ -372,6 +478,14 @@ static struct sock *iso_get_sock_listen(bdaddr_t *src) if (sk->sk_state != BT_LISTEN) continue; + /* Match Broadcast destination */ + if (bacmp(dst, BDADDR_ANY) && bacmp(&iso_pi(sk)->dst, dst)) + continue; + + /* Use Match function if provided */ + if (match && !match(sk, data)) + continue; + /* Exact match. */ if (!bacmp(&iso_pi(sk)->src, src)) break; @@ -587,6 +701,38 @@ static int iso_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } +static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + struct sockaddr_iso *sa = (struct sockaddr_iso *)addr; + struct sock *sk = sock->sk; + int i; + + BT_DBG("sk %p bc_sid %u bc_num_bis %u", sk, sa->iso_bc->bc_sid, + sa->iso_bc->bc_num_bis); + + if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc) || + sa->iso_bc->bc_num_bis < 0x01 || sa->iso_bc->bc_num_bis > 0x1f) + return -EINVAL; + + bacpy(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr); + iso_pi(sk)->dst_type = sa->iso_bc->bc_bdaddr_type; + iso_pi(sk)->sync_handle = -1; + iso_pi(sk)->bc_sid = sa->iso_bc->bc_sid; + iso_pi(sk)->bc_num_bis = sa->iso_bc->bc_num_bis; + + for (i = 0; i < iso_pi(sk)->bc_num_bis; i++) { + if (sa->iso_bc->bc_bis[i] < 0x01 || + sa->iso_bc->bc_bis[i] > 0x1f) + return -EINVAL; + + memcpy(iso_pi(sk)->bc_bis, sa->iso_bc->bc_bis, + iso_pi(sk)->bc_num_bis); + } + + return 0; +} + static int iso_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { @@ -621,6 +767,13 @@ static int iso_sock_bind(struct socket *sock, struct sockaddr *addr, bacpy(&iso_pi(sk)->src, &sa->iso_bdaddr); iso_pi(sk)->src_type = sa->iso_bdaddr_type; + /* Check for Broadcast address */ + if (addr_len > sizeof(*sa)) { + err = iso_sock_bind_bc(sock, addr, addr_len); + if (err) + goto done; + } + sk->sk_state = BT_BOUND; done: @@ -656,7 +809,11 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr *addr, bacpy(&iso_pi(sk)->dst, &sa->iso_bdaddr); iso_pi(sk)->dst_type = sa->iso_bdaddr_type; - err = iso_connect(sk); + if (bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) + err = iso_connect_cis(sk); + else + err = iso_connect_bis(sk); + if (err) goto done; @@ -670,10 +827,59 @@ done: return err; } +static int iso_listen_bis(struct sock *sk) +{ + struct hci_dev *hdev; + int err = 0; + + BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src, + &iso_pi(sk)->dst, iso_pi(sk)->bc_sid); + + write_lock(&iso_sk_list.lock); + + if (__iso_get_sock_listen_by_sid(&iso_pi(sk)->src, &iso_pi(sk)->dst, + iso_pi(sk)->bc_sid)) + err = -EADDRINUSE; + + write_unlock(&iso_sk_list.lock); + + if (err) + return err; + + hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src, + iso_pi(sk)->src_type); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); + + err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst, iso_pi(sk)->dst_type, + iso_pi(sk)->bc_sid); + + hci_dev_unlock(hdev); + + return err; +} + +static int iso_listen_cis(struct sock *sk) +{ + int err = 0; + + BT_DBG("%pMR", &iso_pi(sk)->src); + + write_lock(&iso_sk_list.lock); + + if (__iso_get_sock_listen_by_addr(&iso_pi(sk)->src)) + err = -EADDRINUSE; + + write_unlock(&iso_sk_list.lock); + + return err; +} + static int iso_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - bdaddr_t *src = &iso_pi(sk)->src; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); @@ -690,21 +896,19 @@ static int iso_sock_listen(struct socket *sock, int backlog) goto done; } - write_lock(&iso_sk_list.lock); + if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) + err = iso_listen_cis(sk); + else + err = iso_listen_bis(sk); - if (__iso_get_sock_listen_by_addr(src)) { - err = -EADDRINUSE; - goto unlock; - } + if (err) + goto done; sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; sk->sk_state = BT_LISTEN; -unlock: - write_unlock(&iso_sk_list.lock); - done: release_sock(sk); return err; @@ -886,7 +1090,7 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, release_sock(sk); return 0; case BT_CONNECT: - err = iso_connect(sk); + err = iso_connect_cis(sk); release_sock(sk); return err; } @@ -917,10 +1121,6 @@ static bool check_io_qos(struct bt_iso_io_qos *qos) static bool check_qos(struct bt_iso_qos *qos) { - /* CIS shall not be set */ - if (qos->cis != BT_ISO_QOS_CIS_UNSET) - return false; - if (qos->sca > 0x07) return false; @@ -996,6 +1196,29 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, break; + case BT_ISO_BASE: + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && + sk->sk_state != BT_CONNECT2) { + err = -EINVAL; + break; + } + + if (optlen > sizeof(iso_pi(sk)->base)) { + err = -EOVERFLOW; + break; + } + + len = min_t(unsigned int, sizeof(iso_pi(sk)->base), optlen); + + if (copy_from_sockptr(iso_pi(sk)->base, optval, len)) { + err = -EFAULT; + break; + } + + iso_pi(sk)->base_len = len; + + break; + default: err = -ENOPROTOOPT; break; @@ -1011,6 +1234,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; int len, err = 0; struct bt_iso_qos qos; + u8 base_len; + u8 *base; BT_DBG("sk %p", sk); @@ -1044,6 +1269,21 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, break; + case BT_ISO_BASE: + if (sk->sk_state == BT_CONNECTED) { + base_len = iso_pi(sk)->conn->hcon->le_per_adv_data_len; + base = iso_pi(sk)->conn->hcon->le_per_adv_data; + } else { + base_len = iso_pi(sk)->base_len; + base = iso_pi(sk)->base; + } + + len = min_t(unsigned int, len, base_len); + if (copy_to_user(optval, base, len)) + err = -EFAULT; + + break; + default: err = -ENOPROTOOPT; break; @@ -1126,10 +1366,18 @@ struct iso_list_data { int count; }; +static bool iso_match_big(struct sock *sk, void *data) +{ + struct hci_evt_le_big_sync_estabilished *ev = data; + + return ev->handle == iso_pi(sk)->qos.big; +} + static void iso_conn_ready(struct iso_conn *conn) { struct sock *parent; struct sock *sk = conn->sk; + struct hci_ev_le_big_sync_estabilished *ev; BT_DBG("conn %p", conn); @@ -1143,7 +1391,16 @@ static void iso_conn_ready(struct iso_conn *conn) return; } - parent = iso_get_sock_listen(&conn->hcon->src); + ev = hci_recv_event_data(conn->hcon->hdev, + HCI_EVT_LE_BIG_SYNC_ESTABILISHED); + if (ev) + parent = iso_get_sock_listen(&conn->hcon->src, + &conn->hcon->dst, + iso_match_big, ev); + else + parent = iso_get_sock_listen(&conn->hcon->src, + BDADDR_ANY, NULL, NULL); + if (!parent) { iso_conn_unlock(conn); return; @@ -1163,6 +1420,17 @@ static void iso_conn_ready(struct iso_conn *conn) bacpy(&iso_pi(sk)->src, &conn->hcon->src); iso_pi(sk)->src_type = conn->hcon->src_type; + + /* If hcon has no destination address (BDADDR_ANY) it means it + * was created by HCI_EV_LE_BIG_SYNC_ESTABILISHED so we need to + * initialize using the parent socket destination address. + */ + if (!bacmp(&conn->hcon->dst, BDADDR_ANY)) { + bacpy(&conn->hcon->dst, &iso_pi(parent)->dst); + conn->hcon->dst_type = iso_pi(parent)->dst_type; + conn->hcon->sync_handle = iso_pi(parent)->sync_handle; + } + bacpy(&iso_pi(sk)->dst, &conn->hcon->dst); iso_pi(sk)->dst_type = conn->hcon->dst_type; @@ -1183,30 +1451,85 @@ static void iso_conn_ready(struct iso_conn *conn) } } +static bool iso_match_sid(struct sock *sk, void *data) +{ + struct hci_ev_le_pa_sync_established *ev = data; + + return ev->sid == iso_pi(sk)->bc_sid; +} + +static bool iso_match_sync_handle(struct sock *sk, void *data) +{ + struct hci_evt_le_big_info_adv_report *ev = data; + + return le16_to_cpu(ev->sync_handle) == iso_pi(sk)->sync_handle; +} + /* ----- ISO interface with lower layer (HCI) ----- */ + int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) { + struct hci_ev_le_pa_sync_established *ev1; + struct hci_evt_le_big_info_adv_report *ev2; struct sock *sk; int lm = 0; - BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr); - - /* Find listening sockets */ - read_lock(&iso_sk_list.lock); - sk_for_each(sk, &iso_sk_list.head) { - if (sk->sk_state != BT_LISTEN) - continue; + bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr); + + /* Broadcast receiver requires handling of some events before it can + * proceed to establishing a BIG sync: + * + * 1. HCI_EV_LE_PA_SYNC_ESTABLISHED: The socket may specify a specific + * SID to listen to and once sync is estabilished its handle needs to + * be stored in iso_pi(sk)->sync_handle so it can be matched once + * receiving the BIG Info. + * 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a + * a BIG Info it attempts to check if there any listening socket with + * the same sync_handle and if it does then attempt to create a sync. + */ + ev1 = hci_recv_event_data(hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); + if (ev1) { + sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, iso_match_sid, + ev1); + if (sk) + iso_pi(sk)->sync_handle = le16_to_cpu(ev1->handle); - if (!bacmp(&iso_pi(sk)->src, &hdev->bdaddr) || - !bacmp(&iso_pi(sk)->src, BDADDR_ANY)) { - lm |= HCI_LM_ACCEPT; + goto done; + } - if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) - *flags |= HCI_PROTO_DEFER; - break; + ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT); + if (ev2) { + sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, + iso_match_sync_handle, ev2); + if (sk) { + int err; + + if (ev2->num_bis < iso_pi(sk)->bc_num_bis) + iso_pi(sk)->bc_num_bis = ev2->num_bis; + + err = hci_le_big_create_sync(hdev, + &iso_pi(sk)->qos, + iso_pi(sk)->sync_handle, + iso_pi(sk)->bc_num_bis, + iso_pi(sk)->bc_bis); + if (err) { + bt_dev_err(hdev, "hci_le_big_create_sync: %d", + err); + sk = NULL; + } } + } else { + sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); } - read_unlock(&iso_sk_list.lock); + +done: + if (!sk) + return lm; + + lm |= HCI_LM_ACCEPT; + + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) + *flags |= HCI_PROTO_DEFER; return lm; } -- cgit v1.2.3 From 7074732c8faee201a245a6f983008a5789c0be33 Mon Sep 17 00:00:00 2001 From: Matthias May Date: Thu, 21 Jul 2022 22:27:19 +0200 Subject: ip_tunnels: allow VXLAN/GENEVE to inherit TOS/TTL from VLAN The current code allows for VXLAN and GENEVE to inherit the TOS respective the TTL when skb-protocol is ETH_P_IP or ETH_P_IPV6. However when the payload is VLAN encapsulated, then this inheriting does not work, because the visible skb-protocol is of type ETH_P_8021Q or ETH_P_8021AD. Instead of skb->protocol use skb_protocol(). Signed-off-by: Matthias May Link: https://lore.kernel.org/r/20220721202718.10092-1-matthias.may@westermo.com Signed-off-by: Jakub Kicinski --- include/net/ip_tunnels.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 70cbc4a72669..20db95055db3 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -387,9 +387,11 @@ static inline int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, const struct sk_buff *skb) { - if (skb->protocol == htons(ETH_P_IP)) + __be16 payload_protocol = skb_protocol(skb, true); + + if (payload_protocol == htons(ETH_P_IP)) return iph->tos; - else if (skb->protocol == htons(ETH_P_IPV6)) + else if (payload_protocol == htons(ETH_P_IPV6)) return ipv6_get_dsfield((const struct ipv6hdr *)iph); else return 0; @@ -398,9 +400,11 @@ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, static inline u8 ip_tunnel_get_ttl(const struct iphdr *iph, const struct sk_buff *skb) { - if (skb->protocol == htons(ETH_P_IP)) + __be16 payload_protocol = skb_protocol(skb, true); + + if (payload_protocol == htons(ETH_P_IP)) return iph->ttl; - else if (skb->protocol == htons(ETH_P_IPV6)) + else if (payload_protocol == htons(ETH_P_IPV6)) return ((const struct ipv6hdr *)iph)->hop_limit; else return 0; -- cgit v1.2.3 From 72c531f8ef3052c682d39dc21dcb5576afda208c Mon Sep 17 00:00:00 2001 From: Dylan Yudaken Date: Thu, 14 Jul 2022 04:02:57 -0700 Subject: net: copy from user before calling __get_compat_msghdr this is in preparation for multishot receive from io_uring, where it needs to have access to the original struct user_msghdr. functionally this should be a no-op. Acked-by: Paolo Abeni Signed-off-by: Dylan Yudaken Link: https://lore.kernel.org/r/20220714110258.1336200-3-dylany@fb.com Signed-off-by: Jens Axboe --- include/net/compat.h | 5 ++--- io_uring/net.c | 17 +++++++++-------- net/compat.c | 39 +++++++++++++++++---------------------- 3 files changed, 28 insertions(+), 33 deletions(-) (limited to 'include/net') diff --git a/include/net/compat.h b/include/net/compat.h index 595fee069b82..84c163f40f38 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -46,9 +46,8 @@ struct compat_rtentry { unsigned short rt_irtt; /* Initial RTT */ }; -int __get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg, - struct sockaddr __user **save_addr, compat_uptr_t *ptr, - compat_size_t *len); +int __get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr *msg, + struct sockaddr __user **save_addr); int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, struct sockaddr __user **, struct iovec **); int put_cmsg_compat(struct msghdr*, int, int, int, void *); diff --git a/io_uring/net.c b/io_uring/net.c index da7667ed3610..5bc3440a8290 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -369,24 +369,25 @@ static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg) { struct io_sr_msg *sr = io_kiocb_to_cmd(req); + struct compat_msghdr msg; struct compat_iovec __user *uiov; - compat_uptr_t ptr; - compat_size_t len; int ret; - ret = __get_compat_msghdr(&iomsg->msg, sr->umsg_compat, &iomsg->uaddr, - &ptr, &len); + if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg))) + return -EFAULT; + + ret = __get_compat_msghdr(&iomsg->msg, sr->umsg_compat, &iomsg->uaddr); if (ret) return ret; - uiov = compat_ptr(ptr); + uiov = compat_ptr(msg.msg_iov); if (req->flags & REQ_F_BUFFER_SELECT) { compat_ssize_t clen; - if (len == 0) { + if (msg.msg_iovlen == 0) { sr->len = 0; iomsg->free_iov = NULL; - } else if (len > 1) { + } else if (msg.msg_iovlen > 1) { return -EINVAL; } else { if (!access_ok(uiov, sizeof(*uiov))) @@ -400,7 +401,7 @@ static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req, } } else { iomsg->free_iov = iomsg->fast_iov; - ret = __import_iovec(READ, (struct iovec __user *)uiov, len, + ret = __import_iovec(READ, (struct iovec __user *)uiov, msg.msg_iovlen, UIO_FASTIOV, &iomsg->free_iov, &iomsg->msg.msg_iter, true); if (ret < 0) diff --git a/net/compat.c b/net/compat.c index 210fc3b4d0d8..513aa9a3fc64 100644 --- a/net/compat.c +++ b/net/compat.c @@ -34,20 +34,15 @@ #include int __get_compat_msghdr(struct msghdr *kmsg, - struct compat_msghdr __user *umsg, - struct sockaddr __user **save_addr, - compat_uptr_t *ptr, compat_size_t *len) + struct compat_msghdr *msg, + struct sockaddr __user **save_addr) { - struct compat_msghdr msg; ssize_t err; - if (copy_from_user(&msg, umsg, sizeof(*umsg))) - return -EFAULT; - - kmsg->msg_flags = msg.msg_flags; - kmsg->msg_namelen = msg.msg_namelen; + kmsg->msg_flags = msg->msg_flags; + kmsg->msg_namelen = msg->msg_namelen; - if (!msg.msg_name) + if (!msg->msg_name) kmsg->msg_namelen = 0; if (kmsg->msg_namelen < 0) @@ -57,15 +52,15 @@ int __get_compat_msghdr(struct msghdr *kmsg, kmsg->msg_namelen = sizeof(struct sockaddr_storage); kmsg->msg_control_is_user = true; - kmsg->msg_control_user = compat_ptr(msg.msg_control); - kmsg->msg_controllen = msg.msg_controllen; + kmsg->msg_control_user = compat_ptr(msg->msg_control); + kmsg->msg_controllen = msg->msg_controllen; if (save_addr) - *save_addr = compat_ptr(msg.msg_name); + *save_addr = compat_ptr(msg->msg_name); - if (msg.msg_name && kmsg->msg_namelen) { + if (msg->msg_name && kmsg->msg_namelen) { if (!save_addr) { - err = move_addr_to_kernel(compat_ptr(msg.msg_name), + err = move_addr_to_kernel(compat_ptr(msg->msg_name), kmsg->msg_namelen, kmsg->msg_name); if (err < 0) @@ -76,12 +71,10 @@ int __get_compat_msghdr(struct msghdr *kmsg, kmsg->msg_namelen = 0; } - if (msg.msg_iovlen > UIO_MAXIOV) + if (msg->msg_iovlen > UIO_MAXIOV) return -EMSGSIZE; kmsg->msg_iocb = NULL; - *ptr = msg.msg_iov; - *len = msg.msg_iovlen; return 0; } @@ -90,15 +83,17 @@ int get_compat_msghdr(struct msghdr *kmsg, struct sockaddr __user **save_addr, struct iovec **iov) { - compat_uptr_t ptr; - compat_size_t len; + struct compat_msghdr msg; ssize_t err; - err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len); + if (copy_from_user(&msg, umsg, sizeof(*umsg))) + return -EFAULT; + + err = __get_compat_msghdr(kmsg, umsg, save_addr); if (err) return err; - err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len, + err = import_iovec(save_addr ? READ : WRITE, compat_ptr(msg.msg_iov), msg.msg_iovlen, UIO_FASTIOV, iov, &kmsg->msg_iter); return err < 0 ? err : 0; } -- cgit v1.2.3 From 451ef36bd229f8aa329cb2258a859b4c636d08ef Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Mon, 25 Jul 2022 16:31:37 +0200 Subject: ip_tunnels: Add new flow flags field to ip_tunnel_key This commit extends the ip_tunnel_key struct with a new field for the flow flags, to pass them to the route lookups. This new field will be populated and used in subsequent commits. Signed-off-by: Paul Chaignon Signed-off-by: Daniel Borkmann Reviewed-by: Nikolay Aleksandrov Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/f8bfd4983bd06685a59b1e3ba76ca27496f51ef3.1658759380.git.paul@isovalent.com --- include/net/ip_tunnels.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/net') diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 20db95055db3..63fac94f9ace 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -54,6 +54,7 @@ struct ip_tunnel_key { __be32 label; /* Flow Label for IPv6 */ __be16 tp_src; __be16 tp_dst; + __u8 flow_flags; }; /* Flags for ip_tunnel_info mode. */ -- cgit v1.2.3 From 46126db9c86110e5fc1e369b9bb89735ddefdae4 Mon Sep 17 00:00:00 2001 From: Wojciech Drewek Date: Mon, 18 Jul 2022 14:18:10 +0200 Subject: flow_dissector: Add PPPoE dissectors Allow to dissect PPPoE specific fields which are: - session ID (16 bits) - ppp protocol (16 bits) - type (16 bits) - this is PPPoE ethertype, for now only ETH_P_PPP_SES is supported, possible ETH_P_PPP_DISC in the future The goal is to make the following TC command possible: # tc filter add dev ens6f0 ingress prio 1 protocol ppp_ses \ flower \ pppoe_sid 12 \ ppp_proto ip \ action drop Note that only PPPoE Session is supported. Signed-off-by: Wojciech Drewek Acked-by: Guillaume Nault Signed-off-by: Tony Nguyen --- include/linux/ppp_defs.h | 14 ++++++++++++ include/net/flow_dissector.h | 13 +++++++++++ net/core/flow_dissector.c | 53 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 7 deletions(-) (limited to 'include/net') diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h index 9d2b388fae1a..b7e57fdbd413 100644 --- a/include/linux/ppp_defs.h +++ b/include/linux/ppp_defs.h @@ -11,4 +11,18 @@ #include #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) + +/** + * ppp_proto_is_valid - checks if PPP protocol is valid + * @proto: PPP protocol + * + * Assumes proto is not compressed. + * Protocol is valid if the value is odd and the least significant bit of the + * most significant octet is 0 (see RFC 1661, section 2). + */ +static inline bool ppp_proto_is_valid(u16 proto) +{ + return !!((proto & 0x0101) == 0x0001); +} + #endif /* _PPP_DEFS_H_ */ diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 0f9544a9bb9e..6c74812d64b2 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -277,6 +277,18 @@ struct flow_dissector_key_num_of_vlans { u8 num_of_vlans; }; +/** + * struct flow_dissector_key_pppoe: + * @session_id: pppoe session id + * @ppp_proto: ppp protocol + * @type: pppoe eth type + */ +struct flow_dissector_key_pppoe { + __be16 session_id; + __be16 ppp_proto; + __be16 type; +}; + enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ @@ -307,6 +319,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ FLOW_DISSECTOR_KEY_HASH, /* struct flow_dissector_key_hash */ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ + FLOW_DISSECTOR_KEY_PPPOE, /* struct flow_dissector_key_pppoe */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 6aee04f75e3e..237d396b6e41 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -895,6 +895,11 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, return result == BPF_OK; } +static bool is_pppoe_ses_hdr_valid(struct pppoe_hdr hdr) +{ + return hdr.ver == 1 && hdr.type == 1 && hdr.code == 0; +} + /** * __skb_flow_dissect - extract the flow_keys struct and return it * @net: associated network namespace, derived from @skb if NULL @@ -1214,26 +1219,60 @@ proto_again: struct pppoe_hdr hdr; __be16 proto; } *hdr, _hdr; + u16 ppp_proto; + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) { fdret = FLOW_DISSECT_RET_OUT_BAD; break; } - nhoff += PPPOE_SES_HLEN; - switch (hdr->proto) { - case htons(PPP_IP): + if (!is_pppoe_ses_hdr_valid(hdr->hdr)) { + fdret = FLOW_DISSECT_RET_OUT_BAD; + break; + } + + /* least significant bit of the most significant octet + * indicates if protocol field was compressed + */ + ppp_proto = ntohs(hdr->proto); + if (ppp_proto & 0x0100) { + ppp_proto = ppp_proto >> 8; + nhoff += PPPOE_SES_HLEN - 1; + } else { + nhoff += PPPOE_SES_HLEN; + } + + if (ppp_proto == PPP_IP) { proto = htons(ETH_P_IP); fdret = FLOW_DISSECT_RET_PROTO_AGAIN; - break; - case htons(PPP_IPV6): + } else if (ppp_proto == PPP_IPV6) { proto = htons(ETH_P_IPV6); fdret = FLOW_DISSECT_RET_PROTO_AGAIN; - break; - default: + } else if (ppp_proto == PPP_MPLS_UC) { + proto = htons(ETH_P_MPLS_UC); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; + } else if (ppp_proto == PPP_MPLS_MC) { + proto = htons(ETH_P_MPLS_MC); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; + } else if (ppp_proto_is_valid(ppp_proto)) { + fdret = FLOW_DISSECT_RET_OUT_GOOD; + } else { fdret = FLOW_DISSECT_RET_OUT_BAD; break; } + + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_PPPOE)) { + struct flow_dissector_key_pppoe *key_pppoe; + + key_pppoe = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_PPPOE, + target_container); + key_pppoe->session_id = hdr->hdr.sid; + key_pppoe->ppp_proto = htons(ppp_proto); + key_pppoe->type = htons(ETH_P_PPP_SES); + } break; } case htons(ETH_P_TIPC): { -- cgit v1.2.3 From 6a21b0856daaf9b7f63225f5b449ddee170c6f0a Mon Sep 17 00:00:00 2001 From: Wojciech Drewek Date: Mon, 18 Jul 2022 14:18:12 +0200 Subject: flow_offload: Introduce flow_match_pppoe Allow to offload PPPoE filters by adding flow_rule_match_pppoe. Drivers can extract PPPoE specific fields from now on. Signed-off-by: Wojciech Drewek Signed-off-by: Tony Nguyen --- include/net/flow_offload.h | 6 ++++++ net/core/flow_offload.c | 7 +++++++ 2 files changed, 13 insertions(+) (limited to 'include/net') diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h index a8d8512b7059..2a9a9e42e7fd 100644 --- a/include/net/flow_offload.h +++ b/include/net/flow_offload.h @@ -76,6 +76,10 @@ struct flow_match_ct { struct flow_dissector_key_ct *key, *mask; }; +struct flow_match_pppoe { + struct flow_dissector_key_pppoe *key, *mask; +}; + struct flow_rule; void flow_rule_match_meta(const struct flow_rule *rule, @@ -122,6 +126,8 @@ void flow_rule_match_enc_opts(const struct flow_rule *rule, struct flow_match_enc_opts *out); void flow_rule_match_ct(const struct flow_rule *rule, struct flow_match_ct *out); +void flow_rule_match_pppoe(const struct flow_rule *rule, + struct flow_match_pppoe *out); enum flow_action_id { FLOW_ACTION_ACCEPT = 0, diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c index 0d3075d3c8fb..8cfb63528d18 100644 --- a/net/core/flow_offload.c +++ b/net/core/flow_offload.c @@ -230,6 +230,13 @@ void flow_rule_match_ct(const struct flow_rule *rule, } EXPORT_SYMBOL(flow_rule_match_ct); +void flow_rule_match_pppoe(const struct flow_rule *rule, + struct flow_match_pppoe *out) +{ + FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PPPOE, out); +} +EXPORT_SYMBOL(flow_rule_match_pppoe); + struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb, void *cb_ident, void *cb_priv, void (*release)(void *cb_priv)) -- cgit v1.2.3 From 7b2d9a1a50ec3bedf067fe234a4a71196c89e826 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 25 Jul 2022 10:29:16 +0200 Subject: net: devlink: introduce nested devlink entity for line card For the purpose of exposing device info and allow flash update which is going to be implemented in follow-up patches, introduce a possibility for a line card to expose relation to nested devlink entity. The nested devlink entity represents the line card. Example: $ devlink lc show pci/0000:01:00.0 lc 1 pci/0000:01:00.0: lc 1 state active type 16x100G nested_devlink auxiliary/mlxsw_core.lc.0 supported_types: 16x100G $ devlink dev show auxiliary/mlxsw_core.lc.0 auxiliary/mlxsw_core.lc.0 Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Reviewed-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 2 ++ include/uapi/linux/devlink.h | 2 ++ net/core/devlink.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) (limited to 'include/net') diff --git a/include/net/devlink.h b/include/net/devlink.h index 780744b550b8..5bd3fac12e9e 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1580,6 +1580,8 @@ void devlink_linecard_provision_clear(struct devlink_linecard *linecard); void devlink_linecard_provision_fail(struct devlink_linecard *linecard); void devlink_linecard_activate(struct devlink_linecard *linecard); void devlink_linecard_deactivate(struct devlink_linecard *linecard); +void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, + struct devlink *nested_devlink); int devl_sb_register(struct devlink *devlink, unsigned int sb_index, u32 size, u16 ingress_pools_count, u16 egress_pools_count, u16 ingress_tc_count, diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index b3d40a5d72ff..541321695f52 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -576,6 +576,8 @@ enum devlink_attr { DEVLINK_ATTR_LINECARD_TYPE, /* string */ DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ + DEVLINK_ATTR_NESTED_DEVLINK, /* nested */ + /* add new attributes above here, update the policy in devlink.c */ __DEVLINK_ATTR_MAX, diff --git a/net/core/devlink.c b/net/core/devlink.c index 865232a1455f..698b2d6e0ec7 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -89,6 +89,7 @@ struct devlink_linecard { const char *type; struct devlink_linecard_type *types; unsigned int types_count; + struct devlink *nested_devlink; }; /** @@ -856,6 +857,24 @@ static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) return 0; } +static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink) +{ + struct nlattr *nested_attr; + + nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK); + if (!nested_attr) + return -EMSGSIZE; + if (devlink_nl_put_handle(msg, devlink)) + goto nla_put_failure; + + nla_nest_end(msg, nested_attr); + return 0; + +nla_put_failure: + nla_nest_cancel(msg, nested_attr); + return -EMSGSIZE; +} + struct devlink_reload_combination { enum devlink_reload_action action; enum devlink_reload_limit limit; @@ -2135,6 +2154,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, nla_nest_end(msg, attr); } + if (linecard->nested_devlink && + devlink_nl_put_nested_handle(msg, linecard->nested_devlink)) + goto nla_put_failure; + genlmsg_end(msg, hdr); return 0; @@ -10255,6 +10278,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); void devlink_linecard_provision_clear(struct devlink_linecard *linecard) { mutex_lock(&linecard->state_lock); + WARN_ON(linecard->nested_devlink); linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; linecard->type = NULL; devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); @@ -10273,6 +10297,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear); void devlink_linecard_provision_fail(struct devlink_linecard *linecard) { mutex_lock(&linecard->state_lock); + WARN_ON(linecard->nested_devlink); linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED; devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); mutex_unlock(&linecard->state_lock); @@ -10320,6 +10345,23 @@ void devlink_linecard_deactivate(struct devlink_linecard *linecard) } EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); +/** + * devlink_linecard_nested_dl_set - Attach/detach nested devlink + * instance to linecard. + * + * @linecard: devlink linecard + * @nested_devlink: devlink instance to attach or NULL to detach + */ +void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, + struct devlink *nested_devlink) +{ + mutex_lock(&linecard->state_lock); + linecard->nested_devlink = nested_devlink; + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); + mutex_unlock(&linecard->state_lock); +} +EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set); + int devl_sb_register(struct devlink *devlink, unsigned int sb_index, u32 size, u16 ingress_pools_count, u16 egress_pools_count, u16 ingress_tc_count, -- cgit v1.2.3 From 3f92a64e44e5823a975cbf2c9f05ab1893fd4cb7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 22 Jul 2022 16:50:31 -0700 Subject: tcp: allow tls to decrypt directly from the tcp rcv queue Expose TCP rx queue accessor and cleanup, so that TLS can decrypt directly from the TCP queue. The expectation is that the caller can access the skb returned from tcp_recv_skb() and up to inq bytes worth of data (some of which may be in ->next skbs) and then call tcp_read_done() when data has been consumed. The socket lock must be held continuously across those two operations. Signed-off-by: Jakub Kicinski --- include/net/tcp.h | 2 ++ net/ipv4/tcp.c | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/tcp.h b/include/net/tcp.h index f9e7c85ea829..b8620be32f8f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -673,6 +673,8 @@ void tcp_get_info(struct sock *, struct tcp_info *); int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor); +struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off); +void tcp_read_done(struct sock *sk, size_t len); void tcp_initialize_rcv_mss(struct sock *sk); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ba2bdc811374..dc7cc3ce6a53 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1635,7 +1635,7 @@ static void tcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) __kfree_skb(skb); } -static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) +struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) { struct sk_buff *skb; u32 offset; @@ -1658,6 +1658,7 @@ static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) } return NULL; } +EXPORT_SYMBOL(tcp_recv_skb); /* * This routine provides an alternative to tcp_recvmsg() for routines @@ -1788,6 +1789,45 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) } EXPORT_SYMBOL(tcp_read_skb); +void tcp_read_done(struct sock *sk, size_t len) +{ + struct tcp_sock *tp = tcp_sk(sk); + u32 seq = tp->copied_seq; + struct sk_buff *skb; + size_t left; + u32 offset; + + if (sk->sk_state == TCP_LISTEN) + return; + + left = len; + while (left && (skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { + int used; + + used = min_t(size_t, skb->len - offset, left); + seq += used; + left -= used; + + if (skb->len > offset + used) + break; + + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { + tcp_eat_recv_skb(sk, skb); + ++seq; + break; + } + tcp_eat_recv_skb(sk, skb); + } + WRITE_ONCE(tp->copied_seq, seq); + + tcp_rcv_space_adjust(sk); + + /* Clean up data we have read: This will do ACK frames. */ + if (left != len) + tcp_cleanup_rbuf(sk, len - left); +} +EXPORT_SYMBOL(tcp_read_done); + int tcp_peek_len(struct socket *sock) { return tcp_inq(sock->sk); -- cgit v1.2.3 From 84c61fe1a75b4255df1e1e7c054c9e6d048da417 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 22 Jul 2022 16:50:33 -0700 Subject: tls: rx: do not use the standard strparser TLS is a relatively poor fit for strparser. We pause the input every time a message is received, wait for a read which will decrypt the message, start the parser, repeat. strparser is built to delineate the messages, wrap them in individual skbs and let them float off into the stack or a different socket. TLS wants the data pages and nothing else. There's no need for TLS to keep cloning (and occasionally skb_unclone()'ing) the TCP rx queue. This patch uses a pre-allocated skb and attaches the skbs from the TCP rx queue to it as frags. TLS is careful never to modify the input skb without CoW'ing / detaching it first. Since we call TCP rx queue cleanup directly we also get back the benefit of skb deferred free. Overall this results in a 6% gain in my benchmarks. Acked-by: Paolo Abeni Signed-off-by: Jakub Kicinski --- include/net/tls.h | 19 ++- net/tls/tls.h | 24 ++- net/tls/tls_main.c | 20 ++- net/tls/tls_strp.c | 484 +++++++++++++++++++++++++++++++++++++++++++++++++++-- net/tls/tls_sw.c | 80 ++++----- 5 files changed, 558 insertions(+), 69 deletions(-) (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index 181c496b01b8..abb050b0df83 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -108,18 +108,33 @@ struct tls_sw_context_tx { unsigned long tx_bitmask; }; +struct tls_strparser { + struct sock *sk; + + u32 mark : 8; + u32 stopped : 1; + u32 copy_mode : 1; + u32 msg_ready : 1; + + struct strp_msg stm; + + struct sk_buff *anchor; + struct work_struct work; +}; + struct tls_sw_context_rx { struct crypto_aead *aead_recv; struct crypto_wait async_wait; - struct strparser strp; struct sk_buff_head rx_list; /* list of decrypted 'data' records */ void (*saved_data_ready)(struct sock *sk); - struct sk_buff *recv_pkt; u8 reader_present; u8 async_capable:1; u8 zc_capable:1; u8 reader_contended:1; + + struct tls_strparser strp; + atomic_t decrypt_pending; /* protect crypto_wait with decrypt_pending*/ spinlock_t decrypt_compl_lock; diff --git a/net/tls/tls.h b/net/tls/tls.h index 154a3773e785..0e840a0c3437 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016 Tom Herbert * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. * Copyright (c) 2016-2017, Dave Watson . All rights reserved. * @@ -127,10 +128,24 @@ int tls_sw_fallback_init(struct sock *sk, struct tls_offload_context_tx *offload_ctx, struct tls_crypto_info *crypto_info); +int tls_strp_dev_init(void); +void tls_strp_dev_exit(void); + +void tls_strp_done(struct tls_strparser *strp); +void tls_strp_stop(struct tls_strparser *strp); +int tls_strp_init(struct tls_strparser *strp, struct sock *sk); +void tls_strp_data_ready(struct tls_strparser *strp); + +void tls_strp_check_rcv(struct tls_strparser *strp); +void tls_strp_msg_done(struct tls_strparser *strp); + +int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb); +void tls_rx_msg_ready(struct tls_strparser *strp); + +void tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh); int tls_strp_msg_cow(struct tls_sw_context_rx *ctx); struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx); -int tls_strp_msg_hold(struct sock *sk, struct sk_buff *skb, - struct sk_buff_head *dst); +int tls_strp_msg_hold(struct tls_strparser *strp, struct sk_buff_head *dst); static inline struct tls_msg *tls_msg(struct sk_buff *skb) { @@ -141,12 +156,13 @@ static inline struct tls_msg *tls_msg(struct sk_buff *skb) static inline struct sk_buff *tls_strp_msg(struct tls_sw_context_rx *ctx) { - return ctx->recv_pkt; + DEBUG_NET_WARN_ON_ONCE(!ctx->strp.msg_ready || !ctx->strp.anchor->len); + return ctx->strp.anchor; } static inline bool tls_strp_msg_ready(struct tls_sw_context_rx *ctx) { - return ctx->recv_pkt; + return ctx->strp.msg_ready; } #ifdef CONFIG_TLS_DEVICE diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 9703636cfc60..08ddf9d837ae 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -725,6 +725,10 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval, if (tx) { ctx->sk_write_space = sk->sk_write_space; sk->sk_write_space = tls_write_space; + } else { + struct tls_sw_context_rx *rx_ctx = tls_sw_ctx_rx(ctx); + + tls_strp_check_rcv(&rx_ctx->strp); } return 0; @@ -1141,20 +1145,28 @@ static int __init tls_register(void) if (err) return err; + err = tls_strp_dev_init(); + if (err) + goto err_pernet; + err = tls_device_init(); - if (err) { - unregister_pernet_subsys(&tls_proc_ops); - return err; - } + if (err) + goto err_strp; tcp_register_ulp(&tcp_tls_ulp_ops); return 0; +err_strp: + tls_strp_dev_exit(); +err_pernet: + unregister_pernet_subsys(&tls_proc_ops); + return err; } static void __exit tls_unregister(void) { tcp_unregister_ulp(&tcp_tls_ulp_ops); + tls_strp_dev_exit(); tls_device_cleanup(); unregister_pernet_subsys(&tls_proc_ops); } diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index d9bb4f23f01a..b945288c312e 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -1,37 +1,493 @@ // SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2016 Tom Herbert */ #include +#include +#include +#include +#include +#include #include "tls.h" -struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx) +static struct workqueue_struct *tls_strp_wq; + +static void tls_strp_abort_strp(struct tls_strparser *strp, int err) +{ + if (strp->stopped) + return; + + strp->stopped = 1; + + /* Report an error on the lower socket */ + strp->sk->sk_err = -err; + sk_error_report(strp->sk); +} + +static void tls_strp_anchor_free(struct tls_strparser *strp) { + struct skb_shared_info *shinfo = skb_shinfo(strp->anchor); + + DEBUG_NET_WARN_ON_ONCE(atomic_read(&shinfo->dataref) != 1); + shinfo->frag_list = NULL; + consume_skb(strp->anchor); + strp->anchor = NULL; +} + +/* Create a new skb with the contents of input copied to its page frags */ +static struct sk_buff *tls_strp_msg_make_copy(struct tls_strparser *strp) +{ + struct strp_msg *rxm; struct sk_buff *skb; + int i, err, offset; + + skb = alloc_skb_with_frags(0, strp->anchor->len, TLS_PAGE_ORDER, + &err, strp->sk->sk_allocation); + if (!skb) + return NULL; + + offset = strp->stm.offset; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - skb = ctx->recv_pkt; - ctx->recv_pkt = NULL; + WARN_ON_ONCE(skb_copy_bits(strp->anchor, offset, + skb_frag_address(frag), + skb_frag_size(frag))); + offset += skb_frag_size(frag); + } + + skb_copy_header(skb, strp->anchor); + rxm = strp_msg(skb); + rxm->offset = 0; return skb; } +/* Steal the input skb, input msg is invalid after calling this function */ +struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx) +{ + struct tls_strparser *strp = &ctx->strp; + +#ifdef CONFIG_TLS_DEVICE + DEBUG_NET_WARN_ON_ONCE(!strp->anchor->decrypted); +#else + /* This function turns an input into an output, + * that can only happen if we have offload. + */ + WARN_ON(1); +#endif + + if (strp->copy_mode) { + struct sk_buff *skb; + + /* Replace anchor with an empty skb, this is a little + * dangerous but __tls_cur_msg() warns on empty skbs + * so hopefully we'll catch abuses. + */ + skb = alloc_skb(0, strp->sk->sk_allocation); + if (!skb) + return NULL; + + swap(strp->anchor, skb); + return skb; + } + + return tls_strp_msg_make_copy(strp); +} + +/* Force the input skb to be in copy mode. The data ownership remains + * with the input skb itself (meaning unpause will wipe it) but it can + * be modified. + */ int tls_strp_msg_cow(struct tls_sw_context_rx *ctx) { - struct sk_buff *unused; - int nsg; + struct tls_strparser *strp = &ctx->strp; + struct sk_buff *skb; + + if (strp->copy_mode) + return 0; + + skb = tls_strp_msg_make_copy(strp); + if (!skb) + return -ENOMEM; + + tls_strp_anchor_free(strp); + strp->anchor = skb; + + tcp_read_done(strp->sk, strp->stm.full_len); + strp->copy_mode = 1; + + return 0; +} + +/* Make a clone (in the skb sense) of the input msg to keep a reference + * to the underlying data. The reference-holding skbs get placed on + * @dst. + */ +int tls_strp_msg_hold(struct tls_strparser *strp, struct sk_buff_head *dst) +{ + struct skb_shared_info *shinfo = skb_shinfo(strp->anchor); + + if (strp->copy_mode) { + struct sk_buff *skb; + + WARN_ON_ONCE(!shinfo->nr_frags); + + /* We can't skb_clone() the anchor, it gets wiped by unpause */ + skb = alloc_skb(0, strp->sk->sk_allocation); + if (!skb) + return -ENOMEM; + + __skb_queue_tail(dst, strp->anchor); + strp->anchor = skb; + } else { + struct sk_buff *iter, *clone; + int chunk, len, offset; + + offset = strp->stm.offset; + len = strp->stm.full_len; + iter = shinfo->frag_list; + + while (len > 0) { + if (iter->len <= offset) { + offset -= iter->len; + goto next; + } + + chunk = iter->len - offset; + offset = 0; + + clone = skb_clone(iter, strp->sk->sk_allocation); + if (!clone) + return -ENOMEM; + __skb_queue_tail(dst, clone); + + len -= chunk; +next: + iter = iter->next; + } + } + + return 0; +} + +static void tls_strp_flush_anchor_copy(struct tls_strparser *strp) +{ + struct skb_shared_info *shinfo = skb_shinfo(strp->anchor); + int i; + + DEBUG_NET_WARN_ON_ONCE(atomic_read(&shinfo->dataref) != 1); + + for (i = 0; i < shinfo->nr_frags; i++) + __skb_frag_unref(&shinfo->frags[i], false); + shinfo->nr_frags = 0; + strp->copy_mode = 0; +} + +static int tls_strp_copyin(read_descriptor_t *desc, struct sk_buff *in_skb, + unsigned int offset, size_t in_len) +{ + struct tls_strparser *strp = (struct tls_strparser *)desc->arg.data; + size_t sz, len, chunk; + struct sk_buff *skb; + skb_frag_t *frag; + + if (strp->msg_ready) + return 0; + + skb = strp->anchor; + frag = &skb_shinfo(skb)->frags[skb->len / PAGE_SIZE]; + + len = in_len; + /* First make sure we got the header */ + if (!strp->stm.full_len) { + /* Assume one page is more than enough for headers */ + chunk = min_t(size_t, len, PAGE_SIZE - skb_frag_size(frag)); + WARN_ON_ONCE(skb_copy_bits(in_skb, offset, + skb_frag_address(frag) + + skb_frag_size(frag), + chunk)); + + sz = tls_rx_msg_size(strp, strp->anchor); + if (sz < 0) { + desc->error = sz; + return 0; + } + + /* We may have over-read, sz == 0 is guaranteed under-read */ + if (sz > 0) + chunk = min_t(size_t, chunk, sz - skb->len); + + skb->len += chunk; + skb->data_len += chunk; + skb_frag_size_add(frag, chunk); + frag++; + len -= chunk; + offset += chunk; + + strp->stm.full_len = sz; + if (!strp->stm.full_len) + goto read_done; + } + + /* Load up more data */ + while (len && strp->stm.full_len > skb->len) { + chunk = min_t(size_t, len, strp->stm.full_len - skb->len); + chunk = min_t(size_t, chunk, PAGE_SIZE - skb_frag_size(frag)); + WARN_ON_ONCE(skb_copy_bits(in_skb, offset, + skb_frag_address(frag) + + skb_frag_size(frag), + chunk)); + + skb->len += chunk; + skb->data_len += chunk; + skb_frag_size_add(frag, chunk); + frag++; + len -= chunk; + offset += chunk; + } + + if (strp->stm.full_len == skb->len) { + desc->count = 0; + + strp->msg_ready = 1; + tls_rx_msg_ready(strp); + } + +read_done: + return in_len - len; +} + +static int tls_strp_read_copyin(struct tls_strparser *strp) +{ + struct socket *sock = strp->sk->sk_socket; + read_descriptor_t desc; + + desc.arg.data = strp; + desc.error = 0; + desc.count = 1; /* give more than one skb per call */ + + /* sk should be locked here, so okay to do read_sock */ + sock->ops->read_sock(strp->sk, &desc, tls_strp_copyin); + + return desc.error; +} + +static int tls_strp_read_short(struct tls_strparser *strp) +{ + struct skb_shared_info *shinfo; + struct page *page; + int need_spc, len; + + /* If the rbuf is small or rcv window has collapsed to 0 we need + * to read the data out. Otherwise the connection will stall. + * Without pressure threshold of INT_MAX will never be ready. + */ + if (likely(!tcp_epollin_ready(strp->sk, INT_MAX))) + return 0; + + shinfo = skb_shinfo(strp->anchor); + shinfo->frag_list = NULL; + + /* If we don't know the length go max plus page for cipher overhead */ + need_spc = strp->stm.full_len ?: TLS_MAX_PAYLOAD_SIZE + PAGE_SIZE; + + for (len = need_spc; len > 0; len -= PAGE_SIZE) { + page = alloc_page(strp->sk->sk_allocation); + if (!page) { + tls_strp_flush_anchor_copy(strp); + return -ENOMEM; + } + + skb_fill_page_desc(strp->anchor, shinfo->nr_frags++, + page, 0, 0); + } + + strp->copy_mode = 1; + strp->stm.offset = 0; + + strp->anchor->len = 0; + strp->anchor->data_len = 0; + strp->anchor->truesize = round_up(need_spc, PAGE_SIZE); + + tls_strp_read_copyin(strp); + + return 0; +} + +static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len) +{ + struct tcp_sock *tp = tcp_sk(strp->sk); + struct sk_buff *first; + u32 offset; + + first = tcp_recv_skb(strp->sk, tp->copied_seq, &offset); + if (WARN_ON_ONCE(!first)) + return; + + /* Bestow the state onto the anchor */ + strp->anchor->len = offset + len; + strp->anchor->data_len = offset + len; + strp->anchor->truesize = offset + len; + + skb_shinfo(strp->anchor)->frag_list = first; + + skb_copy_header(strp->anchor, first); + strp->anchor->destructor = NULL; + + strp->stm.offset = offset; +} + +void tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh) +{ + struct strp_msg *rxm; + struct tls_msg *tlm; + + DEBUG_NET_WARN_ON_ONCE(!strp->msg_ready); + DEBUG_NET_WARN_ON_ONCE(!strp->stm.full_len); + + if (!strp->copy_mode && force_refresh) { + if (WARN_ON(tcp_inq(strp->sk) < strp->stm.full_len)) + return; + + tls_strp_load_anchor_with_queue(strp, strp->stm.full_len); + } + + rxm = strp_msg(strp->anchor); + rxm->full_len = strp->stm.full_len; + rxm->offset = strp->stm.offset; + tlm = tls_msg(strp->anchor); + tlm->control = strp->mark; +} + +/* Called with lock held on lower socket */ +static int tls_strp_read_sock(struct tls_strparser *strp) +{ + int sz, inq; + + inq = tcp_inq(strp->sk); + if (inq < 1) + return 0; + + if (unlikely(strp->copy_mode)) + return tls_strp_read_copyin(strp); + + if (inq < strp->stm.full_len) + return tls_strp_read_short(strp); + + if (!strp->stm.full_len) { + tls_strp_load_anchor_with_queue(strp, inq); + + sz = tls_rx_msg_size(strp, strp->anchor); + if (sz < 0) { + tls_strp_abort_strp(strp, sz); + return sz; + } + + strp->stm.full_len = sz; + + if (!strp->stm.full_len || inq < strp->stm.full_len) + return tls_strp_read_short(strp); + } + + strp->msg_ready = 1; + tls_rx_msg_ready(strp); + + return 0; +} + +void tls_strp_check_rcv(struct tls_strparser *strp) +{ + if (unlikely(strp->stopped) || strp->msg_ready) + return; + + if (tls_strp_read_sock(strp) == -ENOMEM) + queue_work(tls_strp_wq, &strp->work); +} + +/* Lower sock lock held */ +void tls_strp_data_ready(struct tls_strparser *strp) +{ + /* This check is needed to synchronize with do_tls_strp_work. + * do_tls_strp_work acquires a process lock (lock_sock) whereas + * the lock held here is bh_lock_sock. The two locks can be + * held by different threads at the same time, but bh_lock_sock + * allows a thread in BH context to safely check if the process + * lock is held. In this case, if the lock is held, queue work. + */ + if (sock_owned_by_user_nocheck(strp->sk)) { + queue_work(tls_strp_wq, &strp->work); + return; + } + + tls_strp_check_rcv(strp); +} + +static void tls_strp_work(struct work_struct *w) +{ + struct tls_strparser *strp = + container_of(w, struct tls_strparser, work); + + lock_sock(strp->sk); + tls_strp_check_rcv(strp); + release_sock(strp->sk); +} + +void tls_strp_msg_done(struct tls_strparser *strp) +{ + WARN_ON(!strp->stm.full_len); + + if (likely(!strp->copy_mode)) + tcp_read_done(strp->sk, strp->stm.full_len); + else + tls_strp_flush_anchor_copy(strp); + + strp->msg_ready = 0; + memset(&strp->stm, 0, sizeof(strp->stm)); + + tls_strp_check_rcv(strp); +} + +void tls_strp_stop(struct tls_strparser *strp) +{ + strp->stopped = 1; +} + +int tls_strp_init(struct tls_strparser *strp, struct sock *sk) +{ + memset(strp, 0, sizeof(*strp)); + + strp->sk = sk; + + strp->anchor = alloc_skb(0, GFP_KERNEL); + if (!strp->anchor) + return -ENOMEM; + + INIT_WORK(&strp->work, tls_strp_work); - nsg = skb_cow_data(ctx->recv_pkt, 0, &unused); - if (nsg < 0) - return nsg; return 0; } -int tls_strp_msg_hold(struct sock *sk, struct sk_buff *skb, - struct sk_buff_head *dst) +/* strp must already be stopped so that tls_strp_recv will no longer be called. + * Note that tls_strp_done is not called with the lower socket held. + */ +void tls_strp_done(struct tls_strparser *strp) { - struct sk_buff *clone; + WARN_ON(!strp->stopped); - clone = skb_clone(skb, sk->sk_allocation); - if (!clone) + cancel_work_sync(&strp->work); + tls_strp_anchor_free(strp); +} + +int __init tls_strp_dev_init(void) +{ + tls_strp_wq = create_singlethread_workqueue("kstrp"); + if (unlikely(!tls_strp_wq)) return -ENOMEM; - __skb_queue_tail(dst, clone); + return 0; } + +void tls_strp_dev_exit(void) +{ + destroy_workqueue(tls_strp_wq); +} diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index bd4486819e64..0fc24a5ce208 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1283,7 +1283,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, static int tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, - long timeo) + bool released, long timeo) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); @@ -1297,7 +1297,7 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, return sock_error(sk); if (!skb_queue_empty(&sk->sk_receive_queue)) { - __strp_unpause(&ctx->strp); + tls_strp_check_rcv(&ctx->strp); if (tls_strp_msg_ready(ctx)) break; } @@ -1311,6 +1311,7 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, if (nonblock || !timeo) return -EAGAIN; + released = true; add_wait_queue(sk_sleep(sk), &wait); sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); sk_wait_event(sk, &timeo, @@ -1325,6 +1326,8 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, return sock_intr_errno(timeo); } + tls_strp_msg_load(&ctx->strp, released); + return 1; } @@ -1570,7 +1573,7 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov, clear_skb = NULL; if (unlikely(darg->async)) { - err = tls_strp_msg_hold(sk, skb, &ctx->async_hold); + err = tls_strp_msg_hold(&ctx->strp, &ctx->async_hold); if (err) __skb_queue_tail(&ctx->async_hold, darg->skb); return err; @@ -1734,9 +1737,7 @@ static int tls_record_content_type(struct msghdr *msg, struct tls_msg *tlm, static void tls_rx_rec_done(struct tls_sw_context_rx *ctx) { - consume_skb(ctx->recv_pkt); - ctx->recv_pkt = NULL; - __strp_unpause(&ctx->strp); + tls_strp_msg_done(&ctx->strp); } /* This function traverses the rx_list in tls receive context to copies the @@ -1823,7 +1824,7 @@ out: return copied ? : err; } -static void +static bool tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot, size_t len_left, size_t decrypted, ssize_t done, size_t *flushed_at) @@ -1831,14 +1832,14 @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot, size_t max_rec; if (len_left <= decrypted) - return; + return false; max_rec = prot->overhead_size - prot->tail_size + TLS_MAX_PAYLOAD_SIZE; if (done - *flushed_at < SZ_128K && tcp_inq(sk) > max_rec) - return; + return false; *flushed_at = done; - sk_flush_backlog(sk); + return sk_flush_backlog(sk); } static long tls_rx_reader_lock(struct sock *sk, struct tls_sw_context_rx *ctx, @@ -1916,6 +1917,7 @@ int tls_sw_recvmsg(struct sock *sk, long timeo; bool is_kvec = iov_iter_is_kvec(&msg->msg_iter); bool is_peek = flags & MSG_PEEK; + bool released = true; bool bpf_strp_enabled; bool zc_capable; @@ -1952,7 +1954,8 @@ int tls_sw_recvmsg(struct sock *sk, struct tls_decrypt_arg darg; int to_decrypt, chunk; - err = tls_rx_rec_wait(sk, psock, flags & MSG_DONTWAIT, timeo); + err = tls_rx_rec_wait(sk, psock, flags & MSG_DONTWAIT, released, + timeo); if (err <= 0) { if (psock) { chunk = sk_msg_recvmsg(sk, psock, msg, len, @@ -1968,8 +1971,8 @@ int tls_sw_recvmsg(struct sock *sk, memset(&darg.inargs, 0, sizeof(darg.inargs)); - rxm = strp_msg(ctx->recv_pkt); - tlm = tls_msg(ctx->recv_pkt); + rxm = strp_msg(tls_strp_msg(ctx)); + tlm = tls_msg(tls_strp_msg(ctx)); to_decrypt = rxm->full_len - prot->overhead_size; @@ -2008,8 +2011,9 @@ put_on_rx_list_err: } /* periodically flush backlog, and feed strparser */ - tls_read_flush_backlog(sk, prot, len, to_decrypt, - decrypted + copied, &flushed_at); + released = tls_read_flush_backlog(sk, prot, len, to_decrypt, + decrypted + copied, + &flushed_at); /* TLS 1.3 may have updated the length by more than overhead */ rxm = strp_msg(darg.skb); @@ -2020,7 +2024,7 @@ put_on_rx_list_err: bool partially_consumed = chunk > len; struct sk_buff *skb = darg.skb; - DEBUG_NET_WARN_ON_ONCE(darg.skb == ctx->recv_pkt); + DEBUG_NET_WARN_ON_ONCE(darg.skb == tls_strp_msg(ctx)); if (async) { /* TLS 1.2-only, to_decrypt must be text len */ @@ -2034,6 +2038,7 @@ put_on_rx_list: } if (bpf_strp_enabled) { + released = true; err = sk_psock_tls_strp_read(psock, skb); if (err != __SK_PASS) { rxm->offset = rxm->offset + rxm->full_len; @@ -2140,7 +2145,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, struct tls_decrypt_arg darg; err = tls_rx_rec_wait(sk, NULL, flags & SPLICE_F_NONBLOCK, - timeo); + true, timeo); if (err <= 0) goto splice_read_end; @@ -2204,19 +2209,17 @@ bool tls_sw_sock_is_readable(struct sock *sk) !skb_queue_empty(&ctx->rx_list); } -static int tls_read_size(struct strparser *strp, struct sk_buff *skb) +int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) { struct tls_context *tls_ctx = tls_get_ctx(strp->sk); struct tls_prot_info *prot = &tls_ctx->prot_info; char header[TLS_HEADER_SIZE + MAX_IV_SIZE]; - struct strp_msg *rxm = strp_msg(skb); - struct tls_msg *tlm = tls_msg(skb); size_t cipher_overhead; size_t data_len = 0; int ret; /* Verify that we have a full TLS header, or wait for more data */ - if (rxm->offset + prot->prepend_size > skb->len) + if (strp->stm.offset + prot->prepend_size > skb->len) return 0; /* Sanity-check size of on-stack buffer. */ @@ -2226,11 +2229,11 @@ static int tls_read_size(struct strparser *strp, struct sk_buff *skb) } /* Linearize header to local buffer */ - ret = skb_copy_bits(skb, rxm->offset, header, prot->prepend_size); + ret = skb_copy_bits(skb, strp->stm.offset, header, prot->prepend_size); if (ret < 0) goto read_failure; - tlm->control = header[0]; + strp->mark = header[0]; data_len = ((header[4] & 0xFF) | (header[3] << 8)); @@ -2257,7 +2260,7 @@ static int tls_read_size(struct strparser *strp, struct sk_buff *skb) } tls_device_rx_resync_new_rec(strp->sk, data_len + TLS_HEADER_SIZE, - TCP_SKB_CB(skb)->seq + rxm->offset); + TCP_SKB_CB(skb)->seq + strp->stm.offset); return data_len + TLS_HEADER_SIZE; read_failure: @@ -2266,14 +2269,11 @@ read_failure: return ret; } -static void tls_queue(struct strparser *strp, struct sk_buff *skb) +void tls_rx_msg_ready(struct tls_strparser *strp) { - struct tls_context *tls_ctx = tls_get_ctx(strp->sk); - struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - - ctx->recv_pkt = skb; - strp_pause(strp); + struct tls_sw_context_rx *ctx; + ctx = container_of(strp, struct tls_sw_context_rx, strp); ctx->saved_data_ready(strp->sk); } @@ -2283,7 +2283,7 @@ static void tls_data_ready(struct sock *sk) struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); struct sk_psock *psock; - strp_data_ready(&ctx->strp); + tls_strp_data_ready(&ctx->strp); psock = sk_psock_get(sk); if (psock) { @@ -2359,13 +2359,11 @@ void tls_sw_release_resources_rx(struct sock *sk) kfree(tls_ctx->rx.iv); if (ctx->aead_recv) { - kfree_skb(ctx->recv_pkt); - ctx->recv_pkt = NULL; __skb_queue_purge(&ctx->rx_list); crypto_free_aead(ctx->aead_recv); - strp_stop(&ctx->strp); + tls_strp_stop(&ctx->strp); /* If tls_sw_strparser_arm() was not called (cleanup paths) - * we still want to strp_stop(), but sk->sk_data_ready was + * we still want to tls_strp_stop(), but sk->sk_data_ready was * never swapped. */ if (ctx->saved_data_ready) { @@ -2380,7 +2378,7 @@ void tls_sw_strparser_done(struct tls_context *tls_ctx) { struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - strp_done(&ctx->strp); + tls_strp_done(&ctx->strp); } void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) @@ -2453,8 +2451,6 @@ void tls_sw_strparser_arm(struct sock *sk, struct tls_context *tls_ctx) rx_ctx->saved_data_ready = sk->sk_data_ready; sk->sk_data_ready = tls_data_ready; write_unlock_bh(&sk->sk_callback_lock); - - strp_check_rcv(&rx_ctx->strp); } void tls_update_rx_zc_capable(struct tls_context *tls_ctx) @@ -2474,7 +2470,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) struct tls_sw_context_rx *sw_ctx_rx = NULL; struct cipher_context *cctx; struct crypto_aead **aead; - struct strp_callbacks cb; u16 nonce_size, tag_size, iv_size, rec_seq_size, salt_size; struct crypto_tfm *tfm; char *iv, *rec_seq, *key, *salt, *cipher_name; @@ -2708,12 +2703,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) crypto_info->version != TLS_1_3_VERSION && !!(tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC); - /* Set up strparser */ - memset(&cb, 0, sizeof(cb)); - cb.rcv_msg = tls_queue; - cb.parse_msg = tls_read_size; - - strp_init(&sw_ctx_rx->strp, sk, &cb); + tls_strp_init(&sw_ctx_rx->strp, sk); } goto out; -- cgit v1.2.3 From 0a2f4f9893c83bd722bd55a903fb682da2eb24ba Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Mon, 25 Jul 2022 16:09:58 +0200 Subject: s390/ism: Cleanups Reworked signature of the function to retrieve the system EID: No plausible reason to use a double pointer. And neither to pass in the device as an argument, as this identifier is by definition per system, not per device. Plus some minor consistency edits. Signed-off-by: Stefan Raspl Signed-off-by: Wenjia Zhang < wenjia@linux.ibm.com> Reviewed-by: Tony Lu Signed-off-by: David S. Miller --- drivers/s390/net/ism_drv.c | 11 +++++------ include/net/smc.h | 2 +- net/smc/smc_ism.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 5f7e28de8b15..4665e9a0e048 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -409,20 +409,19 @@ static void ism_create_system_eid(void) memcpy(&SYSTEM_EID.type, tmp, 4); } -static void ism_get_system_eid(struct smcd_dev *smcd, u8 **eid) +static u8 *ism_get_system_eid(void) { - *eid = &SYSTEM_EID.seid_string[0]; + return SYSTEM_EID.seid_string; } static u16 ism_get_chid(struct smcd_dev *smcd) { - struct ism_dev *ismdev; + struct ism_dev *ism = (struct ism_dev *)smcd->priv; - ismdev = (struct ism_dev *)smcd->priv; - if (!ismdev || !ismdev->pdev) + if (!ism || !ism->pdev) return 0; - return to_zpci(ismdev->pdev)->pchid; + return to_zpci(ism->pdev)->pchid; } static void ism_handle_event(struct ism_dev *ism) diff --git a/include/net/smc.h b/include/net/smc.h index 37f829d9c6e5..1868a5014dea 100644 --- a/include/net/smc.h +++ b/include/net/smc.h @@ -72,7 +72,7 @@ struct smcd_ops { int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx, bool sf, unsigned int offset, void *data, unsigned int size); - void (*get_system_eid)(struct smcd_dev *dev, u8 **eid); + u8* (*get_system_eid)(void); u16 (*get_chid)(struct smcd_dev *dev); }; diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index c656ef25ee4b..e51c0cdff8e0 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -429,7 +429,7 @@ int smcd_register_dev(struct smcd_dev *smcd) if (list_empty(&smcd_dev_list.list)) { u8 *system_eid = NULL; - smcd->ops->get_system_eid(smcd, &system_eid); + system_eid = smcd->ops->get_system_eid(); if (system_eid[24] != '0' || system_eid[28] != '0') { smc_ism_v2_capable = true; memcpy(smc_ism_v2_system_eid, system_eid, -- cgit v1.2.3 From 8b2fed8e2712e8c23665df3c9e0fbabbb76e466c Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Mon, 25 Jul 2022 16:09:59 +0200 Subject: net/smc: Pass on DMBE bit mask in IRQ handler Make the DMBE bits, which are passed on individually in ism_move() as parameter idx, available to the receiver. Signed-off-by: Stefan Raspl Signed-off-by: Wenjia Zhang < wenjia@linux.ibm.com> Reviewed-by: Tony Lu Signed-off-by: David S. Miller --- drivers/s390/net/ism_drv.c | 4 +++- include/net/smc.h | 2 +- net/smc/smc_ism.c | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 4665e9a0e048..d34bb6ec1490 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -443,6 +443,7 @@ static irqreturn_t ism_handle_irq(int irq, void *data) struct ism_dev *ism = data; unsigned long bit, end; unsigned long *bv; + u16 dmbemask; bv = (void *) &ism->sba->dmb_bits[ISM_DMB_WORD_OFFSET]; end = sizeof(ism->sba->dmb_bits) * BITS_PER_BYTE - ISM_DMB_BIT_OFFSET; @@ -456,9 +457,10 @@ static irqreturn_t ism_handle_irq(int irq, void *data) break; clear_bit_inv(bit, bv); + dmbemask = ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET]; ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0; barrier(); - smcd_handle_irq(ism->smcd, bit + ISM_DMB_BIT_OFFSET); + smcd_handle_irq(ism->smcd, bit + ISM_DMB_BIT_OFFSET, dmbemask); } if (ism->sba->e) { diff --git a/include/net/smc.h b/include/net/smc.h index 1868a5014dea..c926d3313e05 100644 --- a/include/net/smc.h +++ b/include/net/smc.h @@ -101,5 +101,5 @@ int smcd_register_dev(struct smcd_dev *smcd); void smcd_unregister_dev(struct smcd_dev *smcd); void smcd_free_dev(struct smcd_dev *smcd); void smcd_handle_event(struct smcd_dev *dev, struct smcd_event *event); -void smcd_handle_irq(struct smcd_dev *dev, unsigned int bit); +void smcd_handle_irq(struct smcd_dev *dev, unsigned int bit, u16 dmbemask); #endif /* _SMC_H */ diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index e51c0cdff8e0..911fe08bc54b 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -508,13 +508,13 @@ void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event) EXPORT_SYMBOL_GPL(smcd_handle_event); /* SMCD Device interrupt handler. Called from ISM device interrupt handler. - * Parameters are smcd device pointer and DMB number. Find the connection and - * schedule the tasklet for this connection. + * Parameters are smcd device pointer, DMB number, and the DMBE bitmask. + * Find the connection and schedule the tasklet for this connection. * * Context: * - Function called in IRQ context from ISM device driver IRQ handler. */ -void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno) +void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno, u16 dmbemask) { struct smc_connection *conn = NULL; unsigned long flags; -- cgit v1.2.3 From 5f10376b6bc1e2773f56977980ab08c9e4fa91a7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 Jul 2022 14:56:52 -0700 Subject: add missing includes and forward declarations to networking includes under linux/ Similarly to a recent include/net/ cleanup, this patch adds missing includes to networking headers under include/linux. All these problems are currently masked by the existing users including the missing dependency before the broken header. Link: https://lore.kernel.org/all/20220723045755.2676857-1-kuba@kernel.org/ v1 Signed-off-by: Jakub Kicinski Link: https://lore.kernel.org/r/20220726215652.158167-1-kuba@kernel.org Signed-off-by: Paolo Abeni --- include/linux/atm_tcp.h | 2 ++ include/linux/dsa/tag_qca.h | 5 +++++ include/linux/hippidevice.h | 4 ++++ include/linux/if_eql.h | 1 + include/linux/if_hsr.h | 4 ++++ include/linux/if_rmnet.h | 2 ++ include/linux/if_tap.h | 11 ++++++----- include/linux/mdio/mdio-xgene.h | 4 ++++ include/linux/nl802154.h | 2 ++ include/linux/phy_fixed.h | 3 +++ include/linux/ppp-comp.h | 2 +- include/linux/ppp_channel.h | 2 ++ include/linux/ptp_kvm.h | 2 ++ include/linux/ptp_pch.h | 4 ++++ include/linux/seq_file_net.h | 1 + include/linux/sungem_phy.h | 2 ++ include/linux/usb/usbnet.h | 6 ++++++ include/net/llc_s_st.h | 6 ++++++ 18 files changed, 57 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/linux/atm_tcp.h b/include/linux/atm_tcp.h index c8ecf6f68fb5..2558439d849b 100644 --- a/include/linux/atm_tcp.h +++ b/include/linux/atm_tcp.h @@ -9,6 +9,8 @@ #include +struct atm_vcc; +struct module; struct atm_tcp_ops { int (*attach)(struct atm_vcc *vcc,int itf); diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h index 4359fb0221cf..50be7cbd93a5 100644 --- a/include/linux/dsa/tag_qca.h +++ b/include/linux/dsa/tag_qca.h @@ -3,6 +3,11 @@ #ifndef __TAG_QCA_H #define __TAG_QCA_H +#include + +struct dsa_switch; +struct sk_buff; + #define QCA_HDR_LEN 2 #define QCA_HDR_VERSION 0x2 diff --git a/include/linux/hippidevice.h b/include/linux/hippidevice.h index 9dc01f7ab5b4..07414c241e65 100644 --- a/include/linux/hippidevice.h +++ b/include/linux/hippidevice.h @@ -23,6 +23,10 @@ #ifdef __KERNEL__ +struct neigh_parms; +struct net_device; +struct sk_buff; + struct hippi_cb { __u32 ifield; }; diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h index d75601d613cc..07f9b660b741 100644 --- a/include/linux/if_eql.h +++ b/include/linux/if_eql.h @@ -21,6 +21,7 @@ #include #include +#include #include typedef struct slave { diff --git a/include/linux/if_hsr.h b/include/linux/if_hsr.h index 408539d5ea5f..0404f5bf4f30 100644 --- a/include/linux/if_hsr.h +++ b/include/linux/if_hsr.h @@ -2,6 +2,10 @@ #ifndef _LINUX_IF_HSR_H_ #define _LINUX_IF_HSR_H_ +#include + +struct net_device; + /* used to differentiate various protocols */ enum hsr_version { HSR_V0 = 0, diff --git a/include/linux/if_rmnet.h b/include/linux/if_rmnet.h index 10e7521ecb6c..839d1e48b85e 100644 --- a/include/linux/if_rmnet.h +++ b/include/linux/if_rmnet.h @@ -5,6 +5,8 @@ #ifndef _LINUX_IF_RMNET_H_ #define _LINUX_IF_RMNET_H_ +#include + struct rmnet_map_header { u8 flags; /* MAP_CMD_FLAG, MAP_PAD_LEN_MASK */ u8 mux_id; diff --git a/include/linux/if_tap.h b/include/linux/if_tap.h index 915a187cfabd..553552fa635c 100644 --- a/include/linux/if_tap.h +++ b/include/linux/if_tap.h @@ -2,14 +2,18 @@ #ifndef _LINUX_IF_TAP_H_ #define _LINUX_IF_TAP_H_ +#include +#include + +struct file; +struct socket; + #if IS_ENABLED(CONFIG_TAP) struct socket *tap_get_socket(struct file *); struct ptr_ring *tap_get_ptr_ring(struct file *file); #else #include #include -struct file; -struct socket; static inline struct socket *tap_get_socket(struct file *f) { return ERR_PTR(-EINVAL); @@ -20,9 +24,6 @@ static inline struct ptr_ring *tap_get_ptr_ring(struct file *f) } #endif /* CONFIG_TAP */ -#include -#include - /* * Maximum times a tap device can be opened. This can be used to * configure the number of receive queue, e.g. for multiqueue virtio. diff --git a/include/linux/mdio/mdio-xgene.h b/include/linux/mdio/mdio-xgene.h index 8af93ada8b64..9e588965dc83 100644 --- a/include/linux/mdio/mdio-xgene.h +++ b/include/linux/mdio/mdio-xgene.h @@ -8,6 +8,10 @@ #ifndef __MDIO_XGENE_H__ #define __MDIO_XGENE_H__ +#include +#include +#include + #define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 #define BLOCK_DIAG_CSR_OFFSET 0xd000 #define XGENET_CONFIG_REG_ADDR 0x20 diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index b22782225f27..cbe5fd1dd2e7 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -8,6 +8,8 @@ #ifndef NL802154_H #define NL802154_H +#include + #define IEEE802154_NL_NAME "802.15.4 MAC" #define IEEE802154_MCAST_COORD_NAME "coordinator" #define IEEE802154_MCAST_BEACON_NAME "beacon" diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h index 52bc8e487ef7..1acafd86ab13 100644 --- a/include/linux/phy_fixed.h +++ b/include/linux/phy_fixed.h @@ -2,6 +2,8 @@ #ifndef __PHY_FIXED_H #define __PHY_FIXED_H +#include + struct fixed_phy_status { int link; int speed; @@ -12,6 +14,7 @@ struct fixed_phy_status { struct device_node; struct gpio_desc; +struct net_device; #if IS_ENABLED(CONFIG_FIXED_PHY) extern int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier); diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h index 9d3ffc8f5ea6..fb847e47f148 100644 --- a/include/linux/ppp-comp.h +++ b/include/linux/ppp-comp.h @@ -9,7 +9,7 @@ #include - +struct compstat; struct module; /* diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h index 91f9a928344e..45e6e427ceb8 100644 --- a/include/linux/ppp_channel.h +++ b/include/linux/ppp_channel.h @@ -20,6 +20,8 @@ #include #include +struct net_device_path; +struct net_device_path_ctx; struct ppp_channel; struct ppp_channel_ops { diff --git a/include/linux/ptp_kvm.h b/include/linux/ptp_kvm.h index f960a719f0d5..c2e28deef33a 100644 --- a/include/linux/ptp_kvm.h +++ b/include/linux/ptp_kvm.h @@ -8,6 +8,8 @@ #ifndef _PTP_KVM_H_ #define _PTP_KVM_H_ +#include + struct timespec64; struct clocksource; diff --git a/include/linux/ptp_pch.h b/include/linux/ptp_pch.h index 51818198c292..7ba643b62c15 100644 --- a/include/linux/ptp_pch.h +++ b/include/linux/ptp_pch.h @@ -10,6 +10,10 @@ #ifndef _PTP_PCH_H_ #define _PTP_PCH_H_ +#include + +struct pci_dev; + void pch_ch_control_write(struct pci_dev *pdev, u32 val); u32 pch_ch_event_read(struct pci_dev *pdev); void pch_ch_event_write(struct pci_dev *pdev, u32 val); diff --git a/include/linux/seq_file_net.h b/include/linux/seq_file_net.h index b97912fdbae7..79638395bc32 100644 --- a/include/linux/seq_file_net.h +++ b/include/linux/seq_file_net.h @@ -3,6 +3,7 @@ #define __SEQ_FILE_NET_H__ #include +#include struct net; extern struct net init_net; diff --git a/include/linux/sungem_phy.h b/include/linux/sungem_phy.h index 3a11fa41a131..c505f30e8b68 100644 --- a/include/linux/sungem_phy.h +++ b/include/linux/sungem_phy.h @@ -2,6 +2,8 @@ #ifndef __SUNGEM_PHY_H__ #define __SUNGEM_PHY_H__ +#include + struct mii_phy; /* Operations supported by any kind of PHY */ diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 1b4d72d5e891..b42b72391a8d 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -23,6 +23,12 @@ #ifndef __LINUX_USB_USBNET_H #define __LINUX_USB_USBNET_H +#include +#include +#include +#include +#include + /* interface from usbnet core to each USB networking link we handle */ struct usbnet { /* housekeeping */ diff --git a/include/net/llc_s_st.h b/include/net/llc_s_st.h index c4359e203013..ed5b2fa40d32 100644 --- a/include/net/llc_s_st.h +++ b/include/net/llc_s_st.h @@ -12,6 +12,12 @@ * See the GNU General Public License for more details. */ +#include +#include +#include + +struct llc_sap_state_trans; + #define LLC_NR_SAP_STATES 2 /* size of state table */ /* structures and types */ -- cgit v1.2.3 From 7adc91e0c93901a0eeeea10665d0feb48ffde2d4 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 27 Jul 2022 12:43:42 +0300 Subject: net/tls: Multi-threaded calls to TX tls_dev_del Multiple TLS device-offloaded contexts can be added in parallel via concurrent calls to .tls_dev_add, while calls to .tls_dev_del are sequential in tls_device_gc_task. This is not a sustainable behavior. This creates a rate gap between add and del operations (addition rate outperforms the deletion rate). When running for enough time, the TLS device resources could get exhausted, failing to offload new connections. Replace the single-threaded garbage collector work with a per-context alternative, so they can be handled on several cores in parallel. Use a new dedicated destruct workqueue for this. Tested with mlx5 device: Before: 22141 add/sec, 103 del/sec After: 11684 add/sec, 11684 del/sec Signed-off-by: Tariq Toukan Reviewed-by: Maxim Mikityanskiy Signed-off-by: Saeed Mahameed Signed-off-by: Jakub Kicinski --- include/net/tls.h | 2 ++ net/tls/tls_device.c | 63 ++++++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 32 deletions(-) (limited to 'include/net') diff --git a/include/net/tls.h b/include/net/tls.h index abb050b0df83..b75b5727abdb 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -161,6 +161,8 @@ struct tls_offload_context_tx { struct scatterlist sg_tx_data[MAX_SKB_FRAGS]; void (*sk_destruct)(struct sock *sk); + struct work_struct destruct_work; + struct tls_context *ctx; u8 driver_state[] __aligned(8); /* The TLS layer reserves room for driver specific state * Currently the belief is that there is not enough diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 5150b3939b1f..18c7e5c6d228 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -46,10 +46,8 @@ */ static DECLARE_RWSEM(device_offload_lock); -static void tls_device_gc_task(struct work_struct *work); +static struct workqueue_struct *destruct_wq __read_mostly; -static DECLARE_WORK(tls_device_gc_work, tls_device_gc_task); -static LIST_HEAD(tls_device_gc_list); static LIST_HEAD(tls_device_list); static LIST_HEAD(tls_device_down_list); static DEFINE_SPINLOCK(tls_device_lock); @@ -68,29 +66,17 @@ static void tls_device_free_ctx(struct tls_context *ctx) tls_ctx_free(NULL, ctx); } -static void tls_device_gc_task(struct work_struct *work) +static void tls_device_tx_del_task(struct work_struct *work) { - struct tls_context *ctx, *tmp; - unsigned long flags; - LIST_HEAD(gc_list); - - spin_lock_irqsave(&tls_device_lock, flags); - list_splice_init(&tls_device_gc_list, &gc_list); - spin_unlock_irqrestore(&tls_device_lock, flags); - - list_for_each_entry_safe(ctx, tmp, &gc_list, list) { - struct net_device *netdev = ctx->netdev; + struct tls_offload_context_tx *offload_ctx = + container_of(work, struct tls_offload_context_tx, destruct_work); + struct tls_context *ctx = offload_ctx->ctx; + struct net_device *netdev = ctx->netdev; - if (netdev && ctx->tx_conf == TLS_HW) { - netdev->tlsdev_ops->tls_dev_del(netdev, ctx, - TLS_OFFLOAD_CTX_DIR_TX); - dev_put(netdev); - ctx->netdev = NULL; - } - - list_del(&ctx->list); - tls_device_free_ctx(ctx); - } + netdev->tlsdev_ops->tls_dev_del(netdev, ctx, TLS_OFFLOAD_CTX_DIR_TX); + dev_put(netdev); + ctx->netdev = NULL; + tls_device_free_ctx(ctx); } static void tls_device_queue_ctx_destruction(struct tls_context *ctx) @@ -104,16 +90,15 @@ static void tls_device_queue_ctx_destruction(struct tls_context *ctx) return; } + list_del(&ctx->list); /* Remove from tls_device_list / tls_device_down_list */ async_cleanup = ctx->netdev && ctx->tx_conf == TLS_HW; if (async_cleanup) { - list_move_tail(&ctx->list, &tls_device_gc_list); + struct tls_offload_context_tx *offload_ctx = tls_offload_ctx_tx(ctx); - /* schedule_work inside the spinlock + /* queue_work inside the spinlock * to make sure tls_device_down waits for that work. */ - schedule_work(&tls_device_gc_work); - } else { - list_del(&ctx->list); + queue_work(destruct_wq, &offload_ctx->destruct_work); } spin_unlock_irqrestore(&tls_device_lock, flags); @@ -1160,6 +1145,9 @@ int tls_set_device_offload(struct sock *sk, struct tls_context *ctx) start_marker_record->len = 0; start_marker_record->num_frags = 0; + INIT_WORK(&offload_ctx->destruct_work, tls_device_tx_del_task); + offload_ctx->ctx = ctx; + INIT_LIST_HEAD(&offload_ctx->records_list); list_add_tail(&start_marker_record->list, &offload_ctx->records_list); spin_lock_init(&offload_ctx->lock); @@ -1404,7 +1392,7 @@ static int tls_device_down(struct net_device *netdev) up_write(&device_offload_lock); - flush_work(&tls_device_gc_work); + flush_workqueue(destruct_wq); return NOTIFY_DONE; } @@ -1445,12 +1433,23 @@ static struct notifier_block tls_dev_notifier = { int __init tls_device_init(void) { - return register_netdevice_notifier(&tls_dev_notifier); + int err; + + destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0); + if (!destruct_wq) + return -ENOMEM; + + err = register_netdevice_notifier(&tls_dev_notifier); + if (err) + destroy_workqueue(destruct_wq); + + return err; } void __exit tls_device_cleanup(void) { unregister_netdevice_notifier(&tls_dev_notifier); - flush_work(&tls_device_gc_work); + flush_workqueue(destruct_wq); + destroy_workqueue(destruct_wq); clean_acked_data_flush(); } -- cgit v1.2.3 From 08f588fa301bef264576fc915da6bf31b585a824 Mon Sep 17 00:00:00 2001 From: Vikas Gupta Date: Wed, 27 Jul 2022 22:27:20 +0530 Subject: devlink: introduce framework for selftests Add a framework for running selftests. Framework exposes devlink commands and test suite(s) to the user to execute and query the supported tests by the driver. Below are new entries in devlink_nl_ops devlink_nl_cmd_selftests_show_doit/dumpit: To query the supported selftests by the drivers. devlink_nl_cmd_selftests_run: To execute selftests. Users can provide a test mask for executing group tests or standalone tests. Documentation/networking/devlink/ path is already part of MAINTAINERS & the new files come under this path. Hence no update needed to the MAINTAINERS Signed-off-by: Vikas Gupta Reviewed-by: Andy Gospodarek Reviewed-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- .../networking/devlink/devlink-selftests.rst | 38 ++++ include/net/devlink.h | 21 ++ include/uapi/linux/devlink.h | 29 +++ net/core/devlink.c | 216 +++++++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 Documentation/networking/devlink/devlink-selftests.rst (limited to 'include/net') diff --git a/Documentation/networking/devlink/devlink-selftests.rst b/Documentation/networking/devlink/devlink-selftests.rst new file mode 100644 index 000000000000..c0aa1f3aef0d --- /dev/null +++ b/Documentation/networking/devlink/devlink-selftests.rst @@ -0,0 +1,38 @@ +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +================= +Devlink Selftests +================= + +The ``devlink-selftests`` API allows executing selftests on the device. + +Tests Mask +========== +The ``devlink-selftests`` command should be run with a mask indicating +the tests to be executed. + +Tests Description +================= +The following is a list of tests that drivers may execute. + +.. list-table:: List of tests + :widths: 5 90 + + * - Name + - Description + * - ``DEVLINK_SELFTEST_FLASH`` + - Devices may have the firmware on non-volatile memory on the board, e.g. + flash. This particular test helps to run a flash selftest on the device. + Implementation of the test is left to the driver/firmware. + +example usage +------------- + +.. code:: shell + + # Query selftests supported on the devlink device + $ devlink dev selftests show DEV + # Query selftests supported on all devlink devices + $ devlink dev selftests show + # Executes selftests on the device + $ devlink dev selftests run DEV id flash diff --git a/include/net/devlink.h b/include/net/devlink.h index 5bd3fac12e9e..119ed1ffb988 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1509,6 +1509,27 @@ struct devlink_ops { struct devlink_rate *parent, void *priv_child, void *priv_parent, struct netlink_ext_ack *extack); + /** + * selftests_check() - queries if selftest is supported + * @devlink: devlink instance + * @id: test index + * @extack: extack for reporting error messages + * + * Return: true if test is supported by the driver + */ + bool (*selftest_check)(struct devlink *devlink, unsigned int id, + struct netlink_ext_ack *extack); + /** + * selftest_run() - Runs a selftest + * @devlink: devlink instance + * @id: test index + * @extack: extack for reporting error messages + * + * Return: status of the test + */ + enum devlink_selftest_status + (*selftest_run)(struct devlink *devlink, unsigned int id, + struct netlink_ext_ack *extack); }; void *devlink_priv(struct devlink *devlink); diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 541321695f52..2f24b53a87a5 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -136,6 +136,9 @@ enum devlink_command { DEVLINK_CMD_LINECARD_NEW, DEVLINK_CMD_LINECARD_DEL, + DEVLINK_CMD_SELFTESTS_GET, /* can dump */ + DEVLINK_CMD_SELFTESTS_RUN, + /* add new commands above here */ __DEVLINK_CMD_MAX, DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 @@ -276,6 +279,30 @@ enum { #define DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS \ (_BITUL(__DEVLINK_FLASH_OVERWRITE_MAX_BIT) - 1) +enum devlink_attr_selftest_id { + DEVLINK_ATTR_SELFTEST_ID_UNSPEC, + DEVLINK_ATTR_SELFTEST_ID_FLASH, /* flag */ + + __DEVLINK_ATTR_SELFTEST_ID_MAX, + DEVLINK_ATTR_SELFTEST_ID_MAX = __DEVLINK_ATTR_SELFTEST_ID_MAX - 1 +}; + +enum devlink_selftest_status { + DEVLINK_SELFTEST_STATUS_SKIP, + DEVLINK_SELFTEST_STATUS_PASS, + DEVLINK_SELFTEST_STATUS_FAIL +}; + +enum devlink_attr_selftest_result { + DEVLINK_ATTR_SELFTEST_RESULT_UNSPEC, + DEVLINK_ATTR_SELFTEST_RESULT, /* nested */ + DEVLINK_ATTR_SELFTEST_RESULT_ID, /* u32, enum devlink_attr_selftest_id */ + DEVLINK_ATTR_SELFTEST_RESULT_STATUS, /* u8, enum devlink_selftest_status */ + + __DEVLINK_ATTR_SELFTEST_RESULT_MAX, + DEVLINK_ATTR_SELFTEST_RESULT_MAX = __DEVLINK_ATTR_SELFTEST_RESULT_MAX - 1 +}; + /** * enum devlink_trap_action - Packet trap action. * @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not @@ -578,6 +605,8 @@ enum devlink_attr { DEVLINK_ATTR_NESTED_DEVLINK, /* nested */ + DEVLINK_ATTR_SELFTESTS, /* nested */ + /* add new attributes above here, update the policy in devlink.c */ __DEVLINK_ATTR_MAX, diff --git a/net/core/devlink.c b/net/core/devlink.c index ca4c9939d569..efeba223b9b8 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -201,6 +201,10 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ DEVLINK_PORT_FN_STATE_ACTIVE), }; +static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { + [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG }, +}; + static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); #define DEVLINK_REGISTERED XA_MARK_1 @@ -4826,6 +4830,206 @@ static int devlink_nl_cmd_flash_update(struct sk_buff *skb, return ret; } +static int +devlink_nl_selftests_fill(struct sk_buff *msg, struct devlink *devlink, + u32 portid, u32 seq, int flags, + struct netlink_ext_ack *extack) +{ + struct nlattr *selftests; + void *hdr; + int err; + int i; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, + DEVLINK_CMD_SELFTESTS_GET); + if (!hdr) + return -EMSGSIZE; + + err = -EMSGSIZE; + if (devlink_nl_put_handle(msg, devlink)) + goto err_cancel_msg; + + selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); + if (!selftests) + goto err_cancel_msg; + + for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; + i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { + if (devlink->ops->selftest_check(devlink, i, extack)) { + err = nla_put_flag(msg, i); + if (err) + goto err_cancel_msg; + } + } + + nla_nest_end(msg, selftests); + genlmsg_end(msg, hdr); + return 0; + +err_cancel_msg: + genlmsg_cancel(msg, hdr); + return err; +} + +static int devlink_nl_cmd_selftests_get_doit(struct sk_buff *skb, + struct genl_info *info) +{ + struct devlink *devlink = info->user_ptr[0]; + struct sk_buff *msg; + int err; + + if (!devlink->ops->selftest_check) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + err = devlink_nl_selftests_fill(msg, devlink, info->snd_portid, + info->snd_seq, 0, info->extack); + if (err) { + nlmsg_free(msg); + return err; + } + + return genlmsg_reply(msg, info); +} + +static int devlink_nl_cmd_selftests_get_dumpit(struct sk_buff *msg, + struct netlink_callback *cb) +{ + struct devlink *devlink; + int start = cb->args[0]; + unsigned long index; + int idx = 0; + int err = 0; + + mutex_lock(&devlink_mutex); + devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) { + if (idx < start || !devlink->ops->selftest_check) + goto inc; + + devl_lock(devlink); + err = devlink_nl_selftests_fill(msg, devlink, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + cb->extack); + devl_unlock(devlink); + if (err) { + devlink_put(devlink); + break; + } +inc: + idx++; + devlink_put(devlink); + } + mutex_unlock(&devlink_mutex); + + if (err != -EMSGSIZE) + return err; + + cb->args[0] = idx; + return msg->len; +} + +static int devlink_selftest_result_put(struct sk_buff *skb, unsigned int id, + enum devlink_selftest_status test_status) +{ + struct nlattr *result_attr; + + result_attr = nla_nest_start(skb, DEVLINK_ATTR_SELFTEST_RESULT); + if (!result_attr) + return -EMSGSIZE; + + if (nla_put_u32(skb, DEVLINK_ATTR_SELFTEST_RESULT_ID, id) || + nla_put_u8(skb, DEVLINK_ATTR_SELFTEST_RESULT_STATUS, + test_status)) + goto nla_put_failure; + + nla_nest_end(skb, result_attr); + return 0; + +nla_put_failure: + nla_nest_cancel(skb, result_attr); + return -EMSGSIZE; +} + +static int devlink_nl_cmd_selftests_run(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1]; + struct devlink *devlink = info->user_ptr[0]; + struct nlattr *attrs, *selftests; + struct sk_buff *msg; + void *hdr; + int err; + int i; + + if (!devlink->ops->selftest_run || !devlink->ops->selftest_check) + return -EOPNOTSUPP; + + if (!info->attrs[DEVLINK_ATTR_SELFTESTS]) { + NL_SET_ERR_MSG_MOD(info->extack, "selftest required"); + return -EINVAL; + } + + attrs = info->attrs[DEVLINK_ATTR_SELFTESTS]; + + err = nla_parse_nested(tb, DEVLINK_ATTR_SELFTEST_ID_MAX, attrs, + devlink_selftest_nl_policy, info->extack); + if (err < 0) + return err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + err = -EMSGSIZE; + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, + &devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN); + if (!hdr) + goto free_msg; + + if (devlink_nl_put_handle(msg, devlink)) + goto genlmsg_cancel; + + selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); + if (!selftests) + goto genlmsg_cancel; + + for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; + i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { + enum devlink_selftest_status test_status; + + if (nla_get_flag(tb[i])) { + if (!devlink->ops->selftest_check(devlink, i, + info->extack)) { + if (devlink_selftest_result_put(msg, i, + DEVLINK_SELFTEST_STATUS_SKIP)) + goto selftests_nest_cancel; + continue; + } + + test_status = devlink->ops->selftest_run(devlink, i, + info->extack); + if (devlink_selftest_result_put(msg, i, test_status)) + goto selftests_nest_cancel; + } + } + + nla_nest_end(msg, selftests); + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + +selftests_nest_cancel: + nla_nest_cancel(msg, selftests); +genlmsg_cancel: + genlmsg_cancel(msg, hdr); +free_msg: + nlmsg_free(msg); + return err; +} + static const struct devlink_param devlink_param_generic[] = { { .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET, @@ -8969,6 +9173,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING }, + [DEVLINK_ATTR_SELFTESTS] = { .type = NLA_NESTED }, }; static const struct genl_small_ops devlink_nl_ops[] = { @@ -9328,6 +9533,17 @@ static const struct genl_small_ops devlink_nl_ops[] = { .doit = devlink_nl_cmd_trap_policer_set_doit, .flags = GENL_ADMIN_PERM, }, + { + .cmd = DEVLINK_CMD_SELFTESTS_GET, + .doit = devlink_nl_cmd_selftests_get_doit, + .dumpit = devlink_nl_cmd_selftests_get_dumpit + /* can be retrieved by unprivileged users */ + }, + { + .cmd = DEVLINK_CMD_SELFTESTS_RUN, + .doit = devlink_nl_cmd_selftests_run, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family devlink_nl_family __ro_after_init = { -- cgit v1.2.3 From d7c4c9e075f8cc6d88d277bc24e5d99297f03c06 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Jul 2022 22:18:21 -0700 Subject: ax25: fix incorrect dev_tracker usage While investigating a separate rose issue [1], and enabling CONFIG_NET_DEV_REFCNT_TRACKER=y, Bernard reported an orthogonal ax25 issue [2] An ax25_dev can be used by one (or many) struct ax25_cb. We thus need different dev_tracker, one per struct ax25_cb. After this patch is applied, we are able to focus on rose. [1] https://lore.kernel.org/netdev/fb7544a1-f42e-9254-18cc-c9b071f4ca70@free.fr/ [2] [ 205.798723] reference already released. [ 205.798732] allocated in: [ 205.798734] ax25_bind+0x1a2/0x230 [ax25] [ 205.798747] __sys_bind+0xea/0x110 [ 205.798753] __x64_sys_bind+0x18/0x20 [ 205.798758] do_syscall_64+0x5c/0x80 [ 205.798763] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 205.798768] freed in: [ 205.798770] ax25_release+0x115/0x370 [ax25] [ 205.798778] __sock_release+0x42/0xb0 [ 205.798782] sock_close+0x15/0x20 [ 205.798785] __fput+0x9f/0x260 [ 205.798789] ____fput+0xe/0x10 [ 205.798792] task_work_run+0x64/0xa0 [ 205.798798] exit_to_user_mode_prepare+0x18b/0x190 [ 205.798804] syscall_exit_to_user_mode+0x26/0x40 [ 205.798808] do_syscall_64+0x69/0x80 [ 205.798812] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 205.798827] ------------[ cut here ]------------ [ 205.798829] WARNING: CPU: 2 PID: 2605 at lib/ref_tracker.c:136 ref_tracker_free.cold+0x60/0x81 [ 205.798837] Modules linked in: rose netrom mkiss ax25 rfcomm cmac algif_hash algif_skcipher af_alg bnep snd_hda_codec_hdmi nls_iso8859_1 i915 rtw88_8821ce rtw88_8821c x86_pkg_temp_thermal rtw88_pci intel_powerclamp rtw88_core snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio coretemp snd_hda_intel kvm_intel snd_intel_dspcfg mac80211 snd_hda_codec kvm i2c_algo_bit drm_buddy drm_dp_helper btusb drm_kms_helper snd_hwdep btrtl snd_hda_core btbcm joydev crct10dif_pclmul btintel crc32_pclmul ghash_clmulni_intel mei_hdcp btmtk intel_rapl_msr aesni_intel bluetooth input_leds snd_pcm crypto_simd syscopyarea processor_thermal_device_pci_legacy sysfillrect cryptd intel_soc_dts_iosf snd_seq sysimgblt ecdh_generic fb_sys_fops rapl libarc4 processor_thermal_device intel_cstate processor_thermal_rfim cec snd_timer ecc snd_seq_device cfg80211 processor_thermal_mbox mei_me processor_thermal_rapl mei rc_core at24 snd intel_pch_thermal intel_rapl_common ttm soundcore int340x_thermal_zone video [ 205.798948] mac_hid acpi_pad sch_fq_codel ipmi_devintf ipmi_msghandler drm msr parport_pc ppdev lp parport ramoops pstore_blk reed_solomon pstore_zone efi_pstore ip_tables x_tables autofs4 hid_generic usbhid hid i2c_i801 i2c_smbus r8169 xhci_pci ahci libahci realtek lpc_ich xhci_pci_renesas [last unloaded: ax25] [ 205.798992] CPU: 2 PID: 2605 Comm: ax25ipd Not tainted 5.18.11-F6BVP #3 [ 205.798996] Hardware name: To be filled by O.E.M. To be filled by O.E.M./CK3, BIOS 5.011 09/16/2020 [ 205.798999] RIP: 0010:ref_tracker_free.cold+0x60/0x81 [ 205.799005] Code: e8 d2 01 9b ff 83 7b 18 00 74 14 48 c7 c7 2f d7 ff 98 e8 10 6e fc ff 8b 7b 18 e8 b8 01 9b ff 4c 89 ee 4c 89 e7 e8 5d fd 07 00 <0f> 0b b8 ea ff ff ff e9 30 05 9b ff 41 0f b6 f7 48 c7 c7 a0 fa 4e [ 205.799008] RSP: 0018:ffffaf5281073958 EFLAGS: 00010286 [ 205.799011] RAX: 0000000080000000 RBX: ffff9a0bd687ebe0 RCX: 0000000000000000 [ 205.799014] RDX: 0000000000000001 RSI: 0000000000000282 RDI: 00000000ffffffff [ 205.799016] RBP: ffffaf5281073a10 R08: 0000000000000003 R09: fffffffffffd5618 [ 205.799019] R10: 0000000000ffff10 R11: 000000000000000f R12: ffff9a0bc53384d0 [ 205.799022] R13: 0000000000000282 R14: 00000000ae000001 R15: 0000000000000001 [ 205.799024] FS: 0000000000000000(0000) GS:ffff9a0d0f300000(0000) knlGS:0000000000000000 [ 205.799028] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 205.799031] CR2: 00007ff6b8311554 CR3: 000000001ac10004 CR4: 00000000001706e0 [ 205.799033] Call Trace: [ 205.799035] [ 205.799038] ? ax25_dev_device_down+0xd9/0x1b0 [ax25] [ 205.799047] ? ax25_device_event+0x9f/0x270 [ax25] [ 205.799055] ? raw_notifier_call_chain+0x49/0x60 [ 205.799060] ? call_netdevice_notifiers_info+0x52/0xa0 [ 205.799065] ? dev_close_many+0xc8/0x120 [ 205.799070] ? unregister_netdevice_many+0x13d/0x890 [ 205.799073] ? unregister_netdevice_queue+0x90/0xe0 [ 205.799076] ? unregister_netdev+0x1d/0x30 [ 205.799080] ? mkiss_close+0x7c/0xc0 [mkiss] [ 205.799084] ? tty_ldisc_close+0x2e/0x40 [ 205.799089] ? tty_ldisc_hangup+0x137/0x210 [ 205.799092] ? __tty_hangup.part.0+0x208/0x350 [ 205.799098] ? tty_vhangup+0x15/0x20 [ 205.799103] ? pty_close+0x127/0x160 [ 205.799108] ? tty_release+0x139/0x5e0 [ 205.799112] ? __fput+0x9f/0x260 [ 205.799118] ax25_dev_device_down+0xd9/0x1b0 [ax25] [ 205.799126] ax25_device_event+0x9f/0x270 [ax25] [ 205.799135] raw_notifier_call_chain+0x49/0x60 [ 205.799140] call_netdevice_notifiers_info+0x52/0xa0 [ 205.799146] dev_close_many+0xc8/0x120 [ 205.799152] unregister_netdevice_many+0x13d/0x890 [ 205.799157] unregister_netdevice_queue+0x90/0xe0 [ 205.799161] unregister_netdev+0x1d/0x30 [ 205.799165] mkiss_close+0x7c/0xc0 [mkiss] [ 205.799170] tty_ldisc_close+0x2e/0x40 [ 205.799173] tty_ldisc_hangup+0x137/0x210 [ 205.799178] __tty_hangup.part.0+0x208/0x350 [ 205.799184] tty_vhangup+0x15/0x20 [ 205.799188] pty_close+0x127/0x160 [ 205.799193] tty_release+0x139/0x5e0 [ 205.799199] __fput+0x9f/0x260 [ 205.799203] ____fput+0xe/0x10 [ 205.799208] task_work_run+0x64/0xa0 [ 205.799213] do_exit+0x33b/0xab0 [ 205.799217] ? __handle_mm_fault+0xc4f/0x15f0 [ 205.799224] do_group_exit+0x35/0xa0 [ 205.799228] __x64_sys_exit_group+0x18/0x20 [ 205.799232] do_syscall_64+0x5c/0x80 [ 205.799238] ? handle_mm_fault+0xba/0x290 [ 205.799242] ? debug_smp_processor_id+0x17/0x20 [ 205.799246] ? fpregs_assert_state_consistent+0x26/0x50 [ 205.799251] ? exit_to_user_mode_prepare+0x49/0x190 [ 205.799256] ? irqentry_exit_to_user_mode+0x9/0x20 [ 205.799260] ? irqentry_exit+0x33/0x40 [ 205.799263] ? exc_page_fault+0x87/0x170 [ 205.799268] ? asm_exc_page_fault+0x8/0x30 [ 205.799273] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 205.799277] RIP: 0033:0x7ff6b80eaca1 [ 205.799281] Code: Unable to access opcode bytes at RIP 0x7ff6b80eac77. [ 205.799283] RSP: 002b:00007fff6dfd4738 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 [ 205.799287] RAX: ffffffffffffffda RBX: 00007ff6b8215a00 RCX: 00007ff6b80eaca1 [ 205.799290] RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000001 [ 205.799293] RBP: 0000000000000001 R08: ffffffffffffff80 R09: 0000000000000028 [ 205.799295] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ff6b8215a00 [ 205.799298] R13: 0000000000000000 R14: 00007ff6b821aee8 R15: 00007ff6b821af00 [ 205.799304] Fixes: feef318c855a ("ax25: fix UAF bugs of net_device caused by rebinding operation") Reported-by: Bernard F6BVP Signed-off-by: Eric Dumazet Cc: Duoming Zhou Link: https://lore.kernel.org/r/20220728051821.3160118-1-eric.dumazet@gmail.com Signed-off-by: Jakub Kicinski --- include/net/ax25.h | 1 + net/ax25/af_ax25.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/ax25.h b/include/net/ax25.h index a427a05672e2..f8cf3629a419 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -236,6 +236,7 @@ typedef struct ax25_cb { ax25_address source_addr, dest_addr; ax25_digi *digipeat; ax25_dev *ax25_dev; + netdevice_tracker dev_tracker; unsigned char iamdigi; unsigned char state, modulus, pidincl; unsigned short vs, vr, va; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 4c7030ed8d33..5b5363c99ed5 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1065,7 +1065,7 @@ static int ax25_release(struct socket *sock) del_timer_sync(&ax25->t3timer); del_timer_sync(&ax25->idletimer); } - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + dev_put_track(ax25_dev->dev, &ax25->dev_tracker); ax25_dev_put(ax25_dev); } @@ -1146,7 +1146,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (ax25_dev) { ax25_fillin_cb(ax25, ax25_dev); - dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC); + dev_hold_track(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC); } done: -- cgit v1.2.3 From 29192a170e1579ac8293d00c88d9938c2b2f5aab Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Jul 2022 17:49:06 +0300 Subject: firewire: net: Make use of get_unaligned_be48(), put_unaligned_be48() Since we have a proper endianness converters for BE 48-bit data use them. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220726144906.5217-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jakub Kicinski --- drivers/firewire/net.c | 14 ++------------ include/net/firewire.h | 3 +-- 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'include/net') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index dcc141068128..af22be84034b 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -201,15 +201,6 @@ struct fwnet_packet_task { u8 enqueued; }; -/* - * Get fifo address embedded in hwaddr - */ -static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha) -{ - return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32 - | get_unaligned_be32(&ha->uc.fifo_lo); -} - /* * saddr == NULL means use device source address. * daddr == NULL means leave destination address (eg unresolved arp). @@ -1306,7 +1297,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) max_payload = peer->max_payload; datagram_label_ptr = &peer->datagram_label; - ptask->fifo_addr = fwnet_hwaddr_fifo(ha); + ptask->fifo_addr = get_unaligned_be48(ha->uc.fifo); ptask->generation = generation; ptask->dest_node = dest_node; ptask->speed = peer->speed; @@ -1494,8 +1485,7 @@ static int fwnet_probe(struct fw_unit *unit, ha.uc.uniq_id = cpu_to_be64(card->guid); ha.uc.max_rec = dev->card->max_receive; ha.uc.sspd = dev->card->link_speed; - ha.uc.fifo_hi = cpu_to_be16(dev->local_fifo >> 32); - ha.uc.fifo_lo = cpu_to_be32(dev->local_fifo & 0xffffffff); + put_unaligned_be48(dev->local_fifo, ha.uc.fifo); dev_addr_set(net, ha.u); memset(net->broadcast, -1, net->addr_len); diff --git a/include/net/firewire.h b/include/net/firewire.h index 2442d645e412..8fbff8d77865 100644 --- a/include/net/firewire.h +++ b/include/net/firewire.h @@ -13,8 +13,7 @@ union fwnet_hwaddr { __be64 uniq_id; /* EUI-64 */ u8 max_rec; /* max packet size */ u8 sspd; /* max speed */ - __be16 fifo_hi; /* hi 16bits of FIFO addr */ - __be32 fifo_lo; /* lo 32bits of FIFO addr */ + u8 fifo[6]; /* FIFO addr */ } __packed uc; }; -- cgit v1.2.3 From 944fd1aeacb627fa617f85f8e5a34f7ae8ea4d8e Mon Sep 17 00:00:00 2001 From: Mike Manning Date: Mon, 25 Jul 2022 19:14:42 +0100 Subject: net: allow unbound socket for packets in VRF when tcp_l3mdev_accept set The commit 3c82a21f4320 ("net: allow binding socket in a VRF when there's an unbound socket") changed the inet socket lookup to avoid packets in a VRF from matching an unbound socket. This is to ensure the necessary isolation between the default and other VRFs for routing and forwarding. VRF-unaware processes running in the default VRF cannot access another VRF and have to be run with 'ip vrf exec '. This is to be expected with tcp_l3mdev_accept disabled, but could be reallowed when this sysctl option is enabled. So instead of directly checking dif and sdif in inet[6]_match, here call inet_sk_bound_dev_eq(). This allows a match on unbound socket for non-zero sdif i.e. for packets in a VRF, if tcp_l3mdev_accept is enabled. Fixes: 3c82a21f4320 ("net: allow binding socket in a VRF when there's an unbound socket") Signed-off-by: Mike Manning Link: https://lore.kernel.org/netdev/a54c149aed38fded2d3b5fdb1a6c89e36a083b74.camel@lasnet.de/ Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/inet6_hashtables.h | 7 +++---- include/net/inet_hashtables.h | 19 +++---------------- include/net/inet_sock.h | 11 +++++++++++ 3 files changed, 17 insertions(+), 20 deletions(-) (limited to 'include/net') diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index f259e1ae14ba..56f1286583d3 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -110,8 +110,6 @@ static inline bool inet6_match(struct net *net, const struct sock *sk, const __portpair ports, const int dif, const int sdif) { - int bound_dev_if; - if (!net_eq(sock_net(sk), net) || sk->sk_family != AF_INET6 || sk->sk_portpair != ports || @@ -119,8 +117,9 @@ static inline bool inet6_match(struct net *net, const struct sock *sk, !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) return false; - bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); - return bound_dev_if == dif || bound_dev_if == sdif; + /* READ_ONCE() paired with WRITE_ONCE() in sock_bindtoindex_locked() */ + return inet_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif, + sdif); } #endif /* IS_ENABLED(CONFIG_IPV6) */ diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index fd6b510d114b..e9cf2157ed8a 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -175,17 +175,6 @@ static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo) hashinfo->ehash_locks = NULL; } -static inline bool inet_sk_bound_dev_eq(struct net *net, int bound_dev_if, - int dif, int sdif) -{ -#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) - return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept), - bound_dev_if, dif, sdif); -#else - return inet_bound_dev_eq(true, bound_dev_if, dif, sdif); -#endif -} - struct inet_bind_bucket * inet_bind_bucket_create(struct kmem_cache *cachep, struct net *net, struct inet_bind_hashbucket *head, @@ -271,16 +260,14 @@ static inline bool inet_match(struct net *net, const struct sock *sk, const __addrpair cookie, const __portpair ports, int dif, int sdif) { - int bound_dev_if; - if (!net_eq(sock_net(sk), net) || sk->sk_portpair != ports || sk->sk_addrpair != cookie) return false; - /* Paired with WRITE_ONCE() from sock_bindtoindex_locked() */ - bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); - return bound_dev_if == dif || bound_dev_if == sdif; + /* READ_ONCE() paired with WRITE_ONCE() in sock_bindtoindex_locked() */ + return inet_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif, + sdif); } /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 6395f6b9a5d2..bf5654ce711e 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -149,6 +149,17 @@ static inline bool inet_bound_dev_eq(bool l3mdev_accept, int bound_dev_if, return bound_dev_if == dif || bound_dev_if == sdif; } +static inline bool inet_sk_bound_dev_eq(struct net *net, int bound_dev_if, + int dif, int sdif) +{ +#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) + return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept), + bound_dev_if, dif, sdif); +#else + return inet_bound_dev_eq(true, bound_dev_if, dif, sdif); +#endif +} + struct inet_cork { unsigned int flags; __be32 addr; -- cgit v1.2.3 From 2df91e397d85cd4c5206ab48d4e398e338db02d7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Jul 2022 09:12:33 +0000 Subject: net: rose: add netdev ref tracker to 'struct rose_sock' This will help debugging netdevice refcount problems with CONFIG_NET_DEV_REFCNT_TRACKER=y Signed-off-by: Eric Dumazet Cc: Tested-by: Bernard Pidoux Signed-off-by: Jakub Kicinski --- include/net/rose.h | 3 ++- net/rose/af_rose.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/rose.h b/include/net/rose.h index f192a64ddef2..23267b4efcfa 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -132,7 +132,8 @@ struct rose_sock { ax25_address source_digis[ROSE_MAX_DIGIS]; ax25_address dest_digis[ROSE_MAX_DIGIS]; struct rose_neigh *neighbour; - struct net_device *device; + struct net_device *device; + netdevice_tracker dev_tracker; unsigned int lci, rand; unsigned char state, condition, qbitincl, defer; unsigned char cause, diagnostic; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index a8e3ec800a9c..36fefc3957d7 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -192,7 +192,7 @@ static void rose_kill_by_device(struct net_device *dev) rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); if (rose->neighbour) rose->neighbour->use--; - dev_put(rose->device); + netdev_put(rose->device, &rose->dev_tracker); rose->device = NULL; } } @@ -594,7 +594,7 @@ static struct sock *rose_make_new(struct sock *osk) rose->defer = orose->defer; rose->device = orose->device; if (rose->device) - dev_hold(rose->device); + netdev_hold(rose->device, &rose->dev_tracker, GFP_ATOMIC); rose->qbitincl = orose->qbitincl; return sk; @@ -648,7 +648,7 @@ static int rose_release(struct socket *sock) break; } - dev_put(rose->device); + netdev_put(rose->device, &rose->dev_tracker); sock->sk = NULL; release_sock(sk); sock_put(sk); @@ -700,6 +700,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) rose->source_addr = addr->srose_addr; rose->device = dev; + netdev_tracker_alloc(rose->device, &rose->dev_tracker, GFP_KERNEL); rose->source_ndigis = addr->srose_ndigis; if (addr_len == sizeof(struct full_sockaddr_rose)) { @@ -801,6 +802,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); rose->source_call = user->call; rose->device = dev; + netdev_tracker_alloc(rose->device, &rose->dev_tracker, + GFP_KERNEL); ax25_uid_put(user); rose_insert_socket(sk); /* Finish the bind */ @@ -1024,6 +1027,9 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros make_rose->source_digis[n] = facilities.source_digis[n]; make_rose->neighbour = neigh; make_rose->device = dev; + /* Caller got a reference for us. */ + netdev_tracker_alloc(make_rose->device, &make_rose->dev_tracker, + GFP_ATOMIC); make_rose->facilities = facilities; make_rose->neighbour->use++; -- cgit v1.2.3 From 8eaa1d110800fac050bab44001732747a1c39894 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Fri, 29 Jul 2022 15:13:56 +0300 Subject: net/mlx5e: xsk: Discard unaligned XSK frames on striding RQ Striding RQ uses MTT page mapping, where each page corresponds to an XSK frame. MTT pages have alignment requirements, and XSK frames don't have any alignment guarantees in the unaligned mode. Frames with improper alignment must be discarded, otherwise the packet data will be written at a wrong address. Fixes: 282c0c798f8e ("net/mlx5e: Allow XSK frames smaller than a page") Signed-off-by: Maxim Mikityanskiy Reviewed-by: Tariq Toukan Reviewed-by: Saeed Mahameed Reviewed-by: Maciej Fijalkowski Link: https://lore.kernel.org/r/20220729121356.3990867-1-maximmi@nvidia.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h | 14 ++++++++++++++ include/net/xdp_sock_drv.h | 11 +++++++++++ 2 files changed, 25 insertions(+) (limited to 'include/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h index a8cfab4a393c..cc18d97d8ee0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h @@ -7,6 +7,8 @@ #include "en.h" #include +#define MLX5E_MTT_PTAG_MASK 0xfffffffffffffff8ULL + /* RX data path */ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, @@ -21,6 +23,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq, static inline int mlx5e_xsk_page_alloc_pool(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info) { +retry: dma_info->xsk = xsk_buff_alloc(rq->xsk_pool); if (!dma_info->xsk) return -ENOMEM; @@ -32,6 +35,17 @@ static inline int mlx5e_xsk_page_alloc_pool(struct mlx5e_rq *rq, */ dma_info->addr = xsk_buff_xdp_get_frame_dma(dma_info->xsk); + /* MTT page mapping has alignment requirements. If they are not + * satisfied, leak the descriptor so that it won't come again, and try + * to allocate a new one. + */ + if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) { + if (unlikely(dma_info->addr & ~MLX5E_MTT_PTAG_MASK)) { + xsk_buff_discard(dma_info->xsk); + goto retry; + } + } + return 0; } diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h index 4aa031849668..0774ce97c2f1 100644 --- a/include/net/xdp_sock_drv.h +++ b/include/net/xdp_sock_drv.h @@ -95,6 +95,13 @@ static inline void xsk_buff_free(struct xdp_buff *xdp) xp_free(xskb); } +static inline void xsk_buff_discard(struct xdp_buff *xdp) +{ + struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); + + xp_release(xskb); +} + static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) { xdp->data = xdp->data_hard_start + XDP_PACKET_HEADROOM; @@ -238,6 +245,10 @@ static inline void xsk_buff_free(struct xdp_buff *xdp) { } +static inline void xsk_buff_discard(struct xdp_buff *xdp) +{ +} + static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) { } -- cgit v1.2.3 From 06799a9085e12a778fe2851db550ab5911ad28fe Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 31 Jul 2022 15:41:05 +0300 Subject: net: bonding: replace dev_trans_start() with the jiffies of the last ARP/NS The bonding driver piggybacks on time stamps kept by the network stack for the purpose of the netdev TX watchdog, and this is problematic because it does not work with NETIF_F_LLTX devices. It is hard to say why the driver looks at dev_trans_start() of the slave->dev, considering that this is updated even by non-ARP/NS probes sent by us, and even by traffic not sent by us at all (for example PTP on physical slave devices). ARP monitoring in active-backup mode appears to still work even if we track only the last TX time of actual ARP probes. Signed-off-by: Vladimir Oltean Acked-by: Jay Vosburgh Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 35 ++++++++++++++++++++--------------- include/net/bonding.h | 13 ++++++++++++- 2 files changed, 32 insertions(+), 16 deletions(-) (limited to 'include/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e75acb14d066..ab7fdbbc2530 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2001,6 +2001,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) new_slave->target_last_arp_rx[i] = new_slave->last_rx; + new_slave->last_tx = new_slave->last_rx; + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -2884,8 +2886,11 @@ static void bond_arp_send(struct slave *slave, int arp_op, __be32 dest_ip, return; } - if (bond_handle_vlan(slave, tags, skb)) + if (bond_handle_vlan(slave, tags, skb)) { + slave_update_last_tx(slave); arp_xmit(skb); + } + return; } @@ -3074,8 +3079,7 @@ static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, curr_active_slave->last_link_up)) bond_validate_arp(bond, slave, tip, sip); else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) && - bond_time_in_interval(bond, - dev_trans_start(curr_arp_slave->dev), 1)) + bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1)) bond_validate_arp(bond, slave, sip, tip); out_unlock: @@ -3103,8 +3107,10 @@ static void bond_ns_send(struct slave *slave, const struct in6_addr *daddr, } addrconf_addr_solict_mult(daddr, &mcaddr); - if (bond_handle_vlan(slave, tags, skb)) + if (bond_handle_vlan(slave, tags, skb)) { + slave_update_last_tx(slave); ndisc_send_skb(skb, &mcaddr, saddr); + } } static void bond_ns_send_all(struct bonding *bond, struct slave *slave) @@ -3246,8 +3252,7 @@ static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond, curr_active_slave->last_link_up)) bond_validate_ns(bond, slave, saddr, daddr); else if (curr_arp_slave && - bond_time_in_interval(bond, - dev_trans_start(curr_arp_slave->dev), 1)) + bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1)) bond_validate_ns(bond, slave, saddr, daddr); out: @@ -3335,12 +3340,12 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) * so it can wait */ bond_for_each_slave_rcu(bond, slave, iter) { - unsigned long trans_start = dev_trans_start(slave->dev); + unsigned long last_tx = slave_last_tx(slave); bond_propose_link_state(slave, BOND_LINK_NOCHANGE); if (slave->link != BOND_LINK_UP) { - if (bond_time_in_interval(bond, trans_start, 1) && + if (bond_time_in_interval(bond, last_tx, 1) && bond_time_in_interval(bond, slave->last_rx, 1)) { bond_propose_link_state(slave, BOND_LINK_UP); @@ -3365,7 +3370,7 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (!bond_time_in_interval(bond, trans_start, bond->params.missed_max) || + if (!bond_time_in_interval(bond, last_tx, bond->params.missed_max) || !bond_time_in_interval(bond, slave->last_rx, bond->params.missed_max)) { bond_propose_link_state(slave, BOND_LINK_DOWN); @@ -3431,7 +3436,7 @@ re_arm: */ static int bond_ab_arp_inspect(struct bonding *bond) { - unsigned long trans_start, last_rx; + unsigned long last_tx, last_rx; struct list_head *iter; struct slave *slave; int commit = 0; @@ -3482,9 +3487,9 @@ static int bond_ab_arp_inspect(struct bonding *bond) * - (more than missed_max*delta since receive AND * the bond has an IP address) */ - trans_start = dev_trans_start(slave->dev); + last_tx = slave_last_tx(slave); if (bond_is_active_slave(slave) && - (!bond_time_in_interval(bond, trans_start, bond->params.missed_max) || + (!bond_time_in_interval(bond, last_tx, bond->params.missed_max) || !bond_time_in_interval(bond, last_rx, bond->params.missed_max))) { bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; @@ -3501,8 +3506,8 @@ static int bond_ab_arp_inspect(struct bonding *bond) */ static void bond_ab_arp_commit(struct bonding *bond) { - unsigned long trans_start; struct list_head *iter; + unsigned long last_tx; struct slave *slave; bond_for_each_slave(bond, slave, iter) { @@ -3511,10 +3516,10 @@ static void bond_ab_arp_commit(struct bonding *bond) continue; case BOND_LINK_UP: - trans_start = dev_trans_start(slave->dev); + last_tx = slave_last_tx(slave); if (rtnl_dereference(bond->curr_active_slave) != slave || (!rtnl_dereference(bond->curr_active_slave) && - bond_time_in_interval(bond, trans_start, 1))) { + bond_time_in_interval(bond, last_tx, 1))) { struct slave *current_arp_slave; current_arp_slave = rtnl_dereference(bond->current_arp_slave); diff --git a/include/net/bonding.h b/include/net/bonding.h index 6e78d657aa05..afd606df149a 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -161,8 +161,9 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct bonding *bond; /* our master */ int delay; - /* all three in jiffies */ + /* all 4 in jiffies */ unsigned long last_link_up; + unsigned long last_tx; unsigned long last_rx; unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS]; s8 link; /* one of BOND_LINK_XXXX */ @@ -540,6 +541,16 @@ static inline unsigned long slave_last_rx(struct bonding *bond, return slave->last_rx; } +static inline void slave_update_last_tx(struct slave *slave) +{ + WRITE_ONCE(slave->last_tx, jiffies); +} + +static inline unsigned long slave_last_tx(struct slave *slave) +{ + return READ_ONCE(slave->last_tx); +} + #ifdef CONFIG_NET_POLL_CONTROLLER static inline netdev_tx_t bond_netpoll_send_skb(const struct slave *slave, struct sk_buff *skb) -- cgit v1.2.3 From f1d41f7720c89705c20e4335a807b1c518c2e7be Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 2 Aug 2022 18:33:24 +0200 Subject: mptcp, btf: Add struct mptcp_sock definition when CONFIG_MPTCP is disabled The btf_sock_ids array needs struct mptcp_sock BTF ID for the bpf_skc_to_mptcp_sock helper. When CONFIG_MPTCP is disabled, the 'struct mptcp_sock' is not defined and resolve_btfids will complain with: [...] BTFIDS vmlinux WARN: resolve_btfids: unresolved symbol mptcp_sock [...] Add an empty definition for struct mptcp_sock when CONFIG_MPTCP is disabled. Fixes: 3bc253c2e652 ("bpf: Add bpf_skc_to_mptcp_sock_proto") Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Reviewed-by: Mat Martineau Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20220802163324.1873044-1-jolsa@kernel.org --- include/net/mptcp.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/net') diff --git a/include/net/mptcp.h b/include/net/mptcp.h index ac9cf7271d46..412479ebf5ad 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -291,4 +291,8 @@ struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk); static inline struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk) { return NULL; } #endif +#if !IS_ENABLED(CONFIG_MPTCP) +struct mptcp_sock { }; +#endif + #endif /* __NET_MPTCP_H */ -- cgit v1.2.3 From 34aae2c2fb1e3d88a5aeee16715cb6bf0336cdce Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 9 Aug 2022 11:25:43 +0200 Subject: netfilter: nf_tables: validate variable length element extension Update template to validate variable length extensions. This patch adds a new .ext_len[id] field to the template to store the expected extension length. This is used to sanity check the initialization of the variable length extension. Use PTR_ERR() in nft_set_elem_init() to report errors since, after this update, there are two reason why this might fail, either because of ENOMEM or insufficient room in the extension field (EINVAL). Kernels up until 7e6bc1f6cabc ("netfilter: nf_tables: stricter validation of element data") allowed to copy more data to the extension than was allocated. This ext_len field allows to validate if the destination has the correct size as additional check. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 4 +- net/netfilter/nf_tables_api.c | 84 ++++++++++++++++++++++++++++++++------- net/netfilter/nft_dynset.c | 2 +- 3 files changed, 73 insertions(+), 17 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 8bfb9c74afbf..7ece4fd0cf66 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -651,6 +651,7 @@ extern const struct nft_set_ext_type nft_set_ext_types[]; struct nft_set_ext_tmpl { u16 len; u8 offset[NFT_SET_EXT_NUM]; + u8 ext_len[NFT_SET_EXT_NUM]; }; /** @@ -680,7 +681,8 @@ static inline int nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id, return -EINVAL; tmpl->offset[id] = tmpl->len; - tmpl->len += nft_set_ext_types[id].len + len; + tmpl->ext_len[id] = nft_set_ext_types[id].len + len; + tmpl->len += tmpl->ext_len[id]; return 0; } diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 9f976b11d896..3b09e13b9b5c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5467,6 +5467,27 @@ err_set_elem_expr: return ERR_PTR(err); } +static int nft_set_ext_check(const struct nft_set_ext_tmpl *tmpl, u8 id, u32 len) +{ + len += nft_set_ext_types[id].len; + if (len > tmpl->ext_len[id] || + len > U8_MAX) + return -1; + + return 0; +} + +static int nft_set_ext_memcpy(const struct nft_set_ext_tmpl *tmpl, u8 id, + void *to, const void *from, u32 len) +{ + if (nft_set_ext_check(tmpl, id, len) < 0) + return -1; + + memcpy(to, from, len); + + return 0; +} + void *nft_set_elem_init(const struct nft_set *set, const struct nft_set_ext_tmpl *tmpl, const u32 *key, const u32 *key_end, @@ -5477,17 +5498,26 @@ void *nft_set_elem_init(const struct nft_set *set, elem = kzalloc(set->ops->elemsize + tmpl->len, gfp); if (elem == NULL) - return NULL; + return ERR_PTR(-ENOMEM); ext = nft_set_elem_ext(set, elem); nft_set_ext_init(ext, tmpl); - if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY)) - memcpy(nft_set_ext_key(ext), key, set->klen); - if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) - memcpy(nft_set_ext_key_end(ext), key_end, set->klen); - if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) - memcpy(nft_set_ext_data(ext), data, set->dlen); + if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY) && + nft_set_ext_memcpy(tmpl, NFT_SET_EXT_KEY, + nft_set_ext_key(ext), key, set->klen) < 0) + goto err_ext_check; + + if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END) && + nft_set_ext_memcpy(tmpl, NFT_SET_EXT_KEY_END, + nft_set_ext_key_end(ext), key_end, set->klen) < 0) + goto err_ext_check; + + if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && + nft_set_ext_memcpy(tmpl, NFT_SET_EXT_DATA, + nft_set_ext_data(ext), data, set->dlen) < 0) + goto err_ext_check; + if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { *nft_set_ext_expiration(ext) = get_jiffies_64() + expiration; if (expiration == 0) @@ -5497,6 +5527,11 @@ void *nft_set_elem_init(const struct nft_set *set, *nft_set_ext_timeout(ext) = timeout; return elem; + +err_ext_check: + kfree(elem); + + return ERR_PTR(-EINVAL); } static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx, @@ -5584,14 +5619,25 @@ err_expr: } static int nft_set_elem_expr_setup(struct nft_ctx *ctx, + const struct nft_set_ext_tmpl *tmpl, const struct nft_set_ext *ext, struct nft_expr *expr_array[], u32 num_exprs) { struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext); + u32 len = sizeof(struct nft_set_elem_expr); struct nft_expr *expr; int i, err; + if (num_exprs == 0) + return 0; + + for (i = 0; i < num_exprs; i++) + len += expr_array[i]->ops->size; + + if (nft_set_ext_check(tmpl, NFT_SET_EXT_EXPRESSIONS, len) < 0) + return -EINVAL; + for (i = 0; i < num_exprs; i++) { expr = nft_setelem_expr_at(elem_expr, elem_expr->size); err = nft_expr_clone(expr, expr_array[i]); @@ -6054,17 +6100,23 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, } } - err = -ENOMEM; elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, elem.key_end.val.data, elem.data.val.data, timeout, expiration, GFP_KERNEL_ACCOUNT); - if (elem.priv == NULL) + if (IS_ERR(elem.priv)) { + err = PTR_ERR(elem.priv); goto err_parse_data; + } ext = nft_set_elem_ext(set, elem.priv); if (flags) *nft_set_ext_flags(ext) = flags; + if (ulen > 0) { + if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) { + err = -EINVAL; + goto err_elem_userdata; + } udata = nft_set_ext_userdata(ext); udata->len = ulen - 1; nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); @@ -6073,14 +6125,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, *nft_set_ext_obj(ext) = obj; obj->use++; } - err = nft_set_elem_expr_setup(ctx, ext, expr_array, num_exprs); + err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs); if (err < 0) - goto err_elem_expr; + goto err_elem_free; trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); if (trans == NULL) { err = -ENOMEM; - goto err_elem_expr; + goto err_elem_free; } ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; @@ -6126,10 +6178,10 @@ err_set_full: nft_setelem_remove(ctx->net, set, &elem); err_element_clash: kfree(trans); -err_elem_expr: +err_elem_free: if (obj) obj->use--; - +err_elem_userdata: nf_tables_set_elem_destroy(ctx, set, elem.priv); err_parse_data: if (nla[NFTA_SET_ELEM_DATA] != NULL) @@ -6311,8 +6363,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, elem.key_end.val.data, NULL, 0, 0, GFP_KERNEL_ACCOUNT); - if (elem.priv == NULL) + if (IS_ERR(elem.priv)) { + err = PTR_ERR(elem.priv); goto fail_elem_key_end; + } ext = nft_set_elem_ext(set, elem.priv); if (flags) diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index 22f70b543fa2..6983e6ddeef9 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -60,7 +60,7 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr, ®s->data[priv->sreg_key], NULL, ®s->data[priv->sreg_data], timeout, 0, GFP_ATOMIC); - if (elem == NULL) + if (IS_ERR(elem)) goto err1; ext = nft_set_elem_ext(set, elem); -- cgit v1.2.3 From 341b6941608762d8235f3fd1e45e4d7114ed8c2c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Aug 2022 19:30:06 +0200 Subject: netfilter: nf_tables: upfront validation of data via nft_data_init() Instead of parsing the data and then validate that type and length are correct, pass a description of the expected data so it can be validated upfront before parsing it to bail out earlier. This patch adds a new .size field to specify the maximum size of the data area. The .len field is optional and it is used as an input/output field, it provides the specific length of the expected data in the input path. If then .len field is not specified, then obtained length from the netlink attribute is stored. This is required by cmp, bitwise, range and immediate, which provide no netlink attribute that describes the data length. The immediate expression uses the destination register type to infer the expected data type. Relying on opencoded validation of the expected data might lead to subtle bugs as described in 7e6bc1f6cabc ("netfilter: nf_tables: stricter validation of element data"). Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 4 +- net/netfilter/nf_tables_api.c | 78 ++++++++++++++++++++------------------- net/netfilter/nft_bitwise.c | 66 ++++++++++++++++----------------- net/netfilter/nft_cmp.c | 44 ++++++++++------------ net/netfilter/nft_immediate.c | 22 +++++++++-- net/netfilter/nft_range.c | 27 ++++++-------- 6 files changed, 126 insertions(+), 115 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 7ece4fd0cf66..1554f1e7215b 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -223,11 +223,11 @@ struct nft_ctx { struct nft_data_desc { enum nft_data_types type; + unsigned int size; unsigned int len; }; -int nft_data_init(const struct nft_ctx *ctx, - struct nft_data *data, unsigned int size, +int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, struct nft_data_desc *desc, const struct nlattr *nla); void nft_data_hold(const struct nft_data *data, enum nft_data_types type); void nft_data_release(const struct nft_data *data, enum nft_data_types type); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 0c3c0523e5f2..05896765c68f 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5202,19 +5202,13 @@ static int nft_setelem_parse_flags(const struct nft_set *set, static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set, struct nft_data *key, struct nlattr *attr) { - struct nft_data_desc desc; - int err; - - err = nft_data_init(ctx, key, NFT_DATA_VALUE_MAXLEN, &desc, attr); - if (err < 0) - return err; - - if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) { - nft_data_release(key, desc.type); - return -EINVAL; - } + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = NFT_DATA_VALUE_MAXLEN, + .len = set->klen, + }; - return 0; + return nft_data_init(ctx, key, &desc, attr); } static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set, @@ -5223,24 +5217,17 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set, struct nlattr *attr) { u32 dtype; - int err; - - err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr); - if (err < 0) - return err; if (set->dtype == NFT_DATA_VERDICT) dtype = NFT_DATA_VERDICT; else dtype = NFT_DATA_VALUE; - if (dtype != desc->type || - set->dlen != desc->len) { - nft_data_release(data, desc->type); - return -EINVAL; - } + desc->type = dtype; + desc->size = NFT_DATA_VALUE_MAXLEN; + desc->len = set->dlen; - return 0; + return nft_data_init(ctx, data, desc, attr); } static void *nft_setelem_catchall_get(const struct net *net, @@ -9685,7 +9672,7 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data, } desc->len = sizeof(data->verdict); - desc->type = NFT_DATA_VERDICT; + return 0; } @@ -9738,20 +9725,25 @@ nla_put_failure: } static int nft_value_init(const struct nft_ctx *ctx, - struct nft_data *data, unsigned int size, - struct nft_data_desc *desc, const struct nlattr *nla) + struct nft_data *data, struct nft_data_desc *desc, + const struct nlattr *nla) { unsigned int len; len = nla_len(nla); if (len == 0) return -EINVAL; - if (len > size) + if (len > desc->size) return -EOVERFLOW; + if (desc->len) { + if (len != desc->len) + return -EINVAL; + } else { + desc->len = len; + } nla_memcpy(data->data, nla, len); - desc->type = NFT_DATA_VALUE; - desc->len = len; + return 0; } @@ -9771,7 +9763,6 @@ static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = { * * @ctx: context of the expression using the data * @data: destination struct nft_data - * @size: maximum data length * @desc: data description * @nla: netlink attribute containing data * @@ -9781,24 +9772,35 @@ static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = { * The caller can indicate that it only wants to accept data of type * NFT_DATA_VALUE by passing NULL for the ctx argument. */ -int nft_data_init(const struct nft_ctx *ctx, - struct nft_data *data, unsigned int size, +int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, struct nft_data_desc *desc, const struct nlattr *nla) { struct nlattr *tb[NFTA_DATA_MAX + 1]; int err; + if (WARN_ON_ONCE(!desc->size)) + return -EINVAL; + err = nla_parse_nested_deprecated(tb, NFTA_DATA_MAX, nla, nft_data_policy, NULL); if (err < 0) return err; - if (tb[NFTA_DATA_VALUE]) - return nft_value_init(ctx, data, size, desc, - tb[NFTA_DATA_VALUE]); - if (tb[NFTA_DATA_VERDICT] && ctx != NULL) - return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]); - return -EINVAL; + if (tb[NFTA_DATA_VALUE]) { + if (desc->type != NFT_DATA_VALUE) + return -EINVAL; + + err = nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]); + } else if (tb[NFTA_DATA_VERDICT] && ctx != NULL) { + if (desc->type != NFT_DATA_VERDICT) + return -EINVAL; + + err = nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]); + } else { + err = -EINVAL; + } + + return err; } EXPORT_SYMBOL_GPL(nft_data_init); diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index 83590afe3768..e6e402b247d0 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -93,7 +93,16 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { static int nft_bitwise_init_bool(struct nft_bitwise *priv, const struct nlattr *const tb[]) { - struct nft_data_desc mask, xor; + struct nft_data_desc mask = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->mask), + .len = priv->len, + }; + struct nft_data_desc xor = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->xor), + .len = priv->len, + }; int err; if (tb[NFTA_BITWISE_DATA]) @@ -103,37 +112,30 @@ static int nft_bitwise_init_bool(struct nft_bitwise *priv, !tb[NFTA_BITWISE_XOR]) return -EINVAL; - err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &mask, - tb[NFTA_BITWISE_MASK]); + err = nft_data_init(NULL, &priv->mask, &mask, tb[NFTA_BITWISE_MASK]); if (err < 0) return err; - if (mask.type != NFT_DATA_VALUE || mask.len != priv->len) { - err = -EINVAL; - goto err_mask_release; - } - err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &xor, - tb[NFTA_BITWISE_XOR]); + err = nft_data_init(NULL, &priv->xor, &xor, tb[NFTA_BITWISE_XOR]); if (err < 0) - goto err_mask_release; - if (xor.type != NFT_DATA_VALUE || xor.len != priv->len) { - err = -EINVAL; - goto err_xor_release; - } + goto err_xor_err; return 0; -err_xor_release: - nft_data_release(&priv->xor, xor.type); -err_mask_release: +err_xor_err: nft_data_release(&priv->mask, mask.type); + return err; } static int nft_bitwise_init_shift(struct nft_bitwise *priv, const struct nlattr *const tb[]) { - struct nft_data_desc d; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->data), + .len = sizeof(u32), + }; int err; if (tb[NFTA_BITWISE_MASK] || @@ -143,13 +145,12 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv, if (!tb[NFTA_BITWISE_DATA]) return -EINVAL; - err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &d, - tb[NFTA_BITWISE_DATA]); + err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_BITWISE_DATA]); if (err < 0) return err; - if (d.type != NFT_DATA_VALUE || d.len != sizeof(u32) || - priv->data.data[0] >= BITS_PER_TYPE(u32)) { - nft_data_release(&priv->data, d.type); + + if (priv->data.data[0] >= BITS_PER_TYPE(u32)) { + nft_data_release(&priv->data, desc.type); return -EINVAL; } @@ -339,22 +340,21 @@ static const struct nft_expr_ops nft_bitwise_ops = { static int nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out) { - struct nft_data_desc desc; struct nft_data data; - int err = 0; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(data), + .len = sizeof(u32), + }; + int err; - err = nft_data_init(NULL, &data, sizeof(data), &desc, tb); + err = nft_data_init(NULL, &data, &desc, tb); if (err < 0) return err; - if (desc.type != NFT_DATA_VALUE || desc.len != sizeof(u32)) { - err = -EINVAL; - goto err; - } *out = data.data[0]; -err: - nft_data_release(&data, desc.type); - return err; + + return 0; } static int nft_bitwise_fast_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c index 777f09e4dc60..963cf831799c 100644 --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c @@ -73,20 +73,16 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { struct nft_cmp_expr *priv = nft_expr_priv(expr); - struct nft_data_desc desc; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->data), + }; int err; - err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc, - tb[NFTA_CMP_DATA]); + err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]); if (err < 0) return err; - if (desc.type != NFT_DATA_VALUE) { - err = -EINVAL; - nft_data_release(&priv->data, desc.type); - return err; - } - err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len); if (err < 0) return err; @@ -214,12 +210,14 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); - struct nft_data_desc desc; struct nft_data data; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(data), + }; int err; - err = nft_data_init(NULL, &data, sizeof(data), &desc, - tb[NFTA_CMP_DATA]); + err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]); if (err < 0) return err; @@ -313,11 +311,13 @@ static int nft_cmp16_fast_init(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr); - struct nft_data_desc desc; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->data), + }; int err; - err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc, - tb[NFTA_CMP_DATA]); + err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]); if (err < 0) return err; @@ -380,8 +380,11 @@ const struct nft_expr_ops nft_cmp16_fast_ops = { static const struct nft_expr_ops * nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) { - struct nft_data_desc desc; struct nft_data data; + struct nft_data_desc desc = { + .type = NFT_DATA_VALUE, + .size = sizeof(data), + }; enum nft_cmp_ops op; u8 sreg; int err; @@ -404,14 +407,10 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) return ERR_PTR(-EINVAL); } - err = nft_data_init(NULL, &data, sizeof(data), &desc, - tb[NFTA_CMP_DATA]); + err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]); if (err < 0) return ERR_PTR(err); - if (desc.type != NFT_DATA_VALUE) - goto err1; - sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG])); if (op == NFT_CMP_EQ || op == NFT_CMP_NEQ) { @@ -423,9 +422,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) return &nft_cmp16_fast_ops; } return &nft_cmp_ops; -err1: - nft_data_release(&data, desc.type); - return ERR_PTR(-EINVAL); } struct nft_expr_type nft_cmp_type __read_mostly = { diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c index b80f7b507349..5f28b21abc7d 100644 --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c @@ -29,20 +29,36 @@ static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = { [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED }, }; +static enum nft_data_types nft_reg_to_type(const struct nlattr *nla) +{ + enum nft_data_types type; + u8 reg; + + reg = ntohl(nla_get_be32(nla)); + if (reg == NFT_REG_VERDICT) + type = NFT_DATA_VERDICT; + else + type = NFT_DATA_VALUE; + + return type; +} + static int nft_immediate_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { struct nft_immediate_expr *priv = nft_expr_priv(expr); - struct nft_data_desc desc; + struct nft_data_desc desc = { + .size = sizeof(priv->data), + }; int err; if (tb[NFTA_IMMEDIATE_DREG] == NULL || tb[NFTA_IMMEDIATE_DATA] == NULL) return -EINVAL; - err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc, - tb[NFTA_IMMEDIATE_DATA]); + desc.type = nft_reg_to_type(tb[NFTA_IMMEDIATE_DREG]); + err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]); if (err < 0) return err; diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c index 66f77484c227..832f0d725a9e 100644 --- a/net/netfilter/nft_range.c +++ b/net/netfilter/nft_range.c @@ -51,7 +51,14 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr const struct nlattr * const tb[]) { struct nft_range_expr *priv = nft_expr_priv(expr); - struct nft_data_desc desc_from, desc_to; + struct nft_data_desc desc_from = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->data_from), + }; + struct nft_data_desc desc_to = { + .type = NFT_DATA_VALUE, + .size = sizeof(priv->data_to), + }; int err; u32 op; @@ -61,26 +68,16 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr !tb[NFTA_RANGE_TO_DATA]) return -EINVAL; - err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from), - &desc_from, tb[NFTA_RANGE_FROM_DATA]); + err = nft_data_init(NULL, &priv->data_from, &desc_from, + tb[NFTA_RANGE_FROM_DATA]); if (err < 0) return err; - if (desc_from.type != NFT_DATA_VALUE) { - err = -EINVAL; - goto err1; - } - - err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to), - &desc_to, tb[NFTA_RANGE_TO_DATA]); + err = nft_data_init(NULL, &priv->data_to, &desc_to, + tb[NFTA_RANGE_TO_DATA]); if (err < 0) goto err1; - if (desc_to.type != NFT_DATA_VALUE) { - err = -EINVAL; - goto err2; - } - if (desc_from.len != desc_to.len) { err = -EINVAL; goto err2; -- cgit v1.2.3 From f323ef3a0d49e147365284bc1f02212e617b7f09 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Aug 2022 19:30:07 +0200 Subject: netfilter: nf_tables: disallow jump to implicit chain from set element Extend struct nft_data_desc to add a flag field that specifies nft_data_init() is being called for set element data. Use it to disallow jump to implicit chain from set element, only jump to chain via immediate expression is allowed. Fixes: d0e2c7de92c7 ("netfilter: nf_tables: add NFT_CHAIN_BINDING") Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 5 +++++ net/netfilter/nf_tables_api.c | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 1554f1e7215b..99aae36c04b9 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -221,10 +221,15 @@ struct nft_ctx { bool report; }; +enum nft_data_desc_flags { + NFT_DATA_DESC_SETELEM = (1 << 0), +}; + struct nft_data_desc { enum nft_data_types type; unsigned int size; unsigned int len; + unsigned int flags; }; int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 05896765c68f..460b0925ea60 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5226,6 +5226,7 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set, desc->type = dtype; desc->size = NFT_DATA_VALUE_MAXLEN; desc->len = set->dlen; + desc->flags = NFT_DATA_DESC_SETELEM; return nft_data_init(ctx, data, desc, attr); } @@ -9665,6 +9666,9 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data, return PTR_ERR(chain); if (nft_is_base_chain(chain)) return -EOPNOTSUPP; + if (desc->flags & NFT_DATA_DESC_SETELEM && + chain->flags & NFT_CHAIN_BINDING) + return -EINVAL; chain->use++; data->verdict.chain = chain; -- cgit v1.2.3 From 84b709d31063bacaabaaad1c5d85143150edd695 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Aug 2022 18:02:36 +0200 Subject: ax88796: Fix some typo in a comment s/by caused/be caused/ s/ax88786/ax88796/ Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/7db4b622d2c3e5af58c1d1f32b81836f4af71f18.1659801746.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- include/net/ax88796.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/ax88796.h b/include/net/ax88796.h index b658471f97f0..303100f08ab8 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -34,8 +34,8 @@ struct ax_plat_data { const unsigned char *buf, int star_page); void (*block_input)(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); - /* returns nonzero if a pending interrupt request might by caused by - * the ax88786. Handles all interrupts if set to NULL + /* returns nonzero if a pending interrupt request might be caused by + * the ax88796. Handles all interrupts if set to NULL */ int (*check_irq)(struct platform_device *pdev); }; -- cgit v1.2.3 From 2a0133723f9ebeb751cfce19f74ec07e108bef1f Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 5 Aug 2022 15:48:34 +0800 Subject: net: fix refcount bug in sk_psock_get (2) Syzkaller reports refcount bug as follows: ------------[ cut here ]------------ refcount_t: saturated; leaking memory. WARNING: CPU: 1 PID: 3605 at lib/refcount.c:19 refcount_warn_saturate+0xf4/0x1e0 lib/refcount.c:19 Modules linked in: CPU: 1 PID: 3605 Comm: syz-executor208 Not tainted 5.18.0-syzkaller-03023-g7e062cda7d90 #0 __refcount_add_not_zero include/linux/refcount.h:163 [inline] __refcount_inc_not_zero include/linux/refcount.h:227 [inline] refcount_inc_not_zero include/linux/refcount.h:245 [inline] sk_psock_get+0x3bc/0x410 include/linux/skmsg.h:439 tls_data_ready+0x6d/0x1b0 net/tls/tls_sw.c:2091 tcp_data_ready+0x106/0x520 net/ipv4/tcp_input.c:4983 tcp_data_queue+0x25f2/0x4c90 net/ipv4/tcp_input.c:5057 tcp_rcv_state_process+0x1774/0x4e80 net/ipv4/tcp_input.c:6659 tcp_v4_do_rcv+0x339/0x980 net/ipv4/tcp_ipv4.c:1682 sk_backlog_rcv include/net/sock.h:1061 [inline] __release_sock+0x134/0x3b0 net/core/sock.c:2849 release_sock+0x54/0x1b0 net/core/sock.c:3404 inet_shutdown+0x1e0/0x430 net/ipv4/af_inet.c:909 __sys_shutdown_sock net/socket.c:2331 [inline] __sys_shutdown_sock net/socket.c:2325 [inline] __sys_shutdown+0xf1/0x1b0 net/socket.c:2343 __do_sys_shutdown net/socket.c:2351 [inline] __se_sys_shutdown net/socket.c:2349 [inline] __x64_sys_shutdown+0x50/0x70 net/socket.c:2349 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x46/0xb0 During SMC fallback process in connect syscall, kernel will replaces TCP with SMC. In order to forward wakeup smc socket waitqueue after fallback, kernel will sets clcsk->sk_user_data to origin smc socket in smc_fback_replace_callbacks(). Later, in shutdown syscall, kernel will calls sk_psock_get(), which treats the clcsk->sk_user_data as psock type, triggering the refcnt warning. So, the root cause is that smc and psock, both will use sk_user_data field. So they will mismatch this field easily. This patch solves it by using another bit(defined as SK_USER_DATA_PSOCK) in PTRMASK, to mark whether sk_user_data points to a psock object or not. This patch depends on a PTRMASK introduced in commit f1ff5ce2cd5e ("net, sk_msg: Clear sk_user_data pointer on clone if tagged"). For there will possibly be more flags in the sk_user_data field, this patch also refactor sk_user_data flags code to be more generic to improve its maintainability. Reported-and-tested-by: syzbot+5f26f85569bd179c18ce@syzkaller.appspotmail.com Suggested-by: Jakub Kicinski Acked-by: Wen Gu Signed-off-by: Hawkins Jiawei Reviewed-by: Jakub Sitnicki Signed-off-by: Jakub Kicinski --- include/linux/skmsg.h | 3 ++- include/net/sock.h | 68 ++++++++++++++++++++++++++++++++++++--------------- net/core/skmsg.c | 4 ++- 3 files changed, 53 insertions(+), 22 deletions(-) (limited to 'include/net') diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 153b6dec9b6a..48f4b645193b 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -278,7 +278,8 @@ static inline void sk_msg_sg_copy_clear(struct sk_msg *msg, u32 start) static inline struct sk_psock *sk_psock(const struct sock *sk) { - return rcu_dereference_sk_user_data(sk); + return __rcu_dereference_sk_user_data_with_flags(sk, + SK_USER_DATA_PSOCK); } static inline void sk_psock_set_state(struct sk_psock *psock, diff --git a/include/net/sock.h b/include/net/sock.h index a7273b289188..05a1bbdf5805 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -545,14 +545,26 @@ enum sk_pacing { SK_PACING_FQ = 2, }; -/* Pointer stored in sk_user_data might not be suitable for copying - * when cloning the socket. For instance, it can point to a reference - * counted object. sk_user_data bottom bit is set if pointer must not - * be copied. +/* flag bits in sk_user_data + * + * - SK_USER_DATA_NOCOPY: Pointer stored in sk_user_data might + * not be suitable for copying when cloning the socket. For instance, + * it can point to a reference counted object. sk_user_data bottom + * bit is set if pointer must not be copied. + * + * - SK_USER_DATA_BPF: Mark whether sk_user_data field is + * managed/owned by a BPF reuseport array. This bit should be set + * when sk_user_data's sk is added to the bpf's reuseport_array. + * + * - SK_USER_DATA_PSOCK: Mark whether pointer stored in + * sk_user_data points to psock type. This bit should be set + * when sk_user_data is assigned to a psock object. */ #define SK_USER_DATA_NOCOPY 1UL -#define SK_USER_DATA_BPF 2UL /* Managed by BPF */ -#define SK_USER_DATA_PTRMASK ~(SK_USER_DATA_NOCOPY | SK_USER_DATA_BPF) +#define SK_USER_DATA_BPF 2UL +#define SK_USER_DATA_PSOCK 4UL +#define SK_USER_DATA_PTRMASK ~(SK_USER_DATA_NOCOPY | SK_USER_DATA_BPF |\ + SK_USER_DATA_PSOCK) /** * sk_user_data_is_nocopy - Test if sk_user_data pointer must not be copied @@ -565,24 +577,40 @@ static inline bool sk_user_data_is_nocopy(const struct sock *sk) #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data))) +/** + * __rcu_dereference_sk_user_data_with_flags - return the pointer + * only if argument flags all has been set in sk_user_data. Otherwise + * return NULL + * + * @sk: socket + * @flags: flag bits + */ +static inline void * +__rcu_dereference_sk_user_data_with_flags(const struct sock *sk, + uintptr_t flags) +{ + uintptr_t sk_user_data = (uintptr_t)rcu_dereference(__sk_user_data(sk)); + + WARN_ON_ONCE(flags & SK_USER_DATA_PTRMASK); + + if ((sk_user_data & flags) == flags) + return (void *)(sk_user_data & SK_USER_DATA_PTRMASK); + return NULL; +} + #define rcu_dereference_sk_user_data(sk) \ + __rcu_dereference_sk_user_data_with_flags(sk, 0) +#define __rcu_assign_sk_user_data_with_flags(sk, ptr, flags) \ ({ \ - void *__tmp = rcu_dereference(__sk_user_data((sk))); \ - (void *)((uintptr_t)__tmp & SK_USER_DATA_PTRMASK); \ -}) -#define rcu_assign_sk_user_data(sk, ptr) \ -({ \ - uintptr_t __tmp = (uintptr_t)(ptr); \ - WARN_ON_ONCE(__tmp & ~SK_USER_DATA_PTRMASK); \ - rcu_assign_pointer(__sk_user_data((sk)), __tmp); \ -}) -#define rcu_assign_sk_user_data_nocopy(sk, ptr) \ -({ \ - uintptr_t __tmp = (uintptr_t)(ptr); \ - WARN_ON_ONCE(__tmp & ~SK_USER_DATA_PTRMASK); \ + uintptr_t __tmp1 = (uintptr_t)(ptr), \ + __tmp2 = (uintptr_t)(flags); \ + WARN_ON_ONCE(__tmp1 & ~SK_USER_DATA_PTRMASK); \ + WARN_ON_ONCE(__tmp2 & SK_USER_DATA_PTRMASK); \ rcu_assign_pointer(__sk_user_data((sk)), \ - __tmp | SK_USER_DATA_NOCOPY); \ + __tmp1 | __tmp2); \ }) +#define rcu_assign_sk_user_data(sk, ptr) \ + __rcu_assign_sk_user_data_with_flags(sk, ptr, 0) static inline struct net *sock_net(const struct sock *sk) diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 81627892bdd4..57e942a6431a 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -739,7 +739,9 @@ struct sk_psock *sk_psock_init(struct sock *sk, int node) sk_psock_set_state(psock, SK_PSOCK_TX_ENABLED); refcount_set(&psock->refcnt, 1); - rcu_assign_sk_user_data_nocopy(sk, psock); + __rcu_assign_sk_user_data_with_flags(sk, psock, + SK_USER_DATA_NOCOPY | + SK_USER_DATA_PSOCK); sock_hold(sk); out: -- cgit v1.2.3 From 94ce3b64c62d4b628cf85cd0d9a370aca8f7e43a Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Wed, 10 Aug 2022 11:16:02 +0300 Subject: net/tls: Use RCU API to access tls_ctx->netdev Currently, tls_device_down synchronizes with tls_device_resync_rx using RCU, however, the pointer to netdev is stored using WRITE_ONCE and loaded using READ_ONCE. Although such approach is technically correct (rcu_dereference is essentially a READ_ONCE, and rcu_assign_pointer uses WRITE_ONCE to store NULL), using special RCU helpers for pointers is more valid, as it includes additional checks and might change the implementation transparently to the callers. Mark the netdev pointer as __rcu and use the correct RCU helpers to access it. For non-concurrent access pass the right conditions that guarantee safe access (locks taken, refcount value). Also use the correct helper in mlx5e, where even READ_ONCE was missing. The transition to RCU exposes existing issues, fixed by this commit: 1. bond_tls_device_xmit could read netdev twice, and it could become NULL the second time, after the NULL check passed. 2. Drivers shouldn't stop processing the last packet if tls_device_down just set netdev to NULL, before tls_dev_del was called. This prevents a possible packet drop when transitioning to the fallback software mode. Fixes: 89df6a810470 ("net/bonding: Implement TLS TX device offload") Fixes: c55dcdd435aa ("net/tls: Fix use-after-free after the TLS device goes down and up") Signed-off-by: Maxim Mikityanskiy Link: https://lore.kernel.org/r/20220810081602.1435800-1-maximmi@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 10 ++++-- .../chelsio/inline_crypto/ch_ktls/chcr_ktls.c | 8 ++++- .../ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c | 8 ++++- include/net/tls.h | 2 +- net/tls/tls_device.c | 38 +++++++++++++++++----- net/tls/tls_device_fallback.c | 3 +- 6 files changed, 54 insertions(+), 15 deletions(-) (limited to 'include/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ab7fdbbc2530..50e60843020c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5338,8 +5338,14 @@ static struct net_device *bond_sk_get_lower_dev(struct net_device *dev, static netdev_tx_t bond_tls_device_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *dev) { - if (likely(bond_get_slave_by_dev(bond, tls_get_ctx(skb->sk)->netdev))) - return bond_dev_queue_xmit(bond, skb, tls_get_ctx(skb->sk)->netdev); + struct net_device *tls_netdev = rcu_dereference(tls_get_ctx(skb->sk)->netdev); + + /* tls_netdev might become NULL, even if tls_is_sk_tx_device_offloaded + * was true, if tls_device_down is running in parallel, but it's OK, + * because bond_get_slave_by_dev has a NULL check. + */ + if (likely(bond_get_slave_by_dev(bond, tls_netdev))) + return bond_dev_queue_xmit(bond, skb, tls_netdev); return bond_tx_drop(dev, skb); } #endif diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c index bfee0e4e54b1..da9973b711f4 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c @@ -1932,6 +1932,7 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev) int data_len, qidx, ret = 0, mss; struct tls_record_info *record; struct chcr_ktls_info *tx_info; + struct net_device *tls_netdev; struct tls_context *tls_ctx; struct sge_eth_txq *q; struct adapter *adap; @@ -1945,7 +1946,12 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev) mss = skb_is_gso(skb) ? skb_shinfo(skb)->gso_size : data_len; tls_ctx = tls_get_ctx(skb->sk); - if (unlikely(tls_ctx->netdev != dev)) + tls_netdev = rcu_dereference_bh(tls_ctx->netdev); + /* Don't quit on NULL: if tls_device_down is running in parallel, + * netdev might become NULL, even if tls_is_sk_tx_device_offloaded was + * true. Rather continue processing this packet. + */ + if (unlikely(tls_netdev && tls_netdev != dev)) goto out; tx_ctx = chcr_get_ktls_tx_context(tls_ctx); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index 6b6c7044b64a..0aef69527226 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -808,6 +808,7 @@ bool mlx5e_ktls_handle_tx_skb(struct net_device *netdev, struct mlx5e_txqsq *sq, { struct mlx5e_ktls_offload_context_tx *priv_tx; struct mlx5e_sq_stats *stats = sq->stats; + struct net_device *tls_netdev; struct tls_context *tls_ctx; int datalen; u32 seq; @@ -819,7 +820,12 @@ bool mlx5e_ktls_handle_tx_skb(struct net_device *netdev, struct mlx5e_txqsq *sq, mlx5e_tx_mpwqe_ensure_complete(sq); tls_ctx = tls_get_ctx(skb->sk); - if (WARN_ON_ONCE(tls_ctx->netdev != netdev)) + tls_netdev = rcu_dereference_bh(tls_ctx->netdev); + /* Don't WARN on NULL: if tls_device_down is running in parallel, + * netdev might become NULL, even if tls_is_sk_tx_device_offloaded was + * true. Rather continue processing this packet. + */ + if (WARN_ON_ONCE(tls_netdev && tls_netdev != netdev)) goto err_out; priv_tx = mlx5e_get_ktls_tx_priv_ctx(tls_ctx); diff --git a/include/net/tls.h b/include/net/tls.h index b75b5727abdb..cb205f9d9473 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -237,7 +237,7 @@ struct tls_context { void *priv_ctx_tx; void *priv_ctx_rx; - struct net_device *netdev; + struct net_device __rcu *netdev; /* rw cache line */ struct cipher_context tx; diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 6ed41474bdf8..0f983e5f7dde 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -71,7 +71,13 @@ static void tls_device_tx_del_task(struct work_struct *work) struct tls_offload_context_tx *offload_ctx = container_of(work, struct tls_offload_context_tx, destruct_work); struct tls_context *ctx = offload_ctx->ctx; - struct net_device *netdev = ctx->netdev; + struct net_device *netdev; + + /* Safe, because this is the destroy flow, refcount is 0, so + * tls_device_down can't store this field in parallel. + */ + netdev = rcu_dereference_protected(ctx->netdev, + !refcount_read(&ctx->refcount)); netdev->tlsdev_ops->tls_dev_del(netdev, ctx, TLS_OFFLOAD_CTX_DIR_TX); dev_put(netdev); @@ -81,6 +87,7 @@ static void tls_device_tx_del_task(struct work_struct *work) static void tls_device_queue_ctx_destruction(struct tls_context *ctx) { + struct net_device *netdev; unsigned long flags; bool async_cleanup; @@ -91,7 +98,14 @@ static void tls_device_queue_ctx_destruction(struct tls_context *ctx) } list_del(&ctx->list); /* Remove from tls_device_list / tls_device_down_list */ - async_cleanup = ctx->netdev && ctx->tx_conf == TLS_HW; + + /* Safe, because this is the destroy flow, refcount is 0, so + * tls_device_down can't store this field in parallel. + */ + netdev = rcu_dereference_protected(ctx->netdev, + !refcount_read(&ctx->refcount)); + + async_cleanup = netdev && ctx->tx_conf == TLS_HW; if (async_cleanup) { struct tls_offload_context_tx *offload_ctx = tls_offload_ctx_tx(ctx); @@ -229,7 +243,8 @@ static void tls_device_resync_tx(struct sock *sk, struct tls_context *tls_ctx, trace_tls_device_tx_resync_send(sk, seq, rcd_sn); down_read(&device_offload_lock); - netdev = tls_ctx->netdev; + netdev = rcu_dereference_protected(tls_ctx->netdev, + lockdep_is_held(&device_offload_lock)); if (netdev) err = netdev->tlsdev_ops->tls_dev_resync(netdev, sk, seq, rcd_sn, @@ -710,7 +725,7 @@ static void tls_device_resync_rx(struct tls_context *tls_ctx, trace_tls_device_rx_resync_send(sk, seq, rcd_sn, rx_ctx->resync_type); rcu_read_lock(); - netdev = READ_ONCE(tls_ctx->netdev); + netdev = rcu_dereference(tls_ctx->netdev); if (netdev) netdev->tlsdev_ops->tls_dev_resync(netdev, sk, seq, rcd_sn, TLS_OFFLOAD_CTX_DIR_RX); @@ -1035,7 +1050,7 @@ static void tls_device_attach(struct tls_context *ctx, struct sock *sk, if (sk->sk_destruct != tls_device_sk_destruct) { refcount_set(&ctx->refcount, 1); dev_hold(netdev); - ctx->netdev = netdev; + RCU_INIT_POINTER(ctx->netdev, netdev); spin_lock_irq(&tls_device_lock); list_add_tail(&ctx->list, &tls_device_list); spin_unlock_irq(&tls_device_lock); @@ -1306,7 +1321,8 @@ void tls_device_offload_cleanup_rx(struct sock *sk) struct net_device *netdev; down_read(&device_offload_lock); - netdev = tls_ctx->netdev; + netdev = rcu_dereference_protected(tls_ctx->netdev, + lockdep_is_held(&device_offload_lock)); if (!netdev) goto out; @@ -1315,7 +1331,7 @@ void tls_device_offload_cleanup_rx(struct sock *sk) if (tls_ctx->tx_conf != TLS_HW) { dev_put(netdev); - tls_ctx->netdev = NULL; + rcu_assign_pointer(tls_ctx->netdev, NULL); } else { set_bit(TLS_RX_DEV_CLOSED, &tls_ctx->flags); } @@ -1335,7 +1351,11 @@ static int tls_device_down(struct net_device *netdev) spin_lock_irqsave(&tls_device_lock, flags); list_for_each_entry_safe(ctx, tmp, &tls_device_list, list) { - if (ctx->netdev != netdev || + struct net_device *ctx_netdev = + rcu_dereference_protected(ctx->netdev, + lockdep_is_held(&device_offload_lock)); + + if (ctx_netdev != netdev || !refcount_inc_not_zero(&ctx->refcount)) continue; @@ -1352,7 +1372,7 @@ static int tls_device_down(struct net_device *netdev) /* Stop the RX and TX resync. * tls_dev_resync must not be called after tls_dev_del. */ - WRITE_ONCE(ctx->netdev, NULL); + rcu_assign_pointer(ctx->netdev, NULL); /* Start skipping the RX resync logic completely. */ set_bit(TLS_RX_DEV_DEGRADED, &ctx->flags); diff --git a/net/tls/tls_device_fallback.c b/net/tls/tls_device_fallback.c index 618cee704217..7dfc8023e0f1 100644 --- a/net/tls/tls_device_fallback.c +++ b/net/tls/tls_device_fallback.c @@ -426,7 +426,8 @@ struct sk_buff *tls_validate_xmit_skb(struct sock *sk, struct net_device *dev, struct sk_buff *skb) { - if (dev == tls_get_ctx(sk)->netdev || netif_is_bond_master(dev)) + if (dev == rcu_dereference_bh(tls_get_ctx(sk)->netdev) || + netif_is_bond_master(dev)) return skb; return tls_sw_fallback(sk, skb); -- cgit v1.2.3 From 0b2f3212b551a87fe936701fa0813032861a3308 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 5 Aug 2022 10:59:57 +0200 Subject: netfilter: nfnetlink: re-enable conntrack expectation events To avoid allocation of the conntrack extension area when possible, the default behaviour was changed to only allocate the event extension if a userspace program is subscribed to a notification group. Problem is that while 'conntrack -E' does enable the event allocation behind the scenes, 'conntrack -E expect' does not: no expectation events are delivered unless user sets "net.netfilter.nf_conntrack_events" back to 1 (always on). Fix the autodetection to also consider EXP type group. We need to track the 6 event groups (3+3, new/update/destroy for events and for expectations each) independently, else we'd disable events again if an expectation group becomes empty while there is still an active event group. Fixes: 2794cdb0b97b ("netfilter: nfnetlink: allow to detect if ctnetlink listeners exist") Reported-by: Yi Chen Signed-off-by: Florian Westphal --- include/net/netns/conntrack.h | 2 +- net/netfilter/nfnetlink.c | 83 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 13 deletions(-) (limited to 'include/net') diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 0677cd3de034..c396a3862e80 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -95,7 +95,7 @@ struct nf_ip_net { struct netns_ct { #ifdef CONFIG_NF_CONNTRACK_EVENTS - bool ctnetlink_has_listener; + u8 ctnetlink_has_listener; bool ecache_dwork_pending; #endif u8 sysctl_log_invalid; /* Log invalid packets */ diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index c24b1240908f..9c44518cb70f 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -44,6 +44,10 @@ MODULE_DESCRIPTION("Netfilter messages via netlink socket"); static unsigned int nfnetlink_pernet_id __read_mostly; +#ifdef CONFIG_NF_CONNTRACK_EVENTS +static DEFINE_SPINLOCK(nfnl_grp_active_lock); +#endif + struct nfnl_net { struct sock *nfnl; }; @@ -654,6 +658,44 @@ static void nfnetlink_rcv(struct sk_buff *skb) netlink_rcv_skb(skb, nfnetlink_rcv_msg); } +static void nfnetlink_bind_event(struct net *net, unsigned int group) +{ +#ifdef CONFIG_NF_CONNTRACK_EVENTS + int type, group_bit; + u8 v; + + /* All NFNLGRP_CONNTRACK_* group bits fit into u8. + * The other groups are not relevant and can be ignored. + */ + if (group >= 8) + return; + + type = nfnl_group2type[group]; + + switch (type) { + case NFNL_SUBSYS_CTNETLINK: + break; + case NFNL_SUBSYS_CTNETLINK_EXP: + break; + default: + return; + } + + group_bit = (1 << group); + + spin_lock(&nfnl_grp_active_lock); + v = READ_ONCE(net->ct.ctnetlink_has_listener); + if ((v & group_bit) == 0) { + v |= group_bit; + + /* read concurrently without nfnl_grp_active_lock held. */ + WRITE_ONCE(net->ct.ctnetlink_has_listener, v); + } + + spin_unlock(&nfnl_grp_active_lock); +#endif +} + static int nfnetlink_bind(struct net *net, int group) { const struct nfnetlink_subsystem *ss; @@ -670,28 +712,45 @@ static int nfnetlink_bind(struct net *net, int group) if (!ss) request_module_nowait("nfnetlink-subsys-%d", type); -#ifdef CONFIG_NF_CONNTRACK_EVENTS - if (type == NFNL_SUBSYS_CTNETLINK) { - nfnl_lock(NFNL_SUBSYS_CTNETLINK); - WRITE_ONCE(net->ct.ctnetlink_has_listener, true); - nfnl_unlock(NFNL_SUBSYS_CTNETLINK); - } -#endif + nfnetlink_bind_event(net, group); return 0; } static void nfnetlink_unbind(struct net *net, int group) { #ifdef CONFIG_NF_CONNTRACK_EVENTS + int type, group_bit; + if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX) return; - if (nfnl_group2type[group] == NFNL_SUBSYS_CTNETLINK) { - nfnl_lock(NFNL_SUBSYS_CTNETLINK); - if (!nfnetlink_has_listeners(net, group)) - WRITE_ONCE(net->ct.ctnetlink_has_listener, false); - nfnl_unlock(NFNL_SUBSYS_CTNETLINK); + type = nfnl_group2type[group]; + + switch (type) { + case NFNL_SUBSYS_CTNETLINK: + break; + case NFNL_SUBSYS_CTNETLINK_EXP: + break; + default: + return; + } + + /* ctnetlink_has_listener is u8 */ + if (group >= 8) + return; + + group_bit = (1 << group); + + spin_lock(&nfnl_grp_active_lock); + if (!nfnetlink_has_listeners(net, group)) { + u8 v = READ_ONCE(net->ct.ctnetlink_has_listener); + + v &= ~group_bit; + + /* read concurrently without nfnl_grp_active_lock held. */ + WRITE_ONCE(net->ct.ctnetlink_has_listener, v); } + spin_unlock(&nfnl_grp_active_lock); #endif } -- cgit v1.2.3 From 5c221f0af68cfa9edcffd26ba6dbbc4b7ddb1700 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 9 Aug 2022 16:20:12 -0700 Subject: net: add missing kdoc for struct genl_multicast_group::flags Multicast group flags were added in commit 4d54cc32112d ("mptcp: avoid lock_fast usage in accept path"), but it missed adding the kdoc. Mention which flags go into that field, and do the same for op structs. Link: https://lore.kernel.org/r/20220809232012.403730-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/net/genetlink.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 7cb3fa8310ed..56a50e1c51b9 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -11,6 +11,7 @@ /** * struct genl_multicast_group - generic netlink multicast group * @name: name of the multicast group, names are per-family + * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM) */ struct genl_multicast_group { char name[GENL_NAMSIZ]; @@ -116,7 +117,7 @@ enum genl_validate_flags { * struct genl_small_ops - generic netlink operations (small version) * @cmd: command identifier * @internal_flags: flags used by the family - * @flags: flags + * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM) * @validate: validation flags from enum genl_validate_flags * @doit: standard command callback * @dumpit: callback for dumpers @@ -137,7 +138,7 @@ struct genl_small_ops { * struct genl_ops - generic netlink operations * @cmd: command identifier * @internal_flags: flags used by the family - * @flags: flags + * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM) * @maxattr: maximum number of attributes supported * @policy: netlink policy (takes precedence over family policy) * @validate: validation flags from enum genl_validate_flags -- cgit v1.2.3 From 0ff4eb3d5ebbf72a7fc355e6001a0a6740662bf9 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 11 Aug 2022 18:20:12 +0300 Subject: neighbour: make proxy_queue.qlen limit per-device Right now we have a neigh_param PROXY_QLEN which specifies maximum length of neigh_table->proxy_queue. But in fact, this limitation doesn't work well because check condition looks like: tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN) The problem is that p (struct neigh_parms) is a per-device thing, but tbl (struct neigh_table) is a system-wide global thing. It seems reasonable to make proxy_queue limit per-device based. v2: - nothing changed in this patch v3: - rebase to net tree Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Daniel Borkmann Cc: David Ahern Cc: Yajun Deng Cc: Roopa Prabhu Cc: Christian Brauner Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Alexey Kuznetsov Cc: Alexander Mikhalitsyn Cc: Konstantin Khorenko Cc: kernel@openvz.org Cc: devel@openvz.org Suggested-by: Denis V. Lunev Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 + net/core/neighbour.c | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 9f0bab0589d9..3827a6b395fd 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -83,6 +83,7 @@ struct neigh_parms { struct rcu_head rcu_head; int reachable_time; + int qlen; int data[NEIGH_VAR_DATA_MAX]; DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX); }; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0e38a05d5b23..5b669eb80270 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -316,9 +316,18 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net) skb = skb_peek(list); while (skb != NULL) { struct sk_buff *skb_next = skb_peek_next(skb, list); - if (net == NULL || net_eq(dev_net(skb->dev), net)) { + struct net_device *dev = skb->dev; + if (net == NULL || net_eq(dev_net(dev), net)) { + struct in_device *in_dev; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + if (in_dev) + in_dev->arp_parms->qlen--; + rcu_read_unlock(); __skb_unlink(skb, list); - dev_put(skb->dev); + + dev_put(dev); kfree_skb(skb); } skb = skb_next; @@ -1606,8 +1615,15 @@ static void neigh_proxy_process(struct timer_list *t) if (tdif <= 0) { struct net_device *dev = skb->dev; + struct in_device *in_dev; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + if (in_dev) + in_dev->arp_parms->qlen--; + rcu_read_unlock(); __skb_unlink(skb, &tbl->proxy_queue); + if (tbl->proxy_redo && netif_running(dev)) { rcu_read_lock(); tbl->proxy_redo(skb); @@ -1632,7 +1648,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, unsigned long sched_next = jiffies + prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY)); - if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) { + if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) { kfree_skb(skb); return; } @@ -1648,6 +1664,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, skb_dst_drop(skb); dev_hold(skb->dev); __skb_queue_tail(&tbl->proxy_queue, skb); + p->qlen++; mod_timer(&tbl->proxy_timer, sched_next); spin_unlock(&tbl->proxy_queue.lock); } @@ -1680,6 +1697,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, refcount_set(&p->refcnt, 1); p->reachable_time = neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); + p->qlen = 0; netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; write_pnet(&p->net, net); @@ -1745,6 +1763,7 @@ void neigh_table_init(int index, struct neigh_table *tbl) refcount_set(&tbl->parms.refcnt, 1); tbl->parms.reachable_time = neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); + tbl->parms.qlen = 0; tbl->stats = alloc_percpu(struct neigh_statistics); if (!tbl->stats) -- cgit v1.2.3 From fc4aaf9fb3c99bcb326d52f9d320ed5680bd1cee Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Aug 2022 10:34:40 +0100 Subject: net: Fix suspicious RCU usage in bpf_sk_reuseport_detach() bpf_sk_reuseport_detach() calls __rcu_dereference_sk_user_data_with_flags() to obtain the value of sk->sk_user_data, but that function is only usable if the RCU read lock is held, and neither that function nor any of its callers hold it. Fix this by adding a new helper, __locked_read_sk_user_data_with_flags() that checks to see if sk->sk_callback_lock() is held and use that here instead. Alternatively, making __rcu_dereference_sk_user_data_with_flags() use rcu_dereference_checked() might suffice. Without this, the following warning can be occasionally observed: ============================= WARNING: suspicious RCU usage 6.0.0-rc1-build2+ #563 Not tainted ----------------------------- include/net/sock.h:592 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 5 locks held by locktest/29873: #0: ffff88812734b550 (&sb->s_type->i_mutex_key#9){+.+.}-{3:3}, at: __sock_release+0x77/0x121 #1: ffff88812f5621b0 (sk_lock-AF_INET){+.+.}-{0:0}, at: tcp_close+0x1c/0x70 #2: ffff88810312f5c8 (&h->lhash2[i].lock){+.+.}-{2:2}, at: inet_unhash+0x76/0x1c0 #3: ffffffff83768bb8 (reuseport_lock){+...}-{2:2}, at: reuseport_detach_sock+0x18/0xdd #4: ffff88812f562438 (clock-AF_INET){++..}-{2:2}, at: bpf_sk_reuseport_detach+0x24/0xa4 stack backtrace: CPU: 1 PID: 29873 Comm: locktest Not tainted 6.0.0-rc1-build2+ #563 Hardware name: ASUS All Series/H97-PLUS, BIOS 2306 10/09/2014 Call Trace: dump_stack_lvl+0x4c/0x5f bpf_sk_reuseport_detach+0x6d/0xa4 reuseport_detach_sock+0x75/0xdd inet_unhash+0xa5/0x1c0 tcp_set_state+0x169/0x20f ? lockdep_sock_is_held+0x3a/0x3a ? __lock_release.isra.0+0x13e/0x220 ? reacquire_held_locks+0x1bb/0x1bb ? hlock_class+0x31/0x96 ? mark_lock+0x9e/0x1af __tcp_close+0x50/0x4b6 tcp_close+0x28/0x70 inet_release+0x8e/0xa7 __sock_release+0x95/0x121 sock_close+0x14/0x17 __fput+0x20f/0x36a task_work_run+0xa3/0xcc exit_to_user_mode_prepare+0x9c/0x14d syscall_exit_to_user_mode+0x18/0x44 entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: cf8c1e967224 ("net: refactor bpf_sk_reuseport_detach()") Signed-off-by: David Howells cc: Hawkins Jiawei Link: https://lore.kernel.org/r/166064248071.3502205.10036394558814861778.stgit@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- include/net/sock.h | 25 +++++++++++++++++++++++++ kernel/bpf/reuseport_array.c | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/sock.h b/include/net/sock.h index 05a1bbdf5805..d08cfe190a78 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -577,6 +577,31 @@ static inline bool sk_user_data_is_nocopy(const struct sock *sk) #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data))) +/** + * __locked_read_sk_user_data_with_flags - return the pointer + * only if argument flags all has been set in sk_user_data. Otherwise + * return NULL + * + * @sk: socket + * @flags: flag bits + * + * The caller must be holding sk->sk_callback_lock. + */ +static inline void * +__locked_read_sk_user_data_with_flags(const struct sock *sk, + uintptr_t flags) +{ + uintptr_t sk_user_data = + (uintptr_t)rcu_dereference_check(__sk_user_data(sk), + lockdep_is_held(&sk->sk_callback_lock)); + + WARN_ON_ONCE(flags & SK_USER_DATA_PTRMASK); + + if ((sk_user_data & flags) == flags) + return (void *)(sk_user_data & SK_USER_DATA_PTRMASK); + return NULL; +} + /** * __rcu_dereference_sk_user_data_with_flags - return the pointer * only if argument flags all has been set in sk_user_data. Otherwise diff --git a/kernel/bpf/reuseport_array.c b/kernel/bpf/reuseport_array.c index 85fa9dbfa8bf..82c61612f382 100644 --- a/kernel/bpf/reuseport_array.c +++ b/kernel/bpf/reuseport_array.c @@ -24,7 +24,7 @@ void bpf_sk_reuseport_detach(struct sock *sk) struct sock __rcu **socks; write_lock_bh(&sk->sk_callback_lock); - socks = __rcu_dereference_sk_user_data_with_flags(sk, SK_USER_DATA_BPF); + socks = __locked_read_sk_user_data_with_flags(sk, SK_USER_DATA_BPF); if (socks) { WRITE_ONCE(sk->sk_user_data, NULL); /* -- cgit v1.2.3 From 7ec9fce4b31604f8415136a4c07f7dc8ad431aec Mon Sep 17 00:00:00 2001 From: Eyal Birger Date: Thu, 18 Aug 2022 10:41:18 +0300 Subject: ip_tunnel: Respect tunnel key's "flow_flags" in IP tunnels Commit 451ef36bd229 ("ip_tunnels: Add new flow flags field to ip_tunnel_key") added a "flow_flags" member to struct ip_tunnel_key which was later used by the commit in the fixes tag to avoid dropping packets with sources that aren't locally configured when set in bpf_set_tunnel_key(). VXLAN and GENEVE were made to respect this flag, ip tunnels like IPIP and GRE were not. This commit fixes this omission by making ip_tunnel_init_flow() receive the flow flags from the tunnel key in the relevant collect_md paths. Fixes: b8fff748521c ("bpf: Set flow flag to allow any source IP in bpf_tunnel_key") Signed-off-by: Eyal Birger Signed-off-by: Daniel Borkmann Reviewed-by: Paul Chaignon Link: https://lore.kernel.org/bpf/20220818074118.726639-1-eyal.birger@gmail.com --- drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c | 3 ++- include/net/ip_tunnels.h | 4 +++- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_tunnel.c | 7 ++++--- 4 files changed, 10 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 39904dacf4f0..b3472fb94617 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -423,7 +423,8 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev, parms = mlxsw_sp_ipip_netdev_parms4(to_dev); ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp, - 0, 0, dev_net(to_dev), parms.link, tun->fwmark, 0); + 0, 0, dev_net(to_dev), parms.link, tun->fwmark, 0, + 0); rt = ip_route_output_key(tun->net, &fl4); if (IS_ERR(rt)) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 63fac94f9ace..ced80e2f8b58 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -246,7 +246,8 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4, __be32 daddr, __be32 saddr, __be32 key, __u8 tos, struct net *net, int oif, - __u32 mark, __u32 tun_inner_hash) + __u32 mark, __u32 tun_inner_hash, + __u8 flow_flags) { memset(fl4, 0, sizeof(*fl4)); @@ -263,6 +264,7 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4, fl4->fl4_gre_key = key; fl4->flowi4_mark = mark; fl4->flowi4_multipath_hash = tun_inner_hash; + fl4->flowi4_flags = flow_flags; } int ip_tunnel_init(struct net_device *dev); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5c58e21f724e..f866d6282b2b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -609,7 +609,7 @@ static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src, tunnel_id_to_key32(key->tun_id), key->tos & ~INET_ECN_MASK, dev_net(dev), 0, - skb->mark, skb_get_hash(skb)); + skb->mark, skb_get_hash(skb), key->flow_flags); rt = ip_route_output_key(dev_net(dev), &fl4); if (IS_ERR(rt)) return PTR_ERR(rt); diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e65e948cab9f..019f3b0839c5 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -295,7 +295,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev) ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr, iph->saddr, tunnel->parms.o_key, RT_TOS(iph->tos), dev_net(dev), - tunnel->parms.link, tunnel->fwmark, 0); + tunnel->parms.link, tunnel->fwmark, 0, 0); rt = ip_route_output_key(tunnel->net, &fl4); if (!IS_ERR(rt)) { @@ -570,7 +570,8 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, } ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, tunnel_id_to_key32(key->tun_id), RT_TOS(tos), - dev_net(dev), 0, skb->mark, skb_get_hash(skb)); + dev_net(dev), 0, skb->mark, skb_get_hash(skb), + key->flow_flags); if (tunnel->encap.type != TUNNEL_ENCAP_NONE) goto tx_error; @@ -729,7 +730,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr, tunnel->parms.o_key, RT_TOS(tos), dev_net(dev), tunnel->parms.link, - tunnel->fwmark, skb_get_hash(skb)); + tunnel->fwmark, skb_get_hash(skb), 0); if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) goto tx_error; -- cgit v1.2.3 From f2e44dffa97f2e1c222a959ea5b6e604548b891b Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Fri, 19 Aug 2022 11:15:14 -0400 Subject: bonding: 3ad: make ad_ticks_per_sec a const The value is only ever set once in bond_3ad_initialize and only ever read otherwise. There seems to be no reason to set the variable via bond_3ad_initialize when setting the global variable will do. Change ad_ticks_per_sec to a const to enforce its read-only usage. Signed-off-by: Jonathan Toppins Acked-by: Jay Vosburgh Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_3ad.c | 11 +++-------- drivers/net/bonding/bond_main.c | 2 +- include/net/bond_3ad.h | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include/net') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 1f0120cbe9e8..184608bd8999 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -84,7 +84,8 @@ enum ad_link_speed_type { static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { 0, 0, 0, 0, 0, 0 }; -static u16 ad_ticks_per_sec; + +static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; static const u8 lacpdu_mcast_addr[ETH_ALEN + 2] __long_aligned = @@ -2001,11 +2002,10 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout) /** * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures * @bond: bonding struct to work on - * @tick_resolution: tick duration (millisecond resolution) * * Can be called only after the mac address of the bond is set. */ -void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) +void bond_3ad_initialize(struct bonding *bond) { BOND_AD_INFO(bond).aggregator_identifier = 0; BOND_AD_INFO(bond).system.sys_priority = @@ -2017,11 +2017,6 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->params.ad_actor_system); - /* initialize how many times this module is called in one - * second (should be about every 100ms) - */ - ad_ticks_per_sec = tick_resolution; - bond_3ad_initiate_agg_selection(bond, AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 50e60843020c..2f4da2c13c0a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2081,7 +2081,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set */ - bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL); + bond_3ad_initialize(bond); } else { SLAVE_AD_INFO(new_slave)->id = SLAVE_AD_INFO(prev_slave)->id + 1; diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h index 184105d68294..be2992e6de5d 100644 --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h @@ -290,7 +290,7 @@ static inline const char *bond_3ad_churn_desc(churn_state_t state) } /* ========== AD Exported functions to the main bonding code ========== */ -void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution); +void bond_3ad_initialize(struct bonding *bond); void bond_3ad_bind_slave(struct slave *slave); void bond_3ad_unbind_slave(struct slave *slave); void bond_3ad_state_machine_handler(struct work_struct *); -- cgit v1.2.3 From ab482c6b66a4a8c0a8c0b0f577a785cf9ff1c2e2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Aug 2022 10:52:48 +0200 Subject: netfilter: nf_tables: make table handle allocation per-netns friendly mutex is per-netns, move table_netns to the pernet area. *read-write* to 0xffffffff883a01e8 of 8 bytes by task 6542 on cpu 0: nf_tables_newtable+0x6dc/0xc00 net/netfilter/nf_tables_api.c:1221 nfnetlink_rcv_batch net/netfilter/nfnetlink.c:513 [inline] nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:634 [inline] nfnetlink_rcv+0xa6a/0x13a0 net/netfilter/nfnetlink.c:652 netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline] netlink_unicast+0x652/0x730 net/netlink/af_netlink.c:1345 netlink_sendmsg+0x643/0x740 net/netlink/af_netlink.c:1921 Fixes: f102d66b335a ("netfilter: nf_tables: use dedicated mutex to guard transactions") Reported-by: Abhishek Shah Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 1 + net/netfilter/nf_tables_api.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 99aae36c04b9..cdb7db9b0e25 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1652,6 +1652,7 @@ struct nftables_pernet { struct list_head module_list; struct list_head notify_list; struct mutex commit_mutex; + u64 table_handle; unsigned int base_seq; u8 validate_state; }; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index dff2b5851bbb..0951f31caabe 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -32,7 +32,6 @@ static LIST_HEAD(nf_tables_objects); static LIST_HEAD(nf_tables_flowtables); static LIST_HEAD(nf_tables_destroy_list); static DEFINE_SPINLOCK(nf_tables_destroy_list_lock); -static u64 table_handle; enum { NFT_VALIDATE_SKIP = 0, @@ -1235,7 +1234,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info, INIT_LIST_HEAD(&table->flowtables); table->family = family; table->flags = flags; - table->handle = ++table_handle; + table->handle = ++nft_net->table_handle; if (table->flags & NFT_TABLE_F_OWNER) table->nlpid = NETLINK_CB(skb).portid; -- cgit v1.2.3 From 759eebbcfafcefa23b59e912396306543764bd3c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 22 Aug 2022 23:13:00 +0200 Subject: netfilter: flowtable: add function to invoke garbage collection immediately Expose nf_flow_table_gc_run() to force a garbage collector run from the offload infrastructure. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_flow_table.h | 1 + net/netfilter/nf_flow_table_core.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index d5326c44b453..476cc4423a90 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -270,6 +270,7 @@ void flow_offload_refresh(struct nf_flowtable *flow_table, struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table, struct flow_offload_tuple *tuple); +void nf_flow_table_gc_run(struct nf_flowtable *flow_table); void nf_flow_table_gc_cleanup(struct nf_flowtable *flowtable, struct net_device *dev); void nf_flow_table_cleanup(struct net_device *dev); diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 765ac779bfc8..60fc1e1b7182 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -437,12 +437,17 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table, } } +void nf_flow_table_gc_run(struct nf_flowtable *flow_table) +{ + nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL); +} + static void nf_flow_offload_work_gc(struct work_struct *work) { struct nf_flowtable *flow_table; flow_table = container_of(work, struct nf_flowtable, gc_work.work); - nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL); + nf_flow_table_gc_run(flow_table); queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ); } @@ -601,10 +606,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) cancel_delayed_work_sync(&flow_table->gc_work); nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); - nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL); + nf_flow_table_gc_run(flow_table); nf_flow_table_offload_flush(flow_table); if (nf_flowtable_hw_offload(flow_table)) - nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, NULL); + nf_flow_table_gc_run(flow_table); + rhashtable_destroy(&flow_table->rhashtable); } EXPORT_SYMBOL_GPL(nf_flow_table_free); -- cgit v1.2.3 From 9afb4b27349a499483ae0134282cefd0c90f480f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 18 Nov 2021 22:24:15 +0100 Subject: netfilter: flowtable: fix stuck flows on cleanup due to pending work To clear the flow table on flow table free, the following sequence normally happens in order: 1) gc_step work is stopped to disable any further stats/del requests. 2) All flow table entries are set to teardown state. 3) Run gc_step which will queue HW del work for each flow table entry. 4) Waiting for the above del work to finish (flush). 5) Run gc_step again, deleting all entries from the flow table. 6) Flow table is freed. But if a flow table entry already has pending HW stats or HW add work step 3 will not queue HW del work (it will be skipped), step 4 will wait for the pending add/stats to finish, and step 5 will queue HW del work which might execute after freeing of the flow table. To fix the above, this patch flushes the pending work, then it sets the teardown flag to all flows in the flowtable and it forces a garbage collector run to queue work to remove the flows from hardware, then it flushes this new pending work and (finally) it forces another garbage collector run to remove the entry from the software flowtable. Stack trace: [47773.882335] BUG: KASAN: use-after-free in down_read+0x99/0x460 [47773.883634] Write of size 8 at addr ffff888103b45aa8 by task kworker/u20:6/543704 [47773.885634] CPU: 3 PID: 543704 Comm: kworker/u20:6 Not tainted 5.12.0-rc7+ #2 [47773.886745] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) [47773.888438] Workqueue: nf_ft_offload_del flow_offload_work_handler [nf_flow_table] [47773.889727] Call Trace: [47773.890214] dump_stack+0xbb/0x107 [47773.890818] print_address_description.constprop.0+0x18/0x140 [47773.892990] kasan_report.cold+0x7c/0xd8 [47773.894459] kasan_check_range+0x145/0x1a0 [47773.895174] down_read+0x99/0x460 [47773.899706] nf_flow_offload_tuple+0x24f/0x3c0 [nf_flow_table] [47773.907137] flow_offload_work_handler+0x72d/0xbe0 [nf_flow_table] [47773.913372] process_one_work+0x8ac/0x14e0 [47773.921325] [47773.921325] Allocated by task 592159: [47773.922031] kasan_save_stack+0x1b/0x40 [47773.922730] __kasan_kmalloc+0x7a/0x90 [47773.923411] tcf_ct_flow_table_get+0x3cb/0x1230 [act_ct] [47773.924363] tcf_ct_init+0x71c/0x1156 [act_ct] [47773.925207] tcf_action_init_1+0x45b/0x700 [47773.925987] tcf_action_init+0x453/0x6b0 [47773.926692] tcf_exts_validate+0x3d0/0x600 [47773.927419] fl_change+0x757/0x4a51 [cls_flower] [47773.928227] tc_new_tfilter+0x89a/0x2070 [47773.936652] [47773.936652] Freed by task 543704: [47773.937303] kasan_save_stack+0x1b/0x40 [47773.938039] kasan_set_track+0x1c/0x30 [47773.938731] kasan_set_free_info+0x20/0x30 [47773.939467] __kasan_slab_free+0xe7/0x120 [47773.940194] slab_free_freelist_hook+0x86/0x190 [47773.941038] kfree+0xce/0x3a0 [47773.941644] tcf_ct_flow_table_cleanup_work Original patch description and stack trace by Paul Blakey. Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support") Reported-by: Paul Blakey Tested-by: Paul Blakey Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_flow_table.h | 2 ++ net/netfilter/nf_flow_table_core.c | 7 +++---- net/netfilter/nf_flow_table_offload.c | 8 ++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index 476cc4423a90..cd982f4a0f50 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -307,6 +307,8 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable, struct flow_offload *flow); void nf_flow_table_offload_flush(struct nf_flowtable *flowtable); +void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable); + int nf_flow_table_offload_setup(struct nf_flowtable *flowtable, struct net_device *dev, enum flow_block_command cmd); diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 60fc1e1b7182..81c26a96c30b 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -605,12 +605,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) mutex_unlock(&flowtable_lock); cancel_delayed_work_sync(&flow_table->gc_work); + nf_flow_table_offload_flush(flow_table); + /* ... no more pending work after this stage ... */ nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); nf_flow_table_gc_run(flow_table); - nf_flow_table_offload_flush(flow_table); - if (nf_flowtable_hw_offload(flow_table)) - nf_flow_table_gc_run(flow_table); - + nf_flow_table_offload_flush_cleanup(flow_table); rhashtable_destroy(&flow_table->rhashtable); } EXPORT_SYMBOL_GPL(nf_flow_table_free); diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index 103b6cbf257f..b04645ced89b 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -1074,6 +1074,14 @@ void nf_flow_offload_stats(struct nf_flowtable *flowtable, flow_offload_queue_work(offload); } +void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable) +{ + if (nf_flowtable_hw_offload(flowtable)) { + flush_workqueue(nf_flow_offload_del_wq); + nf_flow_table_gc_run(flowtable); + } +} + void nf_flow_table_offload_flush(struct nf_flowtable *flowtable) { if (nf_flowtable_hw_offload(flowtable)) { -- cgit v1.2.3 From c42b7cddea47503411bfb5f2f93a4154aaffa2d9 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Aug 2022 10:46:51 -0700 Subject: net: Fix a data-race around sysctl_net_busy_poll. While reading sysctl_net_busy_poll, it can be changed concurrently. Thus, we need to add READ_ONCE() to its reader. Fixes: 060212928670 ("net: add low latency socket poll") Signed-off-by: Kuniyuki Iwashima Signed-off-by: David S. Miller --- include/net/busy_poll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h index c4898fcbf923..f90f0021f5f2 100644 --- a/include/net/busy_poll.h +++ b/include/net/busy_poll.h @@ -33,7 +33,7 @@ extern unsigned int sysctl_net_busy_poll __read_mostly; static inline bool net_busy_loop_on(void) { - return sysctl_net_busy_poll; + return READ_ONCE(sysctl_net_busy_poll); } static inline bool sk_can_busy_loop(const struct sock *sk) -- cgit v1.2.3 From 8db24af3f02ebdbf302196006ebb270c4c3a2706 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 23 Aug 2022 10:46:58 -0700 Subject: net: Fix a data-race around gro_normal_batch. While reading gro_normal_batch, it can be changed concurrently. Thus, we need to add READ_ONCE() to its reader. Fixes: 323ebb61e32b ("net: use listified RX for handling GRO_NORMAL skbs") Signed-off-by: Kuniyuki Iwashima Acked-by: Edward Cree Signed-off-by: David S. Miller --- include/net/gro.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/gro.h b/include/net/gro.h index 867656b0739c..24003dea8fa4 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -439,7 +439,7 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb, { list_add_tail(&skb->list, &napi->rx_list); napi->rx_count += segs; - if (napi->rx_count >= gro_normal_batch) + if (napi->rx_count >= READ_ONCE(gro_normal_batch)) gro_normal_list(napi); } -- cgit v1.2.3 From b118509076b39cc5e616c0680312b5caaca535fe Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 26 Aug 2022 08:49:16 +0200 Subject: netfilter: remove nf_conntrack_helper sysctl and modparam toggles __nf_ct_try_assign_helper() remains in place but it now requires a template to configure the helper. A toggle to disable automatic helper assignment was added by: a9006892643a ("netfilter: nf_ct_helper: allow to disable automatic helper assignment") in 2012 to address the issues described in "Secure use of iptables and connection tracking helpers". Automatic conntrack helper assignment was disabled by: 3bb398d925ec ("netfilter: nf_ct_helper: disable automatic helper assignment") back in 2016. This patch removes the sysctl and modparam toggles, users now have to rely on explicit conntrack helper configuration via ruleset. Update tools/testing/selftests/netfilter/nft_conntrack_helper.sh to check that auto-assignment does not happen anymore. Acked-by: Aaron Conole Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack.h | 2 - include/net/netns/conntrack.h | 1 - net/netfilter/nf_conntrack_core.c | 7 +- net/netfilter/nf_conntrack_helper.c | 80 +++------------------- net/netfilter/nf_conntrack_netlink.c | 5 -- net/netfilter/nf_conntrack_standalone.c | 10 --- net/netfilter/nft_ct.c | 3 - .../selftests/netfilter/nft_conntrack_helper.sh | 36 +++++++--- 8 files changed, 37 insertions(+), 107 deletions(-) (limited to 'include/net') diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index a32be8aa7ed2..6a2019aaa464 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -53,8 +53,6 @@ struct nf_conntrack_net { /* only used when new connection is allocated: */ atomic_t count; unsigned int expect_count; - u8 sysctl_auto_assign_helper; - bool auto_assign_helper_warned; /* only used from work queues, configuration plane, and so on: */ unsigned int users4; diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index c396a3862e80..e1290c159184 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -101,7 +101,6 @@ struct netns_ct { u8 sysctl_log_invalid; /* Log invalid packets */ u8 sysctl_events; u8 sysctl_acct; - u8 sysctl_auto_assign_helper; u8 sysctl_tstamp; u8 sysctl_checksum; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 71c2f4f95d36..1357a2729a4b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1782,7 +1782,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, } spin_unlock_bh(&nf_conntrack_expect_lock); } - if (!exp) + if (!exp && tmpl) __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); /* Other CPU might have obtained a pointer to this object before it was @@ -2068,10 +2068,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; if (ct->master || (help && !hlist_empty(&help->expectations))) return; - - rcu_read_lock(); - __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); @@ -2797,7 +2793,6 @@ int nf_conntrack_init_net(struct net *net) nf_conntrack_acct_pernet_init(net); nf_conntrack_tstamp_pernet_init(net); nf_conntrack_ecache_pernet_init(net); - nf_conntrack_helper_pernet_init(net); nf_conntrack_proto_pernet_init(net); return 0; diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index e96b32221444..ff737a76052e 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -35,11 +35,6 @@ unsigned int nf_ct_helper_hsize __read_mostly; EXPORT_SYMBOL_GPL(nf_ct_helper_hsize); static unsigned int nf_ct_helper_count __read_mostly; -static bool nf_ct_auto_assign_helper __read_mostly = false; -module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644); -MODULE_PARM_DESC(nf_conntrack_helper, - "Enable automatic conntrack helper assignment (default 0)"); - static DEFINE_MUTEX(nf_ct_nat_helpers_mutex); static struct list_head nf_ct_nat_helpers __read_mostly; @@ -51,24 +46,6 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize; } -static struct nf_conntrack_helper * -__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) -{ - struct nf_conntrack_helper *helper; - struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; - unsigned int h; - - if (!nf_ct_helper_count) - return NULL; - - h = helper_hash(tuple); - hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) { - if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) - return helper; - } - return NULL; -} - struct nf_conntrack_helper * __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum) { @@ -209,33 +186,11 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) } EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); -static struct nf_conntrack_helper * -nf_ct_lookup_helper(struct nf_conn *ct, struct net *net) -{ - struct nf_conntrack_net *cnet = nf_ct_pernet(net); - - if (!cnet->sysctl_auto_assign_helper) { - if (cnet->auto_assign_helper_warned) - return NULL; - if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)) - return NULL; - pr_info("nf_conntrack: default automatic helper assignment " - "has been turned off for security reasons and CT-based " - "firewall rule not found. Use the iptables CT target " - "to attach helpers instead.\n"); - cnet->auto_assign_helper_warned = true; - return NULL; - } - - return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); -} - int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, gfp_t flags) { struct nf_conntrack_helper *helper = NULL; struct nf_conn_help *help; - struct net *net = nf_ct_net(ct); /* We already got a helper explicitly attached. The function * nf_conntrack_alter_reply - in case NAT is in use - asks for looking @@ -246,23 +201,21 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, if (test_bit(IPS_HELPER_BIT, &ct->status)) return 0; - if (tmpl != NULL) { - help = nfct_help(tmpl); - if (help != NULL) { - helper = rcu_dereference(help->helper); - set_bit(IPS_HELPER_BIT, &ct->status); - } + if (WARN_ON_ONCE(!tmpl)) + return 0; + + help = nfct_help(tmpl); + if (help != NULL) { + helper = rcu_dereference(help->helper); + set_bit(IPS_HELPER_BIT, &ct->status); } help = nfct_help(ct); if (helper == NULL) { - helper = nf_ct_lookup_helper(ct, net); - if (helper == NULL) { - if (help) - RCU_INIT_POINTER(help->helper, NULL); - return 0; - } + if (help) + RCU_INIT_POINTER(help->helper, NULL); + return 0; } if (help == NULL) { @@ -545,19 +498,6 @@ void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat) } EXPORT_SYMBOL_GPL(nf_nat_helper_unregister); -void nf_ct_set_auto_assign_helper_warned(struct net *net) -{ - nf_ct_pernet(net)->auto_assign_helper_warned = true; -} -EXPORT_SYMBOL_GPL(nf_ct_set_auto_assign_helper_warned); - -void nf_conntrack_helper_pernet_init(struct net *net) -{ - struct nf_conntrack_net *cnet = nf_ct_pernet(net); - - cnet->sysctl_auto_assign_helper = nf_ct_auto_assign_helper; -} - int nf_conntrack_helper_init(void) { nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 04169b54f2a2..7562b215b932 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2298,11 +2298,6 @@ ctnetlink_create_conntrack(struct net *net, ct->status |= IPS_HELPER; RCU_INIT_POINTER(help->helper, helper); } - } else { - /* try an implicit helper assignation */ - err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); - if (err < 0) - goto err2; } err = ctnetlink_setup_nat(ct, cda); diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 05895878610c..4ffe84c5a82c 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -561,7 +561,6 @@ enum nf_ct_sysctl_index { NF_SYSCTL_CT_LOG_INVALID, NF_SYSCTL_CT_EXPECT_MAX, NF_SYSCTL_CT_ACCT, - NF_SYSCTL_CT_HELPER, #ifdef CONFIG_NF_CONNTRACK_EVENTS NF_SYSCTL_CT_EVENTS, #endif @@ -680,14 +679,6 @@ static struct ctl_table nf_ct_sysctl_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, - [NF_SYSCTL_CT_HELPER] = { - .procname = "nf_conntrack_helper", - .maxlen = sizeof(u8), - .mode = 0644, - .proc_handler = proc_dou8vec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, #ifdef CONFIG_NF_CONNTRACK_EVENTS [NF_SYSCTL_CT_EVENTS] = { .procname = "nf_conntrack_events", @@ -1100,7 +1091,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum; table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid; table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct; - table[NF_SYSCTL_CT_HELPER].data = &cnet->sysctl_auto_assign_helper; #ifdef CONFIG_NF_CONNTRACK_EVENTS table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events; #endif diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index b04995c3e17f..a3f01f209a53 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -1089,9 +1089,6 @@ static int nft_ct_helper_obj_init(const struct nft_ctx *ctx, if (err < 0) goto err_put_helper; - /* Avoid the bogus warning, helper will be assigned after CT init */ - nf_ct_set_auto_assign_helper_warned(ctx->net); - return 0; err_put_helper: diff --git a/tools/testing/selftests/netfilter/nft_conntrack_helper.sh b/tools/testing/selftests/netfilter/nft_conntrack_helper.sh index bf6b9626c7dd..faa7778d7bd1 100755 --- a/tools/testing/selftests/netfilter/nft_conntrack_helper.sh +++ b/tools/testing/selftests/netfilter/nft_conntrack_helper.sh @@ -102,26 +102,42 @@ check_for_helper() ip netns exec ${netns} conntrack -L -f $family -p tcp --dport $port 2> /dev/null |grep -q 'helper=ftp' if [ $? -ne 0 ] ; then - echo "FAIL: ${netns} did not show attached helper $message" 1>&2 - ret=1 + if [ $autoassign -eq 0 ] ;then + echo "FAIL: ${netns} did not show attached helper $message" 1>&2 + ret=1 + else + echo "PASS: ${netns} did not show attached helper $message" 1>&2 + fi + else + if [ $autoassign -eq 0 ] ;then + echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2 + else + echo "FAIL: ${netns} connection on port $port has ftp helper attached" 1>&2 + ret=1 + fi fi - echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2 return 0 } test_helper() { local port=$1 - local msg=$2 + local autoassign=$2 + + if [ $autoassign -eq 0 ] ;then + msg="set via ruleset" + else + msg="auto-assign" + fi sleep 3 | ip netns exec ${ns2} nc -w 2 -l -p $port > /dev/null & sleep 1 | ip netns exec ${ns1} nc -w 2 10.0.1.2 $port > /dev/null & sleep 1 - check_for_helper "$ns1" "ip $msg" $port - check_for_helper "$ns2" "ip $msg" $port + check_for_helper "$ns1" "ip $msg" $port $autoassign + check_for_helper "$ns2" "ip $msg" $port $autoassign wait @@ -173,9 +189,9 @@ if [ $? -ne 0 ];then fi fi -test_helper 2121 "set via ruleset" -ip netns exec ${ns1} sysctl -q 'net.netfilter.nf_conntrack_helper=1' -ip netns exec ${ns2} sysctl -q 'net.netfilter.nf_conntrack_helper=1' -test_helper 21 "auto-assign" +test_helper 2121 0 +ip netns exec ${ns1} sysctl -qe 'net.netfilter.nf_conntrack_helper=1' +ip netns exec ${ns2} sysctl -qe 'net.netfilter.nf_conntrack_helper=1' +test_helper 21 1 exit $ret -- cgit v1.2.3 From 79e3602caa6f9d59c4f66a268407080496dae408 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 30 Aug 2022 11:56:56 -0700 Subject: tcp: make global challenge ack rate limitation per net-ns and default disabled Because per host rate limiting has been proven problematic (side channel attacks can be based on it), per host rate limiting of challenge acks ideally should be per netns and turned off by default. This is a long due followup of following commits: 083ae308280d ("tcp: enable per-socket rate limiting of all 'challenge acks'") f2b2c582e824 ("tcp: mitigate ACK loops for connections as tcp_sock") 75ff39ccc1bd ("tcp: make challenge acks less predictable") Signed-off-by: Eric Dumazet Cc: Jason Baron Acked-by: Neal Cardwell Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 5 ++++- include/net/netns/ipv4.h | 2 ++ net/ipv4/tcp_input.c | 21 +++++++++++---------- net/ipv4/tcp_ipv4.c | 6 ++++-- 4 files changed, 21 insertions(+), 13 deletions(-) (limited to 'include/net') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 56cd4ea059b2..a759872a2883 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -1035,7 +1035,10 @@ tcp_limit_output_bytes - INTEGER tcp_challenge_ack_limit - INTEGER Limits number of Challenge ACK sent per second, as recommended in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) - Default: 1000 + Note that this per netns rate limit can allow some side channel + attacks and probably should not be enabled. + TCP stack implements per TCP socket limits anyway. + Default: INT_MAX (unlimited) UDP variables ============= diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index c7320ef356d9..6320a76cefdc 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -179,6 +179,8 @@ struct netns_ipv4 { unsigned int sysctl_tcp_fastopen_blackhole_timeout; atomic_t tfo_active_disable_times; unsigned long tfo_active_disable_stamp; + u32 tcp_challenge_timestamp; + u32 tcp_challenge_count; int sysctl_udp_wmem_min; int sysctl_udp_rmem_min; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c184e15397a2..b85a9f755da4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3614,12 +3614,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, /* RFC 5961 7 [ACK Throttling] */ static void tcp_send_challenge_ack(struct sock *sk) { - /* unprotected vars, we dont care of overwrites */ - static u32 challenge_timestamp; - static unsigned int challenge_count; struct tcp_sock *tp = tcp_sk(sk); struct net *net = sock_net(sk); - u32 count, now; + u32 count, now, ack_limit; /* First check our per-socket dupack rate limit. */ if (__tcp_oow_rate_limited(net, @@ -3627,18 +3624,22 @@ static void tcp_send_challenge_ack(struct sock *sk) &tp->last_oow_ack_time)) return; + ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); + if (ack_limit == INT_MAX) + goto send_ack; + /* Then check host-wide RFC 5961 rate limit. */ now = jiffies / HZ; - if (now != READ_ONCE(challenge_timestamp)) { - u32 ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); + if (now != READ_ONCE(net->ipv4.tcp_challenge_timestamp)) { u32 half = (ack_limit + 1) >> 1; - WRITE_ONCE(challenge_timestamp, now); - WRITE_ONCE(challenge_count, half + prandom_u32_max(ack_limit)); + WRITE_ONCE(net->ipv4.tcp_challenge_timestamp, now); + WRITE_ONCE(net->ipv4.tcp_challenge_count, half + prandom_u32_max(ack_limit)); } - count = READ_ONCE(challenge_count); + count = READ_ONCE(net->ipv4.tcp_challenge_count); if (count > 0) { - WRITE_ONCE(challenge_count, count - 1); + WRITE_ONCE(net->ipv4.tcp_challenge_count, count - 1); +send_ack: NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK); tcp_send_ack(sk); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0c83780dc9bf..5b019ba2b9d2 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3139,8 +3139,10 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_tso_win_divisor = 3; /* Default TSQ limit of 16 TSO segments */ net->ipv4.sysctl_tcp_limit_output_bytes = 16 * 65536; - /* rfc5961 challenge ack rate limiting */ - net->ipv4.sysctl_tcp_challenge_ack_limit = 1000; + + /* rfc5961 challenge ack rate limiting, per net-ns, disabled by default. */ + net->ipv4.sysctl_tcp_challenge_ack_limit = INT_MAX; + net->ipv4.sysctl_tcp_min_tso_segs = 2; net->ipv4.sysctl_tcp_tso_rtt_log = 9; /* 2^9 = 512 usec */ net->ipv4.sysctl_tcp_min_rtt_wlen = 300; -- cgit v1.2.3 From ac56a0b48da86fd1b4389632fb7c4c8a5d86eefa Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 26 Aug 2022 15:39:28 +0100 Subject: rxrpc: Fix ICMP/ICMP6 error handling Because rxrpc pretends to be a tunnel on top of a UDP/UDP6 socket, allowing it to siphon off UDP packets early in the handling of received UDP packets thereby avoiding the packet going through the UDP receive queue, it doesn't get ICMP packets through the UDP ->sk_error_report() callback. In fact, it doesn't appear that there's any usable option for getting hold of ICMP packets. Fix this by adding a new UDP encap hook to distribute error messages for UDP tunnels. If the hook is set, then the tunnel driver will be able to see ICMP packets. The hook provides the offset into the packet of the UDP header of the original packet that caused the notification. An alternative would be to call the ->error_handler() hook - but that requires that the skbuff be cloned (as ip_icmp_error() or ipv6_cmp_error() do, though isn't really necessary or desirable in rxrpc's case is we want to parse them there and then, not queue them). Changes ======= ver #3) - Fixed an uninitialised variable. ver #2) - Fixed some missing CONFIG_AF_RXRPC_IPV6 conditionals. Fixes: 5271953cad31 ("rxrpc: Use the UDP encap_rcv hook") Signed-off-by: David Howells --- include/linux/udp.h | 1 + include/net/udp_tunnel.h | 4 + net/ipv4/udp.c | 2 + net/ipv4/udp_tunnel_core.c | 1 + net/ipv6/udp.c | 5 +- net/rxrpc/ar-internal.h | 1 + net/rxrpc/local_object.c | 1 + net/rxrpc/peer_event.c | 293 +++++++++++++++++++++++++++++++++++++++------ 8 files changed, 270 insertions(+), 38 deletions(-) (limited to 'include/net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 254a2654400f..e96da4157d04 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -70,6 +70,7 @@ struct udp_sock { * For encapsulation sockets. */ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); + void (*encap_err_rcv)(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset); int (*encap_err_lookup)(struct sock *sk, struct sk_buff *skb); void (*encap_destroy)(struct sock *sk); diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index afc7ce713657..72394f441dad 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -67,6 +67,9 @@ static inline int udp_sock_create(struct net *net, typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb); typedef int (*udp_tunnel_encap_err_lookup_t)(struct sock *sk, struct sk_buff *skb); +typedef void (*udp_tunnel_encap_err_rcv_t)(struct sock *sk, + struct sk_buff *skb, + unsigned int udp_offset); typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk); typedef struct sk_buff *(*udp_tunnel_gro_receive_t)(struct sock *sk, struct list_head *head, @@ -80,6 +83,7 @@ struct udp_tunnel_sock_cfg { __u8 encap_type; udp_tunnel_encap_rcv_t encap_rcv; udp_tunnel_encap_err_lookup_t encap_err_lookup; + udp_tunnel_encap_err_rcv_t encap_err_rcv; udp_tunnel_encap_destroy_t encap_destroy; udp_tunnel_gro_receive_t gro_receive; udp_tunnel_gro_complete_t gro_complete; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 34eda973bbf1..cd72158e953a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -783,6 +783,8 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) */ if (tunnel) { /* ...not for tunnels though: we don't have a sending socket */ + if (udp_sk(sk)->encap_err_rcv) + udp_sk(sk)->encap_err_rcv(sk, skb, iph->ihl << 2); goto out; } if (!inet->recverr) { diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index 8efaf8c3fe2a..8242c8947340 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -72,6 +72,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, udp_sk(sk)->encap_type = cfg->encap_type; udp_sk(sk)->encap_rcv = cfg->encap_rcv; + udp_sk(sk)->encap_err_rcv = cfg->encap_err_rcv; udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup; udp_sk(sk)->encap_destroy = cfg->encap_destroy; udp_sk(sk)->gro_receive = cfg->gro_receive; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 16c176e7c69a..3366d6a77ff2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -616,8 +616,11 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, } /* Tunnels don't have an application socket: don't pass errors back */ - if (tunnel) + if (tunnel) { + if (udp_sk(sk)->encap_err_rcv) + udp_sk(sk)->encap_err_rcv(sk, skb, offset); goto out; + } if (!np->recverr) { if (!harderr || sk->sk_state != TCP_ESTABLISHED) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 571436064cd6..62c70709d798 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -982,6 +982,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *); /* * peer_event.c */ +void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, unsigned int udp_offset); void rxrpc_error_report(struct sock *); void rxrpc_peer_keepalive_worker(struct work_struct *); diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 96ecb7356c0f..79bb02eb67b2 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -137,6 +137,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) tuncfg.encap_type = UDP_ENCAP_RXRPC; tuncfg.encap_rcv = rxrpc_input_packet; + tuncfg.encap_err_rcv = rxrpc_encap_err_rcv; tuncfg.sk_user_data = local; setup_udp_tunnel_sock(net, local->socket, &tuncfg); diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c index be032850ae8c..32561e9567fe 100644 --- a/net/rxrpc/peer_event.c +++ b/net/rxrpc/peer_event.c @@ -16,22 +16,105 @@ #include #include #include +#include #include "ar-internal.h" +static void rxrpc_adjust_mtu(struct rxrpc_peer *, unsigned int); static void rxrpc_store_error(struct rxrpc_peer *, struct sock_exterr_skb *); static void rxrpc_distribute_error(struct rxrpc_peer *, int, enum rxrpc_call_completion); /* - * Find the peer associated with an ICMP packet. + * Find the peer associated with an ICMPv4 packet. */ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, - const struct sk_buff *skb, + struct sk_buff *skb, + unsigned int udp_offset, + unsigned int *info, struct sockaddr_rxrpc *srx) { - struct sock_exterr_skb *serr = SKB_EXT_ERR(skb); + struct iphdr *ip, *ip0 = ip_hdr(skb); + struct icmphdr *icmp = icmp_hdr(skb); + struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset); - _enter(""); + _enter("%u,%u,%u", ip0->protocol, icmp->type, icmp->code); + + switch (icmp->type) { + case ICMP_DEST_UNREACH: + *info = ntohs(icmp->un.frag.mtu); + fallthrough; + case ICMP_TIME_EXCEEDED: + case ICMP_PARAMETERPROB: + ip = (struct iphdr *)((void *)icmp + 8); + break; + default: + return NULL; + } + + memset(srx, 0, sizeof(*srx)); + srx->transport_type = local->srx.transport_type; + srx->transport_len = local->srx.transport_len; + srx->transport.family = local->srx.transport.family; + + /* Can we see an ICMP4 packet on an ICMP6 listening socket? and vice + * versa? + */ + switch (srx->transport.family) { + case AF_INET: + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, &ip->daddr, + sizeof(struct in_addr)); + break; + +#ifdef CONFIG_AF_RXRPC_IPV6 + case AF_INET6: + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, &ip->daddr, + sizeof(struct in_addr)); + break; +#endif + + default: + WARN_ON_ONCE(1); + return NULL; + } + + _net("ICMP {%pISp}", &srx->transport); + return rxrpc_lookup_peer_rcu(local, srx); +} + +#ifdef CONFIG_AF_RXRPC_IPV6 +/* + * Find the peer associated with an ICMPv6 packet. + */ +static struct rxrpc_peer *rxrpc_lookup_peer_icmp6_rcu(struct rxrpc_local *local, + struct sk_buff *skb, + unsigned int udp_offset, + unsigned int *info, + struct sockaddr_rxrpc *srx) +{ + struct icmp6hdr *icmp = icmp6_hdr(skb); + struct ipv6hdr *ip, *ip0 = ipv6_hdr(skb); + struct udphdr *udp = (struct udphdr *)(skb->data + udp_offset); + + _enter("%u,%u,%u", ip0->nexthdr, icmp->icmp6_type, icmp->icmp6_code); + + switch (icmp->icmp6_type) { + case ICMPV6_DEST_UNREACH: + *info = ntohl(icmp->icmp6_mtu); + fallthrough; + case ICMPV6_PKT_TOOBIG: + case ICMPV6_TIME_EXCEED: + case ICMPV6_PARAMPROB: + ip = (struct ipv6hdr *)((void *)icmp + 8); + break; + default: + return NULL; + } memset(srx, 0, sizeof(*srx)); srx->transport_type = local->srx.transport_type; @@ -41,6 +124,165 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, /* Can we see an ICMP4 packet on an ICMP6 listening socket? and vice * versa? */ + switch (srx->transport.family) { + case AF_INET: + _net("Rx ICMP6 on v4 sock"); + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin.sin_addr, + &ip->daddr.s6_addr32[3], sizeof(struct in_addr)); + break; + case AF_INET6: + _net("Rx ICMP6"); + srx->transport.sin.sin_port = udp->dest; + memcpy(&srx->transport.sin6.sin6_addr, &ip->daddr, + sizeof(struct in6_addr)); + break; + default: + WARN_ON_ONCE(1); + return NULL; + } + + _net("ICMP {%pISp}", &srx->transport); + return rxrpc_lookup_peer_rcu(local, srx); +} +#endif /* CONFIG_AF_RXRPC_IPV6 */ + +/* + * Handle an error received on the local endpoint as a tunnel. + */ +void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, + unsigned int udp_offset) +{ + struct sock_extended_err ee; + struct sockaddr_rxrpc srx; + struct rxrpc_local *local; + struct rxrpc_peer *peer; + unsigned int info = 0; + int err; + u8 version = ip_hdr(skb)->version; + u8 type = icmp_hdr(skb)->type; + u8 code = icmp_hdr(skb)->code; + + rcu_read_lock(); + local = rcu_dereference_sk_user_data(sk); + if (unlikely(!local)) { + rcu_read_unlock(); + return; + } + + rxrpc_new_skb(skb, rxrpc_skb_received); + + switch (ip_hdr(skb)->version) { + case IPVERSION: + peer = rxrpc_lookup_peer_icmp_rcu(local, skb, udp_offset, + &info, &srx); + break; +#ifdef CONFIG_AF_RXRPC_IPV6 + case 6: + peer = rxrpc_lookup_peer_icmp6_rcu(local, skb, udp_offset, + &info, &srx); + break; +#endif + default: + rcu_read_unlock(); + return; + } + + if (peer && !rxrpc_get_peer_maybe(peer)) + peer = NULL; + if (!peer) { + rcu_read_unlock(); + return; + } + + memset(&ee, 0, sizeof(ee)); + + switch (version) { + case IPVERSION: + switch (type) { + case ICMP_DEST_UNREACH: + switch (code) { + case ICMP_FRAG_NEEDED: + rxrpc_adjust_mtu(peer, info); + rcu_read_unlock(); + rxrpc_put_peer(peer); + return; + default: + break; + } + + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + /* Might want to do something different with + * non-fatal errors + */ + //harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + default: + err = EPROTO; + break; + } + + ee.ee_origin = SO_EE_ORIGIN_ICMP; + ee.ee_type = type; + ee.ee_code = code; + ee.ee_errno = err; + break; + +#ifdef CONFIG_AF_RXRPC_IPV6 + case 6: + switch (type) { + case ICMPV6_PKT_TOOBIG: + rxrpc_adjust_mtu(peer, info); + rcu_read_unlock(); + rxrpc_put_peer(peer); + return; + } + + icmpv6_err_convert(type, code, &err); + + if (err == EACCES) + err = EHOSTUNREACH; + + ee.ee_origin = SO_EE_ORIGIN_ICMP6; + ee.ee_type = type; + ee.ee_code = code; + ee.ee_errno = err; + break; +#endif + } + + trace_rxrpc_rx_icmp(peer, &ee, &srx); + + rxrpc_distribute_error(peer, err, RXRPC_CALL_NETWORK_ERROR); + rcu_read_unlock(); + rxrpc_put_peer(peer); +} + +/* + * Find the peer associated with a local error. + */ +static struct rxrpc_peer *rxrpc_lookup_peer_local_rcu(struct rxrpc_local *local, + const struct sk_buff *skb, + struct sockaddr_rxrpc *srx) +{ + struct sock_exterr_skb *serr = SKB_EXT_ERR(skb); + + _enter(""); + + memset(srx, 0, sizeof(*srx)); + srx->transport_type = local->srx.transport_type; + srx->transport_len = local->srx.transport_len; + srx->transport.family = local->srx.transport.family; + switch (srx->transport.family) { case AF_INET: srx->transport_len = sizeof(srx->transport.sin); @@ -104,10 +346,8 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, /* * Handle an MTU/fragmentation problem. */ -static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, struct sock_exterr_skb *serr) +static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, unsigned int mtu) { - u32 mtu = serr->ee.ee_info; - _net("Rx ICMP Fragmentation Needed (%d)", mtu); /* wind down the local interface MTU */ @@ -148,7 +388,7 @@ void rxrpc_error_report(struct sock *sk) struct sock_exterr_skb *serr; struct sockaddr_rxrpc srx; struct rxrpc_local *local; - struct rxrpc_peer *peer; + struct rxrpc_peer *peer = NULL; struct sk_buff *skb; rcu_read_lock(); @@ -172,41 +412,20 @@ void rxrpc_error_report(struct sock *sk) } rxrpc_new_skb(skb, rxrpc_skb_received); serr = SKB_EXT_ERR(skb); - if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { - _leave("UDP empty message"); - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - return; - } - peer = rxrpc_lookup_peer_icmp_rcu(local, skb, &srx); - if (peer && !rxrpc_get_peer_maybe(peer)) - peer = NULL; - if (!peer) { - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - _leave(" [no peer]"); - return; - } - - trace_rxrpc_rx_icmp(peer, &serr->ee, &srx); - - if ((serr->ee.ee_origin == SO_EE_ORIGIN_ICMP && - serr->ee.ee_type == ICMP_DEST_UNREACH && - serr->ee.ee_code == ICMP_FRAG_NEEDED)) { - rxrpc_adjust_mtu(peer, serr); - rcu_read_unlock(); - rxrpc_free_skb(skb, rxrpc_skb_freed); - rxrpc_put_peer(peer); - _leave(" [MTU update]"); - return; + if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL) { + peer = rxrpc_lookup_peer_local_rcu(local, skb, &srx); + if (peer && !rxrpc_get_peer_maybe(peer)) + peer = NULL; + if (peer) { + trace_rxrpc_rx_icmp(peer, &serr->ee, &srx); + rxrpc_store_error(peer, serr); + } } - rxrpc_store_error(peer, serr); rcu_read_unlock(); rxrpc_free_skb(skb, rxrpc_skb_freed); rxrpc_put_peer(peer); - _leave(""); } -- cgit v1.2.3 From 21457f4a91cb522f1a3ad9741ff1d25fadfaa3c5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 Aug 2022 13:24:44 +0100 Subject: rxrpc: Remove rxrpc_get_reply_time() which is no longer used Remove rxrpc_get_reply_time() as that is no longer used now that the call issue time is used instead of the reply time. Signed-off-by: David Howells --- Documentation/networking/rxrpc.rst | 11 ---------- include/net/af_rxrpc.h | 2 -- net/rxrpc/recvmsg.c | 43 -------------------------------------- 3 files changed, 56 deletions(-) (limited to 'include/net') diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst index 39c2249c7aa7..39494a6ea739 100644 --- a/Documentation/networking/rxrpc.rst +++ b/Documentation/networking/rxrpc.rst @@ -1055,17 +1055,6 @@ The kernel interface functions are as follows: first function to change. Note that this must be called in TASK_RUNNING state. - (#) Get reply timestamp:: - - bool rxrpc_kernel_get_reply_time(struct socket *sock, - struct rxrpc_call *call, - ktime_t *_ts) - - This allows the timestamp on the first DATA packet of the reply of a - client call to be queried, provided that it is still in the Rx ring. If - successful, the timestamp will be stored into ``*_ts`` and true will be - returned; false will be returned otherwise. - (#) Get remote client epoch:: u32 rxrpc_kernel_get_epoch(struct socket *sock, diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index cee5f83c0f11..b69ca695935c 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -66,8 +66,6 @@ int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t, void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64); bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *); u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *); -bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *, - ktime_t *); bool rxrpc_kernel_call_is_complete(struct rxrpc_call *); void rxrpc_kernel_set_max_life(struct socket *, struct rxrpc_call *, unsigned long); diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 250f23bc1c07..7e39c262fd79 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -771,46 +771,3 @@ call_complete: goto out; } EXPORT_SYMBOL(rxrpc_kernel_recv_data); - -/** - * rxrpc_kernel_get_reply_time - Get timestamp on first reply packet - * @sock: The socket that the call exists on - * @call: The call to query - * @_ts: Where to put the timestamp - * - * Retrieve the timestamp from the first DATA packet of the reply if it is - * in the ring. Returns true if successful, false if not. - */ -bool rxrpc_kernel_get_reply_time(struct socket *sock, struct rxrpc_call *call, - ktime_t *_ts) -{ - struct sk_buff *skb; - rxrpc_seq_t hard_ack, top, seq; - bool success = false; - - mutex_lock(&call->user_mutex); - - if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_RECV_REPLY) - goto out; - - hard_ack = call->rx_hard_ack; - if (hard_ack != 0) - goto out; - - seq = hard_ack + 1; - top = smp_load_acquire(&call->rx_top); - if (after(seq, top)) - goto out; - - skb = call->rxtx_buffer[seq & RXRPC_RXTX_BUFF_MASK]; - if (!skb) - goto out; - - *_ts = skb_get_ktime(skb); - success = true; - -out: - mutex_unlock(&call->user_mutex); - return success; -} -EXPORT_SYMBOL(rxrpc_kernel_get_reply_time); -- cgit v1.2.3 From 9cb252c4c1c53ae58bc565bab76e98133288f23a Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 5 Sep 2022 11:50:15 +0800 Subject: net: skb: export skb drop reaons to user by TRACE_DEFINE_ENUM As Eric reported, the 'reason' field is not presented when trace the kfree_skb event by perf: $ perf record -e skb:kfree_skb -a sleep 10 $ perf script ip_defrag 14605 [021] 221.614303: skb:kfree_skb: skbaddr=0xffff9d2851242700 protocol=34525 location=0xffffffffa39346b1 reason: The cause seems to be passing kernel address directly to TP_printk(), which is not right. As the enum 'skb_drop_reason' is not exported to user space through TRACE_DEFINE_ENUM(), perf can't get the drop reason string from the 'reason' field, which is a number. Therefore, we introduce the macro DEFINE_DROP_REASON(), which is used to define the trace enum by TRACE_DEFINE_ENUM(). With the help of DEFINE_DROP_REASON(), now we can remove the auto-generate that we introduced in the commit ec43908dd556 ("net: skb: use auto-generation to convert skb drop reason to string"), and define the string array 'drop_reasons'. Hmmmm...now we come back to the situation that have to maintain drop reasons in both enum skb_drop_reason and DEFINE_DROP_REASON. But they are both in dropreason.h, which makes it easier. After this commit, now the format of kfree_skb is like this: $ cat /tracing/events/skb/kfree_skb/format name: kfree_skb ID: 1524 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1; field:void * skbaddr; offset:8; size:8; signed:0; field:void * location; offset:16; size:8; signed:0; field:unsigned short protocol; offset:24; size:2; signed:0; field:enum skb_drop_reason reason; offset:28; size:4; signed:0; print fmt: "skbaddr=%p protocol=%u location=%p reason: %s", REC->skbaddr, REC->protocol, REC->location, __print_symbolic(REC->reason, { 1, "NOT_SPECIFIED" }, { 2, "NO_SOCKET" } ...... Fixes: ec43908dd556 ("net: skb: use auto-generation to convert skb drop reason to string") Link: https://lore.kernel.org/netdev/CANn89i+bx0ybvE55iMYf5GJM48WwV1HNpdm9Q6t-HaEstqpCSA@mail.gmail.com/ Reported-by: Eric Dumazet Signed-off-by: Menglong Dong Signed-off-by: David S. Miller --- include/net/dropreason.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++ include/trace/events/skb.h | 15 ++++++++++- net/core/.gitignore | 1 - net/core/Makefile | 22 +-------------- net/core/skbuff.c | 6 ++++- 5 files changed, 87 insertions(+), 24 deletions(-) delete mode 100644 net/core/.gitignore (limited to 'include/net') diff --git a/include/net/dropreason.h b/include/net/dropreason.h index fae9b40e54fa..c1cbcdbaf149 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -3,6 +3,73 @@ #ifndef _LINUX_DROPREASON_H #define _LINUX_DROPREASON_H +#define DEFINE_DROP_REASON(FN, FNe) \ + FN(NOT_SPECIFIED) \ + FN(NO_SOCKET) \ + FN(PKT_TOO_SMALL) \ + FN(TCP_CSUM) \ + FN(SOCKET_FILTER) \ + FN(UDP_CSUM) \ + FN(NETFILTER_DROP) \ + FN(OTHERHOST) \ + FN(IP_CSUM) \ + FN(IP_INHDR) \ + FN(IP_RPFILTER) \ + FN(UNICAST_IN_L2_MULTICAST) \ + FN(XFRM_POLICY) \ + FN(IP_NOPROTO) \ + FN(SOCKET_RCVBUFF) \ + FN(PROTO_MEM) \ + FN(TCP_MD5NOTFOUND) \ + FN(TCP_MD5UNEXPECTED) \ + FN(TCP_MD5FAILURE) \ + FN(SOCKET_BACKLOG) \ + FN(TCP_FLAGS) \ + FN(TCP_ZEROWINDOW) \ + FN(TCP_OLD_DATA) \ + FN(TCP_OVERWINDOW) \ + FN(TCP_OFOMERGE) \ + FN(TCP_RFC7323_PAWS) \ + FN(TCP_INVALID_SEQUENCE) \ + FN(TCP_RESET) \ + FN(TCP_INVALID_SYN) \ + FN(TCP_CLOSE) \ + FN(TCP_FASTOPEN) \ + FN(TCP_OLD_ACK) \ + FN(TCP_TOO_OLD_ACK) \ + FN(TCP_ACK_UNSENT_DATA) \ + FN(TCP_OFO_QUEUE_PRUNE) \ + FN(TCP_OFO_DROP) \ + FN(IP_OUTNOROUTES) \ + FN(BPF_CGROUP_EGRESS) \ + FN(IPV6DISABLED) \ + FN(NEIGH_CREATEFAIL) \ + FN(NEIGH_FAILED) \ + FN(NEIGH_QUEUEFULL) \ + FN(NEIGH_DEAD) \ + FN(TC_EGRESS) \ + FN(QDISC_DROP) \ + FN(CPU_BACKLOG) \ + FN(XDP) \ + FN(TC_INGRESS) \ + FN(UNHANDLED_PROTO) \ + FN(SKB_CSUM) \ + FN(SKB_GSO_SEG) \ + FN(SKB_UCOPY_FAULT) \ + FN(DEV_HDR) \ + FN(DEV_READY) \ + FN(FULL_RING) \ + FN(NOMEM) \ + FN(HDR_TRUNC) \ + FN(TAP_FILTER) \ + FN(TAP_TXFILTER) \ + FN(ICMP_CSUM) \ + FN(INVALID_PROTO) \ + FN(IP_INADDRERRORS) \ + FN(IP_INNOROUTES) \ + FN(PKT_TOO_BIG) \ + FNe(MAX) + /** * enum skb_drop_reason - the reasons of skb drops * diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 45264e4bb254..50a974f7dfb4 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -9,6 +9,15 @@ #include #include +#undef FN +#define FN(reason) TRACE_DEFINE_ENUM(SKB_DROP_REASON_##reason); +DEFINE_DROP_REASON(FN, FN) + +#undef FN +#undef FNe +#define FN(reason) { SKB_DROP_REASON_##reason, #reason }, +#define FNe(reason) { SKB_DROP_REASON_##reason, #reason } + /* * Tracepoint for free an sk_buff: */ @@ -35,9 +44,13 @@ TRACE_EVENT(kfree_skb, TP_printk("skbaddr=%p protocol=%u location=%p reason: %s", __entry->skbaddr, __entry->protocol, __entry->location, - drop_reasons[__entry->reason]) + __print_symbolic(__entry->reason, + DEFINE_DROP_REASON(FN, FNe))) ); +#undef FN +#undef FNe + TRACE_EVENT(consume_skb, TP_PROTO(struct sk_buff *skb), diff --git a/net/core/.gitignore b/net/core/.gitignore deleted file mode 100644 index df1e74372cce..000000000000 --- a/net/core/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dropreason_str.c diff --git a/net/core/Makefile b/net/core/Makefile index e8ce3bd283a6..5857cec87b83 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -5,7 +5,7 @@ obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o \ - flow_dissector.o dropreason_str.o + flow_dissector.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o @@ -40,23 +40,3 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o obj-$(CONFIG_BPF_SYSCALL) += sock_map.o obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o obj-$(CONFIG_OF) += of_net.o - -clean-files := dropreason_str.c - -quiet_cmd_dropreason_str = GEN $@ -cmd_dropreason_str = awk -F ',' 'BEGIN{ print "\#include \n"; \ - print "const char * const drop_reasons[] = {" }\ - /^enum skb_drop/ { dr=1; }\ - /^\};/ { dr=0; }\ - /^\tSKB_DROP_REASON_/ {\ - if (dr) {\ - sub(/\tSKB_DROP_REASON_/, "", $$1);\ - printf "\t[SKB_DROP_REASON_%s] = \"%s\",\n", $$1, $$1;\ - }\ - }\ - END{ print "};" }' $< > $@ - -$(obj)/dropreason_str.c: $(srctree)/include/net/dropreason.h - $(call cmd,dropreason_str) - -$(obj)/dropreason_str.o: $(obj)/dropreason_str.c diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 84bb5e188d0d..417463da4fac 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -91,7 +91,11 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); -/* The array 'drop_reasons' is auto-generated in dropreason_str.c */ +#undef FN +#define FN(reason) [SKB_DROP_REASON_##reason] = #reason, +const char * const drop_reasons[] = { + DEFINE_DROP_REASON(FN, FN) +}; EXPORT_SYMBOL(drop_reasons); /** -- cgit v1.2.3