From e2e57bc11a2ad35a0a90bc5342c4d436dfce5f31 Mon Sep 17 00:00:00 2001 From: desaishivam26 Date: Fri, 25 Nov 2016 17:41:12 +0530 Subject: [PATCH 001/281] Revert "Revert "Makefile: Try to always use GNU ld"" This reverts commit 47f7c8df24c4ea5e03f93dd88c92221c45a0d776. --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index e666b354d364..ffe3d70b9719 100644 --- a/Makefile +++ b/Makefile @@ -345,6 +345,11 @@ DEPMOD = /sbin/depmod PERL = perl CHECK = sparse +# Try to always use GNU ld +ifneq ($(wildcard $(CROSS_COMPILE)ld.bfd),) +LD = $(CROSS_COMPILE)ld.bfd +endif + # Use the wrapper for the compiler. This wrapper scans for new # warnings and causes the build to stop upon encountering them. CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) From ff8eb9023b000729ebdfc22dc628c69ecfbe61ee Mon Sep 17 00:00:00 2001 From: desaishivam26 Date: Fri, 25 Nov 2016 17:41:58 +0530 Subject: [PATCH 002/281] Revert "android-recommended.cfg: enable fstack-protector-strong" This reverts commit 5d438492c88be5e8a64fd6a31c1f17416e53e1c3. --- android/configs/android-recommended.cfg | 1 - arch/arm/configs/lux_defconfig | 4 ++-- arch/arm/configs/merlin_defconfig | 4 ++-- arch/arm/configs/osprey_defconfig | 4 ++-- arch/arm/configs/surnia_defconfig | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index ec8adf6dbcda..4dd3b4585033 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -10,7 +10,6 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_COMPACTION=y CONFIG_DM_UEVENT=y CONFIG_DRAGONRISE_FF=y diff --git a/arch/arm/configs/lux_defconfig b/arch/arm/configs/lux_defconfig index 5568e24ae81d..0914a33d416c 100644 --- a/arch/arm/configs/lux_defconfig +++ b/arch/arm/configs/lux_defconfig @@ -206,8 +206,8 @@ CONFIG_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y CONFIG_CC_STACKPROTECTOR=y # CONFIG_CC_STACKPROTECTOR_NONE is not set -# CONFIG_CC_STACKPROTECTOR_REGULAR is not set -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +# CONFIG_CC_STACKPROTECTOR_STRONG is not set CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y diff --git a/arch/arm/configs/merlin_defconfig b/arch/arm/configs/merlin_defconfig index a455c9f3767a..45b42b453a3b 100644 --- a/arch/arm/configs/merlin_defconfig +++ b/arch/arm/configs/merlin_defconfig @@ -206,8 +206,8 @@ CONFIG_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y CONFIG_CC_STACKPROTECTOR=y # CONFIG_CC_STACKPROTECTOR_NONE is not set -# CONFIG_CC_STACKPROTECTOR_REGULAR is not set -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +# CONFIG_CC_STACKPROTECTOR_STRONG is not set CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y diff --git a/arch/arm/configs/osprey_defconfig b/arch/arm/configs/osprey_defconfig index e7b917fa4de9..095c2e037368 100644 --- a/arch/arm/configs/osprey_defconfig +++ b/arch/arm/configs/osprey_defconfig @@ -208,8 +208,8 @@ CONFIG_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y CONFIG_CC_STACKPROTECTOR=y # CONFIG_CC_STACKPROTECTOR_NONE is not set -# CONFIG_CC_STACKPROTECTOR_REGULAR is not set -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +# CONFIG_CC_STACKPROTECTOR_STRONG is not set CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y diff --git a/arch/arm/configs/surnia_defconfig b/arch/arm/configs/surnia_defconfig index 0b797b4059bc..d47390a8d4e2 100644 --- a/arch/arm/configs/surnia_defconfig +++ b/arch/arm/configs/surnia_defconfig @@ -206,8 +206,8 @@ CONFIG_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y CONFIG_CC_STACKPROTECTOR=y # CONFIG_CC_STACKPROTECTOR_NONE is not set -# CONFIG_CC_STACKPROTECTOR_REGULAR is not set -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +# CONFIG_CC_STACKPROTECTOR_STRONG is not set CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y From 857907dfde0d1f7097f57430dd2ea4d21f9b112a Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 5 Jul 2016 17:32:30 -0400 Subject: [PATCH 003/281] ecryptfs: don't allow mmap when the lower fs doesn't support it There are legitimate reasons to disallow mmap on certain files, notably in sysfs or procfs. We shouldn't emulate mmap support on file systems that don't offer support natively. CVE-2016-1583 Signed-off-by: Jeff Mahoney Cc: stable@vger.kernel.org [tyhicks: clean up f_op check by using ecryptfs_file_to_lower()] Signed-off-by: Tyler Hicks Git-repo: https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/ Git-commit: f0fe970df3838c202ef6c07a4c2b36838ef0a88b [rsiddoji@codeaurora.org: backport and resolved trivial confits ] Change-Id: I6127049027975ca20a38ee4fb500478db8b3fd5e Signed-off-by: Ravi Kumar Siddojigari --- fs/ecryptfs/file.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 041379a646b3..9d3602332674 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -185,6 +185,19 @@ static int read_or_initialize_metadata(struct dentry *dentry) return rc; } +static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file *lower_file = ecryptfs_file_to_lower(file); + /* + * Don't allow mmap on top of file systems that don't support it + * natively. If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs + * allows recursive mounting, this will need to be extended. + */ + if (!lower_file->f_op->mmap) + return -ENODEV; + return generic_file_mmap(file, vma); +} + /** * ecryptfs_open * @inode: inode speciying file to open @@ -372,7 +385,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ecryptfs_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, From 3cd708f3478896adee6c975489381521ce8e03ae Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 24 Oct 2016 13:52:04 -0700 Subject: [PATCH 004/281] msm: crypto: Fix integer over flow check in qce driver Integer overflow check is invalid when ULONG_MAX is used, as ULONG_MAX has typeof 'unsigned long', while areq->assoclen, q_req->crytlen, and qreq.ivsize are 'unsigned int'. Make change to use UINT_MAX instead of ULONG_MAX. Change-Id: If2bb1900c07af1ea162da362c913d4880b0bc755 Signed-off-by: Zhen Kong --- drivers/crypto/msm/qce.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c index d11a8315e660..3c657c8becde 100644 --- a/drivers/crypto/msm/qce.c +++ b/drivers/crypto/msm/qce.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto Engine driver. * - * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1952,8 +1952,8 @@ int qce_aead_req(void *handle, struct qce_req *q_req) else q_req->cryptlen = areq->cryptlen - authsize; - if ((q_req->cryptlen > ULONG_MAX - ivsize) || - (q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) { + if ((q_req->cryptlen > UINT_MAX - ivsize) || + (q_req->cryptlen + ivsize > UINT_MAX - areq->assoclen)) { pr_err("Integer overflow on total aead req length.\n"); return -EINVAL; } From 4d4fd95aeaa66e6b279444d8279c4f5b129d379a Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 12 Sep 2016 15:47:42 -0700 Subject: [PATCH 005/281] cgroup: prefer %pK to %p Prevents leaking kernel pointers when using kptr_restrict. Bug: 30149174 Change-Id: I0fa3cd8d4a0d9ea76d085bba6020f1eda073c09b Git-repo: https://android.googlesource.com/kernel/msm.git Git-commit: 505e48f32f1321ed7cf80d49dd5f31b16da445a8 Signed-off-by: Srinivasa Rao Kuppala --- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 05b36e7b9e6b..1e2c3588b990 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -5449,7 +5449,7 @@ static int cgroup_css_links_read(struct cgroup *cont, struct css_set *cg = link->cg; struct task_struct *task; int count = 0; - seq_printf(seq, "css_set %p\n", cg); + seq_printf(seq, "css_set %pK\n", cg); list_for_each_entry(task, &cg->tasks, cg_list) { if (count++ > MAX_TASKS_SHOWN_PER_CSS) { seq_puts(seq, " ...\n"); From c5e860dac1d5a67966e4c39b41d521c0c0818b16 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Nov 2016 07:53:17 -0700 Subject: [PATCH 006/281] tcp: fix potential memory corruption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ac9e70b17ecd7c6e933ff2eaf7ab37429e71bf4d ] Imagine initial value of max_skb_frags is 17, and last skb in write queue has 15 frags. Then max_skb_frags is lowered to 14 or smaller value. tcp_sendmsg() will then be allowed to add additional page frags and eventually go past MAX_SKB_FRAGS, overflowing struct skb_shared_info. Change-Id: I5028743c15c76a110ca3726abe69591c7a0bed16 Fixes: 5f74f82ea34c ("net:Add sysctl_max_skb_frags") Signed-off-by: Eric Dumazet Cc: Hans Westgaard Ry Cc: Håkon Bugge Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 46cef2b4613c..361bdb16b964 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1181,7 +1181,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (!skb_can_coalesce(skb, i, pfrag->page, pfrag->offset)) { - if (i == MAX_SKB_FRAGS || !sg) { + if (i >= MAX_SKB_FRAGS || !sg) { tcp_mark_push(tp, skb); goto new_segment; } From 762f0cb13be5c07bac405e0089afad18d8f83eb9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 2 Dec 2016 09:44:53 -0800 Subject: [PATCH 007/281] net: avoid signed overflows for SO_{SND|RCV}BUFFORCE [ Upstream commit b98b0bc8c431e3ceb4b26b0dfc8db509518fb290 ] CAP_NET_ADMIN users should not be allowed to set negative sk_sndbuf or sk_rcvbuf values, as it can lead to various memory corruptions, crashes, OOM... Note that before commit 82981930125a ("net: cleanups in sock_setsockopt()"), the bug was even more serious, since SO_SNDBUF and SO_RCVBUF were vulnerable. This needs to be backported to all known linux kernels. Again, many thanks to syzkaller team for discovering this gem. Change-Id: I47e1cd7315b04cbe583509d1c82af2a5dd4ca8d8 Signed-off-by: Eric Dumazet Reported-by: Andrey Konovalov Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby --- net/core/sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 2155eaa86b32..0f3567be54c3 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -727,7 +727,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, val = min_t(u32, val, sysctl_wmem_max); set_sndbuf: sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF); + sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); /* Wake up sending tasks if we upped the value. */ sk->sk_write_space(sk); break; @@ -763,7 +763,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, * returning the value we actually used in getsockopt * is the most desirable behavior. */ - sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF); + sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); break; case SO_RCVBUFFORCE: From 5a7932b293893e0c7e9cc0924a24e840366a4a0e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 5 Dec 2016 10:34:38 -0800 Subject: [PATCH 008/281] net: ping: check minimum size on ICMP header length [ Upstream commit 0eab121ef8750a5c8637d51534d5e9143fb0633f ] Prior to commit c0371da6047a ("put iov_iter into msghdr") in v3.19, there was no check that the iovec contained enough bytes for an ICMP header, and the read loop would walk across neighboring stack contents. Since the iov_iter conversion, bad arguments are noticed, but the returned error is EFAULT. Returning EINVAL is a clearer error and also solves the problem prior to v3.19. This was found using trinity with KASAN on v3.18: BUG: KASAN: stack-out-of-bounds in memcpy_fromiovec+0x60/0x114 at addr ffffffc071077da0 Read of size 8 by task trinity-c2/9623 page:ffffffbe034b9a08 count:0 mapcount:0 mapping: (null) index:0x0 flags: 0x0() page dumped because: kasan: bad access detected CPU: 0 PID: 9623 Comm: trinity-c2 Tainted: G BU 3.18.0-dirty #15 Hardware name: Google Tegra210 Smaug Rev 1,3+ (DT) Call trace: [] dump_backtrace+0x0/0x1ac arch/arm64/kernel/traps.c:90 [] show_stack+0x10/0x1c arch/arm64/kernel/traps.c:171 [< inline >] __dump_stack lib/dump_stack.c:15 [] dump_stack+0x7c/0xd0 lib/dump_stack.c:50 [< inline >] print_address_description mm/kasan/report.c:147 [< inline >] kasan_report_error mm/kasan/report.c:236 [] kasan_report+0x380/0x4b8 mm/kasan/report.c:259 [< inline >] check_memory_region mm/kasan/kasan.c:264 [] __asan_load8+0x20/0x70 mm/kasan/kasan.c:507 [] memcpy_fromiovec+0x5c/0x114 lib/iovec.c:15 [< inline >] memcpy_from_msg include/linux/skbuff.h:2667 [] ping_common_sendmsg+0x50/0x108 net/ipv4/ping.c:674 [] ping_v4_sendmsg+0xd8/0x698 net/ipv4/ping.c:714 [] inet_sendmsg+0xe0/0x12c net/ipv4/af_inet.c:749 [< inline >] __sock_sendmsg_nosec net/socket.c:624 [< inline >] __sock_sendmsg net/socket.c:632 [] sock_sendmsg+0x124/0x164 net/socket.c:643 [< inline >] SYSC_sendto net/socket.c:1797 [] SyS_sendto+0x178/0x1d8 net/socket.c:1761 CVE-2016-8399 Change-Id: I795b2ad57e1d2f73af0ade550756424be51859c3 Reported-by: Qidan He Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby --- net/ipv4/ping.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 299e6c3aaa27..545f0aa09cba 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -654,6 +654,10 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, if (len > 0xFFFF || len < icmph_len) return -EMSGSIZE; + /* Must have at least a full ICMP header. */ + if (len < icmph_len) + return -EINVAL; + /* * Check the flags. */ From 1c8a11a7f15bb23ccd3a139d10c0590488e6eeae Mon Sep 17 00:00:00 2001 From: Ravi Kumar Siddojigari Date: Mon, 21 Nov 2016 20:50:14 +0530 Subject: [PATCH 009/281] usb: Avoid exposing kernel addresses Usage of %p exposes the kernel addresses, an easy target to kernel write vulnerabilities. With this patch currently %pK prints only Zeros as address. If you need actual address echo 0 > /proc/sys/kernel/kptr_restrict addressing the info leak issue under following CVEs CVE-2016-8401, CVE-2016-8402, CVE-2016-8403, CVE-2016-8404, CVE-2016-8405, CVE-2016-8406, CVE-2016-8407 Change-Id: Iefe0639416275cfeca6e90b6f88cd0412bb76414 Signed-off-by: Ravi Kumar Siddojigari --- drivers/usb/gadget/u_ctrl_hsic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/u_ctrl_hsic.c b/drivers/usb/gadget/u_ctrl_hsic.c index b9536ef08752..70797987f88a 100644 --- a/drivers/usb/gadget/u_ctrl_hsic.c +++ b/drivers/usb/gadget/u_ctrl_hsic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011, 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -184,7 +184,7 @@ static void ghsic_ctrl_connect_w(struct work_struct *w) if (!port || !test_bit(CH_READY, &port->bridge_sts)) return; - pr_debug("%s: port:%p port type =%u\n", __func__, port, port->gtype); + pr_debug("%s: port:%pK port type =%u\n", __func__, port, port->gtype); retval = ctrl_bridge_open(&port->brdg); if (retval) { @@ -481,7 +481,7 @@ static int gctrl_port_alloc(int portno, enum gadget_type gtype) platform_driver_register(pdrv); - pr_debug("%s: port:%p portno:%d\n", __func__, port, portno); + pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno); return 0; } @@ -573,7 +573,7 @@ static ssize_t gctrl_read_stats(struct file *file, char __user *ubuf, temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp, "\nName: %s\n" - "#PORT:%d port: %p\n" + "#PORT:%d port: %pK\n" "to_usbhost: %lu\n" "to_modem: %lu\n" "cpkt_drp_cnt: %lu\n" From ebd079ec091f3f940d5463f50edee4d75506567a Mon Sep 17 00:00:00 2001 From: Vishnu Vardhan Reddy Naini Date: Sun, 25 Dec 2016 13:07:05 +0530 Subject: [PATCH 010/281] arm/dts: remove unused dt entries for ion system contig heap Change-Id: Idcb22c20e121c8c9f32f75240006f291d69746e4 --- arch/arm/boot/dts/qcom/apq8084-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8226-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8226-w-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8610-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8909-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8916-512mb-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8916-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8939-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8974-ion.dtsi | 7 +------ arch/arm/boot/dts/qcom/msm8994-ion.dtsi | 7 +------ 10 files changed, 10 insertions(+), 60 deletions(-) diff --git a/arch/arm/boot/dts/qcom/apq8084-ion.dtsi b/arch/arm/boot/dts/qcom/apq8084-ion.dtsi index bd649fe3926f..436a96677a7e 100644 --- a/arch/arm/boot/dts/qcom/apq8084-ion.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; diff --git a/arch/arm/boot/dts/qcom/msm8226-ion.dtsi b/arch/arm/boot/dts/qcom/msm8226-ion.dtsi index b3c25a3cdbfe..949f50607366 100644 --- a/arch/arm/boot/dts/qcom/msm8226-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - system_contig_heap: qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - cp_mm_heap: qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; diff --git a/arch/arm/boot/dts/qcom/msm8226-w-ion.dtsi b/arch/arm/boot/dts/qcom/msm8226-w-ion.dtsi index 1ac36e094041..e638bc581aa1 100644 --- a/arch/arm/boot/dts/qcom/msm8226-w-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8226-w-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - system_contig_heap: qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qsecom_heap: qcom,ion-heap@27 { /* QSECOM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <27>; diff --git a/arch/arm/boot/dts/qcom/msm8610-ion.dtsi b/arch/arm/boot/dts/qcom/msm8610-ion.dtsi index a7a428bec420..22ba8c1536c3 100644 --- a/arch/arm/boot/dts/qcom/msm8610-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8610-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@27 { /* QSECOM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <27>; diff --git a/arch/arm/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm/boot/dts/qcom/msm8909-ion.dtsi index 6209678ee673..6c1aa400d4a8 100644 --- a/arch/arm/boot/dts/qcom/msm8909-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - system_contig_heap: qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qsecom_heap: qcom,ion-heap@27 { /* QSEECOM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <27>; diff --git a/arch/arm/boot/dts/qcom/msm8916-512mb-ion.dtsi b/arch/arm/boot/dts/qcom/msm8916-512mb-ion.dtsi index b688a10a6d8f..2cebe6242f70 100644 --- a/arch/arm/boot/dts/qcom/msm8916-512mb-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-512mb-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@27 { /* QSEECOM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <27>; diff --git a/arch/arm/boot/dts/qcom/msm8916-ion.dtsi b/arch/arm/boot/dts/qcom/msm8916-ion.dtsi index 80baf241df41..53e85b9ac923 100644 --- a/arch/arm/boot/dts/qcom/msm8916-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; diff --git a/arch/arm/boot/dts/qcom/msm8939-ion.dtsi b/arch/arm/boot/dts/qcom/msm8939-ion.dtsi index f5e70544067b..39e3fa505fd0 100644 --- a/arch/arm/boot/dts/qcom/msm8939-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8939-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; diff --git a/arch/arm/boot/dts/qcom/msm8974-ion.dtsi b/arch/arm/boot/dts/qcom/msm8974-ion.dtsi index de751a0f531d..e9ead3cd881d 100644 --- a/arch/arm/boot/dts/qcom/msm8974-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8974-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; diff --git a/arch/arm/boot/dts/qcom/msm8994-ion.dtsi b/arch/arm/boot/dts/qcom/msm8994-ion.dtsi index 16b920e06910..deea46f0e186 100644 --- a/arch/arm/boot/dts/qcom/msm8994-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8994-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014,2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,11 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@21 { - reg = <21>; - qcom,ion-heap-type = "SYSTEM_CONTIG"; - }; - qcom,ion-heap@8 { /* CP_MM HEAP */ compatible = "qcom,msm-ion-reserve"; reg = <8>; From a8c96afdbbb04039eb03073cec5af639dcd82591 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 28 Dec 2015 20:47:08 -0500 Subject: [PATCH 011/281] arm: fix handling of F_OFD_... in oabi_fcntl64() Change-Id: I4809d4887caf26bcfad505d6a378369b217b5a9e Cc: stable@vger.kernel.org # 3.15+ Reviewed-by: Jeff Layton Signed-off-by: Al Viro Git-repo: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git Git-commit: 76cc404bfdc0d419c720de4daaf2584542734f42 Signed-off-by: Dennis Cagle --- arch/arm/kernel/sys_oabi-compat.c | 71 ++++++++++++++++--------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 3e94811690ce..20a6f3a7376f 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -193,52 +193,53 @@ struct oabi_flock64 { pid_t l_pid; } __attribute__ ((packed,aligned(4))); -asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, +static long do_locks(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct oabi_flock64 user; struct flock64 kernel; - mm_segment_t fs = USER_DS; /* initialized to kill a warning */ - unsigned long local_arg = arg; - int ret; + struct oabi_flock64 user; + mm_segment_t fs; + long ret; - switch (cmd) { - case F_GETLK64: - case F_SETLK64: - case F_SETLKW64: - if (copy_from_user(&user, (struct oabi_flock64 __user *)arg, - sizeof(user))) - return -EFAULT; - kernel.l_type = user.l_type; - kernel.l_whence = user.l_whence; - kernel.l_start = user.l_start; - kernel.l_len = user.l_len; - kernel.l_pid = user.l_pid; - local_arg = (unsigned long)&kernel; - fs = get_fs(); - set_fs(KERNEL_DS); - } + if (copy_from_user(&user, (struct oabi_flock64 __user *)arg, + sizeof(user))) + return -EFAULT; + kernel.l_type = user.l_type; + kernel.l_whence = user.l_whence; + kernel.l_start = user.l_start; + kernel.l_len = user.l_len; + kernel.l_pid = user.l_pid; - ret = sys_fcntl64(fd, cmd, local_arg); + fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel); + set_fs(fs); + if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) { + user.l_type = kernel.l_type; + user.l_whence = kernel.l_whence; + user.l_start = kernel.l_start; + user.l_len = kernel.l_len; + user.l_pid = kernel.l_pid; + if (copy_to_user((struct oabi_flock64 __user *)arg, + &user, sizeof(user))) + ret = -EFAULT; + } + return ret; +} + +asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, + unsigned long arg) +{ switch (cmd) { case F_GETLK64: - if (!ret) { - user.l_type = kernel.l_type; - user.l_whence = kernel.l_whence; - user.l_start = kernel.l_start; - user.l_len = kernel.l_len; - user.l_pid = kernel.l_pid; - if (copy_to_user((struct oabi_flock64 __user *)arg, - &user, sizeof(user))) - ret = -EFAULT; - } case F_SETLK64: case F_SETLKW64: - set_fs(fs); - } + return do_locks(fd, cmd, arg); - return ret; + default: + return sys_fcntl64(fd, cmd, arg); + } } struct oabi_epoll_event { From 9fdb9a3a3dadda7fcfe030e2d7d76914ddcbe928 Mon Sep 17 00:00:00 2001 From: ChandanaKishori Chiluveru Date: Tue, 28 Apr 2015 10:48:47 +0530 Subject: [PATCH 012/281] usb: gadget: f_mtp:Fix issue of NULL pointer access in mtp_read MTP usb device node created as a part of mtp function init call. Userspace can read/write to MTP device using this node. If MTP is not enabled in the composition and trying to read mtp_usb dev node from the userspace leading to null pointer access in mtp_read. Do not access ep OUT maxpacket size in mtp_read. First block on mtp_read until the state become online which doesn't wakeup from the thread and expecting for the read completion or state change which occurs as a part of set_alt. Change-Id: Icbee5fe7ae2c02b2bca185a0dc7587eb4940058a Signed-off-by: ChandanaKishori Chiluveru --- drivers/usb/gadget/f_mtp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c index 29d69d82758a..77ce1f9ce263 100644 --- a/drivers/usb/gadget/f_mtp.c +++ b/drivers/usb/gadget/f_mtp.c @@ -594,11 +594,6 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, DBG(cdev, "mtp_read(%zu)\n", count); - len = ALIGN(count, dev->ep_out->maxpacket); - - if (len > mtp_rx_req_len) - return -EINVAL; - /* we will block until we're online */ DBG(cdev, "mtp_read: waiting for online state\n"); ret = wait_event_interruptible(dev->read_wq, @@ -607,6 +602,11 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, r = ret; goto done; } + len = ALIGN(count, dev->ep_out->maxpacket); + + if (len > mtp_rx_req_len) + return -EINVAL; + spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { /* report cancelation to userspace */ From 223eafa0da87e07347e3a65c3f7c2d0c32403730 Mon Sep 17 00:00:00 2001 From: Siqi Lin Date: Tue, 11 Oct 2016 12:12:27 -0700 Subject: [PATCH 013/281] BACKPORT: msm: camera: cpp: Add validation for v4l2 ioctl arguments In CPP v4l2 ioctl command is made, if _IOC_DIR(cmd) is _IOC_NONE, then the user-supplied argument arg is not checked and an information disclosure is possible Bug: 29464815 CRs-Fixed: 1042068 Change-Id: Ibcd0c4d6605ecdabe4f720aaf47366dbd7503ad1 Signed-off-by: Sunid Wilson Signed-off-by: Biswajit Paul Signed-off-by: Siqi Lin (cherry-picked from commit 35b674b22af887a05a1697c8518fd89b8cd87a3d) Change-Id: Ibcd0c4d6605ecdabe4f720aaf47366dbd7503ad1 --- .../msm/camera_v2/pproc/cpp/msm_cpp.c | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index b76ee2d01f44..afdb941b3f09 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1890,16 +1890,39 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, } #endif +static int msm_cpp_validate_input(unsigned int cmd, void *arg, + struct msm_camera_v4l2_ioctl_t **ioctl_ptr) +{ + switch (cmd) { + case MSM_SD_SHUTDOWN: + break; + default: { + if (ioctl_ptr == NULL) { + pr_err("Wrong ioctl_ptr for cmd %u\n", cmd); + return -EINVAL; + } + + *ioctl_ptr = arg; + if ((*ioctl_ptr == NULL) || + (*ioctl_ptr)->ioctl_ptr == NULL) { + pr_err("Error invalid ioctl argument cmd %u", cmd); + return -EINVAL; + } + break; + } + } + return 0; +} + long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct cpp_device *cpp_dev = NULL; - struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = NULL; int rc = 0; - if ((sd == NULL) || (ioctl_ptr == NULL) || - (ioctl_ptr->ioctl_ptr == NULL)) { - pr_err("Wrong ioctl_ptr %p, sd %p\n", ioctl_ptr, sd); + if (sd == NULL) { + pr_err("sd %pK\n", sd); return -EINVAL; } cpp_dev = v4l2_get_subdevdata(sd); @@ -1907,7 +1930,19 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, pr_err("cpp_dev is null\n"); return -EINVAL; } + + if (_IOC_DIR(cmd) == _IOC_NONE) { + pr_err("Invalid ioctl/subdev cmd %u", cmd); + return -EINVAL; + } + + rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr); + if (rc != 0) { + pr_err("input validation failed\n"); + return rc; + } mutex_lock(&cpp_dev->mutex); + CPP_DBG("E cmd: 0x%x\n", cmd); switch (cmd) { case VIDIOC_MSM_CPP_GET_HW_INFO: { From 434f304b9380152d93937f59ed4176754f2a174f Mon Sep 17 00:00:00 2001 From: Walter Yang Date: Wed, 27 Jul 2016 15:07:53 +0800 Subject: [PATCH 014/281] ASoC: msm: set pointers to NULL after kfree In lsm-related driver files, some pointers are not set as NULL after the memory is freed, which will leave many dangling pointers. Set them to NULL explicitly to avoid potential risk. CRs-Fixed: 880388 Change-Id: I44925240705608510266a51225cc02611637c571 Signed-off-by: Walter Yang --- sound/soc/msm/msm-cpe-lsm.c | 7 +++++++ sound/soc/msm/qdsp6v2/msm-dai-slim.c | 2 ++ sound/soc/msm/qdsp6v2/q6lsm.c | 1 + 3 files changed, 10 insertions(+) diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c index 79d81def47f2..e06d39c94d0e 100644 --- a/sound/soc/msm/msm-cpe-lsm.c +++ b/sound/soc/msm/msm-cpe-lsm.c @@ -685,6 +685,7 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: No memory for sound model\n", __func__); kfree(session->conf_levels); + session->conf_levels = NULL; return -ENOMEM; } session->snd_model_size = snd_model.data_size; @@ -696,6 +697,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__); kfree(session->conf_levels); kfree(session->snd_model_data); + session->conf_levels = NULL; + session->snd_model_data = NULL; return -EFAULT; } @@ -707,6 +710,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__, rc); kfree(session->snd_model_data); kfree(session->conf_levels); + session->snd_model_data = NULL; + session->conf_levels = NULL; return rc; } @@ -720,6 +725,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session); kfree(session->snd_model_data); kfree(session->conf_levels); + session->snd_model_data = NULL; + session->conf_levels = NULL; return rc; } diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c index a93dfa6ec853..618da977ef1e 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c @@ -446,7 +446,9 @@ static void msm_dai_slim_remove_dai_data( dai_data_t = &drv_data->slim_dai_data[i]; kfree(dai_data_t->chan_h); + dai_data_t->chan_h = NULL; kfree(dai_data_t->sh_ch); + dai_data_t->sh_ch = NULL; } } diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c index 811844407dba..046bd4da60d6 100644 --- a/sound/soc/msm/qdsp6v2/q6lsm.c +++ b/sound/soc/msm/qdsp6v2/q6lsm.c @@ -285,6 +285,7 @@ void q6lsm_client_free(struct lsm_client *client) q6lsm_mmap_apr_dereg(); mutex_destroy(&client->cmd_lock); kfree(client); + client = NULL; } /* From 3026f276d0fbe7e96ea5369617d752c5bb525a45 Mon Sep 17 00:00:00 2001 From: Kamal Negi Date: Wed, 19 Oct 2016 18:59:11 +0530 Subject: [PATCH 015/281] radio-iris: check argument values before copying the data Check arguments passed in an ioctl before copying the data to kernel buffers. If user sends an erroneous data, data length more than expected, will lead to buffer overflow. Change-Id: I663e937806f38dc3b04c8d7662cd8b045facd12b Signed-off-by: Kamal Negi --- drivers/media/radio/radio-iris.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c index 6389978d2d41..dc539cc307b9 100644 --- a/drivers/media/radio/radio-iris.c +++ b/drivers/media/radio/radio-iris.c @@ -3718,8 +3718,20 @@ static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv, bytes_to_copy = (ctrl->controls[0]).size; spur_tbl_req.mode = data[0]; spur_tbl_req.no_of_freqs_entries = data[1]; - spur_data = kmalloc((data[1] * SPUR_DATA_LEN) + 2, - GFP_ATOMIC); + + if (((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) != + bytes_to_copy - 2) || + ((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) > + 2 * FM_SPUR_TBL_SIZE)) { + FMDERR("Invalid data len: data[1] = %d, bytes = %zu", + spur_tbl_req.no_of_freqs_entries, + bytes_to_copy); + retval = -EINVAL; + goto END; + } + spur_data = + kmalloc((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) + + 2, GFP_ATOMIC); if (!spur_data) { FMDERR("Allocation failed for Spur data"); retval = -EFAULT; @@ -3734,7 +3746,8 @@ static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv, if (spur_tbl_req.no_of_freqs_entries <= ENTRIES_EACH_CMD) { memcpy(&spur_tbl_req.spur_data[0], spur_data, - (data[1] * SPUR_DATA_LEN)); + (spur_tbl_req.no_of_freqs_entries * + SPUR_DATA_LEN)); retval = radio_hci_request(radio->fm_hdev, hci_fm_set_spur_tbl_req, (unsigned long)&spur_tbl_req, From 450ea787c96ccf90d3f06152118d1c00cfb52750 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 2 Nov 2016 17:43:51 -0700 Subject: [PATCH 016/281] ion: Fix use after free during ION_IOC_ALLOC If a user happens to call ION_IOC_FREE during an ION_IOC_ALLOC on the just allocated id, and the copy_to_user fails, the cleanup code will attempt to free an already freed handle. This adds a wrapper for ion_alloc that adds an ion_handle_get to avoid this. Bug: 31568617 Change-Id: I476e5bd5372b5178a213f1fea143d270cf9361ed Signed-off-by: Daniel Rosenberg --- drivers/staging/android/ion/ion.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 6ac8661e1233..7ae0407237d7 100755 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -506,9 +506,9 @@ static int ion_handle_add(struct ion_client *client, struct ion_handle *handle) return 0; } -struct ion_handle *ion_alloc(struct ion_client *client, size_t len, +static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len, size_t align, unsigned int heap_id_mask, - unsigned int flags) + unsigned int flags, bool grab_handle) { struct ion_handle *handle; struct ion_device *dev = client->dev; @@ -609,6 +609,8 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, return handle; mutex_lock(&client->lock); + if (grab_handle) + ion_handle_get(handle); ret = ion_handle_add(client, handle); mutex_unlock(&client->lock); if (ret) { @@ -618,6 +620,13 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, return handle; } + +struct ion_handle *ion_alloc(struct ion_client *client, size_t len, + size_t align, unsigned int heap_id_mask, + unsigned int flags) +{ + return __ion_alloc(client, len, align, heap_id_mask, flags, false); +} EXPORT_SYMBOL(ion_alloc); static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) @@ -1450,10 +1459,10 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ion_handle *handle; - handle = ion_alloc(client, data.allocation.len, + handle = __ion_alloc(client, data.allocation.len, data.allocation.align, data.allocation.heap_id_mask, - data.allocation.flags); + data.allocation.flags, true); if (IS_ERR(handle)) return PTR_ERR(handle); @@ -1529,11 +1538,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (dir & _IOC_READ) { if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { - if (cleanup_handle) + if (cleanup_handle) { ion_free(client, cleanup_handle); + ion_handle_put(cleanup_handle); + } return -EFAULT; } } + if (cleanup_handle) + ion_handle_put(cleanup_handle); return ret; } From 9cc868b8a97ac94dbb07d8e11acb7dce678520bc Mon Sep 17 00:00:00 2001 From: Siqi Lin Date: Wed, 4 Jan 2017 22:47:15 +0530 Subject: [PATCH 017/281] ALSA: info: Check for integer overflow in snd_info_entry_write() snd_info_entry_write() resizes the buffer with an unsigned long size argument that gets truncated because resize_info_buffer() takes the size parameter as an unsigned int. On 64-bit kernels, this causes the following copy_to_user() to write out-of-bounds if (pos + count) can't be represented by an unsigned int. Bug: 32510733 Change-Id: I9e8b55f93f2bd606b4a73b5a4525b71ee88c7c23 Signed-off-by: Siqi Lin --- sound/core/info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/core/info.c b/sound/core/info.c index e79baa11b60e..f94708590e61 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -253,6 +253,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer struct snd_info_buffer *buf; ssize_t size = 0; loff_t pos; + unsigned long realloc_size; data = file->private_data; if (snd_BUG_ON(!data)) @@ -261,7 +262,8 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer pos = *offset; if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) return -EIO; - if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) + realloc_size = (unsigned long) pos + (unsigned long) count; + if (realloc_size < (unsigned long) pos || realloc_size > UINT_MAX) return -EIO; switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: From a0264879c21b7e45798d035ace06efba721aea18 Mon Sep 17 00:00:00 2001 From: John Dias Date: Wed, 9 Nov 2016 11:03:57 -0800 Subject: [PATCH 018/281] perf: don't leave group_entry on sibling list (use-after-free) When perf_group_detach is called on a group leader, it should empty its sibling list. Otherwise, when a sibling is later deallocated, list_del_event() removes the sibling's group_entry from its current list, which can be the now-deallocated group leader's sibling list (use-after-free bug). Bug: 32402548 Change-Id: I99f6bc97c8518df1cb0035814368012ba72ab1f1 Signed-off-by: John Dias --- kernel/events/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index 3e6bfeff14d6..94d4e09bced6 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1314,10 +1314,17 @@ static void perf_group_detach(struct perf_event *event) * If this was a group event with sibling events then * upgrade the siblings to singleton events by adding them * to whatever list we are on. + * If this isn't on a list, make sure we still remove the sibling's + * group_entry from this sibling_list; otherwise, when that sibling + * is later deallocated, it will try to remove itself from this + * sibling_list, which may well have been deallocated already, + * resulting in a use-after-free. */ list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { if (list) list_move_tail(&sibling->group_entry, list); + else + list_del_init(&sibling->group_entry); sibling->group_leader = sibling; /* Inherit group flags from the previous leader */ From a23bec56bfe24d92cf885722ee4b5b5aeb6e6975 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Wed, 4 Jan 2017 22:36:11 +0530 Subject: [PATCH 019/281] msm: kgsl: fix sync file error handling We need to call put_unused_fd() on failure, but only if a file hasn't been stored into the fd yet. This function wasn't called from kgsl_ioctl_syncsource_create_fence() and was called incorrectly from kgsl_add_fence_event(). Reorder our sync_fence_install() calls to happen after all possible failures so that error cleanup will be correct. Bug: 32125137 Change-Id: I57a75447d1a430de7e5a93d5cd103269fc0b1e15 Signed-off-by: Jeremy Gebben --- drivers/gpu/msm/kgsl_sync.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index df181adb0a9d..dc63d9550dc6 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -202,7 +202,6 @@ int kgsl_add_fence_event(struct kgsl_device *device, ret = priv.fence_fd; goto unlock; } - sync_fence_install(fence, priv.fence_fd); /* * If the timestamp hasn't expired yet create an event to trigger it. @@ -229,6 +228,7 @@ int kgsl_add_fence_event(struct kgsl_device *device, ret = -EFAULT; goto out; } + sync_fence_install(fence, priv.fence_fd); return 0; @@ -606,6 +606,9 @@ long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv, if (ret) { if (fence) sync_fence_put(fence); + if (fd >= 0) + put_unused_fd(fd); + } kgsl_syncsource_put(syncsource); return ret; From 1356bae5325a31476dfa3a1429f531aab2092022 Mon Sep 17 00:00:00 2001 From: Siqi Lin Date: Wed, 4 Jan 2017 23:28:07 +0530 Subject: [PATCH 020/281] BACKPORT: msm: camera: Avoid exposing kernel addresses Usage of %p exposes the kernel addresses, an easy target to kernel write vulnerabilities. With this patch currently %pK prints only Zeros as address. If you need actual address echo 0 > /proc/sys/kernel/kptr_restrict Bug: 29464815 CRs-Fixed: 987011 Change-Id: Ieded0296301ef0935f0b685d1d0eb878a52d6b05 Signed-off-by: Azam Sadiq Pasha Kapatrala Syed Signed-off-by: Siqi Lin --- .../platform/msm/camera_v2/isp/msm_buf_mgr.c | 4 +-- .../msm/camera_v2/isp/msm_isp_axi_util.c | 4 +-- .../platform/msm/camera_v2/isp/msm_isp_util.c | 30 +++++++++---------- .../platform/msm/camera_v2/ispif/msm_ispif.c | 4 +-- .../msm/camera_v2/jpeg_10/msm_jpeg_hw.c | 2 +- .../msm/camera_v2/jpeg_10/msm_jpeg_sync.c | 2 +- .../platform/msm/camera_v2/msm_vb2/msm_vb2.c | 4 +-- .../msm/camera_v2/pproc/cpp/msm_cpp.c | 24 +++++++-------- .../msm/camera_v2/pproc/vpe/msm_vpe.c | 8 ++--- .../camera_v2/sensor/actuator/msm_actuator.c | 4 +-- .../msm/camera_v2/sensor/cci/msm_cci.c | 10 +++---- .../msm/camera_v2/sensor/csid/msm_csid.c | 6 ++-- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 10 +++---- .../msm/camera_v2/sensor/eeprom/msm_eeprom.c | 4 +-- .../camera_v2/sensor/io/msm_camera_dt_util.c | 6 ++-- .../camera_v2/sensor/io/msm_camera_io_util.c | 16 +++++----- .../msm/camera_v2/sensor/msm_sensor.c | 22 +++++++------- .../msm/camera_v2/sensor/msm_sensor_driver.c | 30 +++++++++---------- .../msm/camera_v2/sensor/msm_sensor_init.c | 8 ++--- .../msm/camera_v2/sensor/ois/msm_ois.c | 4 +-- 20 files changed, 101 insertions(+), 101 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index bfd706b1d802..f10df1d46ca3 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -145,7 +145,7 @@ static int msm_isp_prepare_isp_buf(struct msm_isp_buf_mgr *buf_mgr, ion_import_dma_buf(buf_mgr->client, qbuf_buf->planes[i].addr); if (IS_ERR_OR_NULL(mapped_info->handle)) { - pr_err("%s: buf has null/error ION handle %p\n", + pr_err("%s: buf has null/error ION handle %pK\n", __func__, mapped_info->handle); goto ion_map_error; } @@ -1151,7 +1151,7 @@ int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr) __func__, k, (unsigned int) bufs->mapped_info[k].paddr, bufs->mapped_info[k].len); - pr_err(" ion handle %p\n", + pr_err(" ion handle %pK\n", bufs->mapped_info[k].handle); } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index cf2d80f6ea43..5cec55eed6eb 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1390,7 +1390,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, struct msm_isp_bufq *bufq = NULL; if (!reset_cmd) { - pr_err("%s: NULL pointer reset cmd %p\n", __func__, reset_cmd); + pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd); rc = -1; return rc; } @@ -1415,7 +1415,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr, stream_info->bufq_handle); if (!bufq) { - pr_err("%s: bufq null %p by handle %x\n", __func__, + pr_err("%s: bufq null %pK by handle %x\n", __func__, bufq, stream_info->bufq_handle); continue; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index ba37cecab49d..51396b718c25 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -82,7 +82,7 @@ void msm_camera_io_dump_2(void __iomem *addr, int size) int i; u32 *p = (u32 *) addr; u32 data; - pr_err("%s: %p %d\n", __func__, addr, size); + pr_err("%s: %pK %d\n", __func__, addr, size); line_str[0] = '\0'; p_str = line_str; for (i = 0; i < size/4; i++) { @@ -385,14 +385,14 @@ static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) long round_rate = 0; if (!vfe_dev || !rate) { - pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__, + pr_err("%s:%d failed: vfe_dev %pK rate %pK\n", __func__, __LINE__, vfe_dev, rate); return -EINVAL; } *rate = 0; if (!vfe_dev->hw_info) { - pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__, + pr_err("%s:%d failed: vfe_dev->hw_info %pK\n", __func__, __LINE__, vfe_dev->hw_info); return -EINVAL; } @@ -540,7 +540,7 @@ static int msm_isp_proc_cmd_list_unlocked(struct vfe_device *vfe_dev, void *arg) struct msm_vfe_cfg_cmd_list cmd, cmd_next; if (!vfe_dev || !arg) { - pr_err("%s:%d failed: vfe_dev %p arg %p", __func__, __LINE__, + pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__, vfe_dev, arg); return -EINVAL; } @@ -610,7 +610,7 @@ static int msm_isp_proc_cmd_list_compat(struct vfe_device *vfe_dev, void *arg) struct msm_vfe_cfg_cmd2 current_cmd; if (!vfe_dev || !arg) { - pr_err("%s:%d failed: vfe_dev %p arg %p", __func__, __LINE__, + pr_err("%s:%d failed: vfe_dev %pK arg %pK", __func__, __LINE__, vfe_dev, arg); return -EINVAL; } @@ -666,10 +666,10 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); if (!vfe_dev || !vfe_dev->vfe_base) { - pr_err("%s:%d failed: invalid params %p\n", + pr_err("%s:%d failed: invalid params %pK\n", __func__, __LINE__, vfe_dev); if (vfe_dev) - pr_err("%s:%d failed %p\n", __func__, + pr_err("%s:%d failed %pK\n", __func__, __LINE__, vfe_dev->vfe_base); return -EINVAL; } @@ -804,10 +804,10 @@ static long msm_isp_ioctl_compat(struct v4l2_subdev *sd, long rc = 0; if (!vfe_dev || !vfe_dev->vfe_base) { - pr_err("%s:%d failed: invalid params %p\n", + pr_err("%s:%d failed: invalid params %pK\n", __func__, __LINE__, vfe_dev); if (vfe_dev) - pr_err("%s:%d failed %p\n", __func__, + pr_err("%s:%d failed %pK\n", __func__, __LINE__, vfe_dev->vfe_base); return -EINVAL; } @@ -882,13 +882,13 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, uint32_t *cfg_data, uint32_t cmd_len) { if (!vfe_dev || !reg_cfg_cmd) { - pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__, + pr_err("%s:%d failed: vfe_dev %pK reg_cfg_cmd %pK\n", __func__, __LINE__, vfe_dev, reg_cfg_cmd); return -EINVAL; } if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && (!cfg_data || !cmd_len)) { - pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n", + pr_err("%s:%d failed: cmd type %d cfg_data %pK cmd_len %d\n", __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, cmd_len); return -EINVAL; @@ -1742,17 +1742,17 @@ static int msm_vfe_iommu_fault_handler(struct iommu_domain *domain, if (token) { vfe_dev = (struct vfe_device *)token; if (!vfe_dev->buf_mgr || !vfe_dev->buf_mgr->ops) { - pr_err("%s:%d] buf_mgr %p\n", __func__, + pr_err("%s:%d] buf_mgr %pK\n", __func__, __LINE__, vfe_dev->buf_mgr); goto end; } if (!vfe_dev->buf_mgr->pagefault_debug) { - pr_err("%s:%d] vfe_dev %p id %d\n", __func__, + pr_err("%s:%d] vfe_dev %pK id %d\n", __func__, __LINE__, vfe_dev, vfe_dev->pdev->id); vfe_dev->buf_mgr->ops->buf_mgr_debug(vfe_dev->buf_mgr); } } else { - ISP_DBG("%s:%d] no token received: %p\n", + ISP_DBG("%s:%d] no token received: %pK\n", __func__, __LINE__, token); goto end; } @@ -1776,7 +1776,7 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) } if (vfe_dev->vfe_base) { - pr_err("%s:%d invalid params cnt %d base %p\n", __func__, + pr_err("%s:%d invalid params cnt %d base %pK\n", __func__, __LINE__, vfe_dev->vfe_open_cnt, vfe_dev->vfe_base); vfe_dev->vfe_base = NULL; } diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 2aee456f1985..ea8f12ce37ec 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1172,7 +1172,7 @@ static int msm_ispif_set_vfe_info(struct ispif_device *ispif, { if (!vfe_info || (vfe_info->num_vfe <= 0) || ((uint32_t)(vfe_info->num_vfe) > ispif->hw_num_isps)) { - pr_err("Invalid VFE info: %p %d\n", vfe_info, + pr_err("Invalid VFE info: %pK %d\n", vfe_info, (vfe_info ? vfe_info->num_vfe:0)); return -EINVAL; } @@ -1207,7 +1207,7 @@ static int msm_ispif_init(struct ispif_device *ispif, if (ispif->csid_version >= CSID_VERSION_V30) { if (!ispif->clk_mux_mem || !ispif->clk_mux_io) { - pr_err("%s csi clk mux mem %p io %p\n", __func__, + pr_err("%s csi clk mux mem %pK io %pK\n", __func__, ispif->clk_mux_mem, ispif->clk_mux_io); rc = -ENOMEM; return rc; diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index a129a668c447..d67ab1119d46 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -562,7 +562,7 @@ void msm_jpeg_io_dump(void *base, int size) int i; u32 *p = (u32 *) addr; u32 data; - JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size); + JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); line_str[0] = '\0'; p_str = line_str; for (i = 0; i < size/4; i++) { diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c index 2a7675cb14a2..424881bad211 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c @@ -736,7 +736,7 @@ int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev) return rc; } - JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n", + JPEG_DBG("%s:%d] platform resources - mem %pK, base %pK, irq %d\n", __func__, __LINE__, pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq); pgmn_dev->res_size = resource_size(pgmn_dev->mem); diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index f9c0bd7d0225..7bd479aa4d62 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -241,7 +241,7 @@ static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, break; } if (vb2_buf != vb) { - pr_err("VB buffer is INVALID vb=%p, ses_id=%d, str_id=%d\n", + pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); return -EINVAL; @@ -282,7 +282,7 @@ static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, break; } if (vb2_buf != vb) { - pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%p\n", + pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index afdb941b3f09..442ab81d46ff 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1059,7 +1059,7 @@ static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) rc = request_firmware(&fw, fw_name_bin, dev); if (rc) { dev_err(dev, - "Fail to loc blob %s from dev %p, Error: %d\n", + "Fail to loc blob %s from dev %pK, Error: %d\n", fw_name_bin, dev, rc); } if (NULL != fw) @@ -1136,13 +1136,13 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) CPP_DBG("E\n"); if (!sd || !fh) { - pr_err("Wrong input parameters sd %p fh %p!", + pr_err("Wrong input parameters sd %pK fh %pK!", sd, fh); return -EINVAL; } cpp_dev = v4l2_get_subdevdata(sd); if (!cpp_dev) { - pr_err("failed: cpp_dev %p\n", cpp_dev); + pr_err("failed: cpp_dev %pK\n", cpp_dev); return -EINVAL; } mutex_lock(&cpp_dev->mutex); @@ -1165,7 +1165,7 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -ENODEV; } - CPP_DBG("open %d %p\n", i, &fh->vfh); + CPP_DBG("open %d %pK\n", i, &fh->vfh); cpp_dev->cpp_open_cnt++; if (cpp_dev->cpp_open_cnt == 1) { rc = cpp_init_hardware(cpp_dev); @@ -1198,7 +1198,7 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) cpp_dev = v4l2_get_subdevdata(sd); if (!cpp_dev) { - pr_err("failed: cpp_dev %p\n", cpp_dev); + pr_err("failed: cpp_dev %pK\n", cpp_dev); return -EINVAL; } @@ -1398,7 +1398,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work) pr_err("cpp_timer_callback called. (jiffies=%lu)\n", jiffies); if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) { - pr_err("Invalid work:%p or state:%d\n", work, + pr_err("Invalid work:%pK or state:%d\n", work, cpp_timer.data.cpp_dev->state); return; } @@ -1848,12 +1848,12 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, int ret; if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0) || (ioctl_ptr->len >= MSM_CPP_MAX_FW_NAME_LEN)) { - pr_err("Wrong ioctl_ptr %p\n", ioctl_ptr); + pr_err("Wrong ioctl_ptr %pK\n", ioctl_ptr); return -EINVAL; } if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { - pr_err("%s: Wrong ioctl_ptr %p / len %zu\n", __func__, + pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); return -EINVAL; } @@ -1876,7 +1876,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr, { int ret; if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) { - pr_err("%s: Wrong ioctl_ptr %p / len %zu\n", __func__, + pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__, ioctl_ptr, ioctl_ptr->len); return -EINVAL; } @@ -2403,14 +2403,14 @@ static long msm_cpp_subdev_do_ioctl( struct v4l2_fh *vfh = NULL; if ((arg == NULL) || (file == NULL)) { - pr_err("Invalid input parameters arg %p, file %p\n", arg, file); + pr_err("Invalid input parameters arg %pK, file %pK\n", arg, file); return -EINVAL; } vdev = video_devdata(file); sd = vdev_to_v4l2_subdev(vdev); if (sd == NULL) { - pr_err("Invalid input parameter sd %p\n", sd); + pr_err("Invalid input parameter sd %pK\n", sd); return -EINVAL; } vfh = file->private_data; @@ -2622,7 +2622,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, } cpp_dev = v4l2_get_subdevdata(sd); if (!vdev || !cpp_dev) { - pr_err("Invalid vdev %p or cpp_dev %p structures!", + pr_err("Invalid vdev %pK or cpp_dev %pK structures!", vdev, cpp_dev); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c index 11f806bbf0b0..2eb6bc90b703 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c +++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c @@ -52,12 +52,12 @@ static void vpe_mem_dump(const char * const name, const void * const addr, int i; u32 *p = (u32 *) addr; u32 data; - VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size); + VPE_DBG("%s: (%s) %pK %d\n", __func__, name, addr, size); line_str[0] = '\0'; p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - snprintf(p_str, 12, "%p: ", p); + snprintf(p_str, 12, "%pK: ", p); p_str += 10; } data = *p++; @@ -594,7 +594,7 @@ static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) goto err_mutex_unlock; } - VPE_DBG("open %d %p\n", i, &fh->vfh); + VPE_DBG("open %d %pK\n", i, &fh->vfh); vpe_dev->vpe_open_cnt++; if (vpe_dev->vpe_open_cnt == 1) { rc = vpe_init_hardware(vpe_dev); @@ -649,7 +649,7 @@ static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -ENODEV; } - VPE_DBG("close %d %p\n", i, &fh->vfh); + VPE_DBG("close %d %pK\n", i, &fh->vfh); vpe_dev->vpe_open_cnt--; if (vpe_dev->vpe_open_cnt == 0) { vpe_deinit_mem(vpe_dev); diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 6687f6bb4667..79b0ee0bf373 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1466,7 +1466,7 @@ static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd, struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); void __user *argp = (void __user *)arg; CDBG("Enter\n"); - CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, a_ctrl, argp); + CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, a_ctrl, argp); switch (cmd) { case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: return msm_actuator_get_subdev_id(a_ctrl, argp); @@ -1713,7 +1713,7 @@ static int32_t msm_actuator_i2c_probe(struct i2c_client *client, goto probe_failure; } - CDBG("client = 0x%p\n", client); + CDBG("client = 0x%pK\n", client); rc = of_property_read_u32(client->dev.of_node, "cell-index", &act_ctrl_t->subdev_id); diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index fd3dfef9e421..91a4b8240327 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -467,7 +467,7 @@ static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, uint16_t read_bytes = 0; if (!sd || !c_ctrl) { - pr_err("%s:%d sd %p c_ctrl %p\n", __func__, + pr_err("%s:%d sd %pK c_ctrl %pK\n", __func__, __LINE__, sd, c_ctrl); return -EINVAL; } @@ -746,7 +746,7 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { - pr_err("%s:%d failed: invalid params %p %p\n", __func__, + pr_err("%s:%d failed: invalid params %pK %pK\n", __func__, __LINE__, cci_dev, c_ctrl); rc = -ENOMEM; return rc; @@ -1330,7 +1330,7 @@ static int msm_cci_probe(struct platform_device *pdev) { struct cci_device *new_cci_dev; int rc = 0; - CDBG("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id); + CDBG("%s: pdev %pK device id = %d\n", __func__, pdev, pdev->id); new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL); if (!new_cci_dev) { CDBG("%s: no enough memory\n", __func__); @@ -1342,7 +1342,7 @@ static int msm_cci_probe(struct platform_device *pdev) ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci"); v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev); platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd); - CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd); + CDBG("%s sd %pK\n", __func__, &new_cci_dev->msm_sd.sd); if (pdev->dev.of_node) of_property_read_u32((&pdev->dev)->of_node, "cell-index", &pdev->id); @@ -1407,7 +1407,7 @@ static int msm_cci_probe(struct platform_device *pdev) pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc); new_cci_dev->cci_state = CCI_STATE_DISABLED; g_cci_subdev = &new_cci_dev->msm_sd.sd; - CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd); + CDBG("%s cci subdev %pK\n", __func__, &new_cci_dev->msm_sd.sd); CDBG("%s line %d\n", __func__, __LINE__); return 0; diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 35ef57b84876..04c1665cc369 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -145,7 +145,7 @@ static int msm_csid_config(struct csid_device *csid_dev, void __iomem *csidbase; csidbase = csid_dev->base; if (!csidbase || !csid_params) { - pr_err("%s:%d csidbase %p, csid params %p\n", __func__, + pr_err("%s:%d csidbase %pK, csid params %pK\n", __func__, __LINE__, csidbase, csid_params); return -EINVAL; } @@ -476,7 +476,7 @@ static int32_t msm_csid_cmd(struct csid_device *csid_dev, void __user *arg) struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg; if (!csid_dev || !cdata) { - pr_err("%s:%d csid_dev %p, cdata %p\n", __func__, __LINE__, + pr_err("%s:%d csid_dev %pK, cdata %pK\n", __func__, __LINE__, csid_dev, cdata); return -EINVAL; } @@ -597,7 +597,7 @@ static int32_t msm_csid_cmd32(struct csid_device *csid_dev, void __user *arg) cdata = &local_arg; if (!csid_dev || !cdata) { - pr_err("%s:%d csid_dev %p, cdata %p\n", __func__, __LINE__, + pr_err("%s:%d csid_dev %pK, cdata %pK\n", __func__, __LINE__, csid_dev, cdata); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 137be497850e..02803007421c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -123,7 +123,7 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, val |= csiphy_params->csid_core; } msm_camera_io_w(val, csiphy_dev->clk_mux_base); - CDBG("%s clk mux addr %p val 0x%x\n", __func__, + CDBG("%s clk mux addr %pK val 0x%x\n", __func__, csiphy_dev->clk_mux_base, val); mb(); } @@ -322,7 +322,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->num_clk, 1); } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { - pr_err("%s clk mux mem %p io %p\n", __func__, + pr_err("%s clk mux mem %pK io %pK\n", __func__, csiphy_dev->clk_mux_mem, csiphy_dev->clk_mux_io); rc = -ENOMEM; @@ -418,7 +418,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev) csiphy_dev->num_clk, 1); } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { - pr_err("%s clk mux mem %p io %p\n", __func__, + pr_err("%s clk mux mem %pK io %pK\n", __func__, csiphy_dev->clk_mux_mem, csiphy_dev->clk_mux_io); rc = -ENOMEM; @@ -499,7 +499,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) mipi_csiphy_lnn_cfg2_addr + 0x40*i); } else { if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + pr_err("%s:%d failed: csi_lane_params %pK\n", __func__, __LINE__, csi_lane_params); return -EINVAL; } @@ -592,7 +592,7 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) mipi_csiphy_lnn_cfg2_addr + 0x40*i); } else { if (!csi_lane_params) { - pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + pr_err("%s:%d failed: csi_lane_params %pK\n", __func__, __LINE__, csi_lane_params); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index b6f3716e81b5..d869951dbc0d 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -188,7 +188,7 @@ static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); void __user *argp = (void __user *)arg; CDBG("%s E\n", __func__); - CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); + CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp); switch (cmd) { case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: return msm_eeprom_get_subdev_id(e_ctrl, argp); @@ -983,7 +983,7 @@ static long msm_eeprom_subdev_ioctl32(struct v4l2_subdev *sd, void __user *argp = (void __user *)arg; CDBG("%s E\n", __func__); - CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); + CDBG("%s:%d a_ctrl %pK argp %pK\n", __func__, __LINE__, e_ctrl, argp); switch (cmd) { case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: return msm_eeprom_get_subdev_id(e_ctrl, argp); diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index 221ca338c6d8..3fdf570e100a 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -36,7 +36,7 @@ int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, /* Validate input parameters */ if (!cam_vreg || !power_setting) { - pr_err("%s:%d failed: cam_vreg %p power_setting %p", __func__, + pr_err("%s:%d failed: cam_vreg %pK power_setting %pK", __func__, __LINE__, cam_vreg, power_setting); return -EINVAL; } @@ -1235,7 +1235,7 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, CDBG("%s:%d\n", __func__, __LINE__); if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl, sensor_i2c_client); return -EINVAL; } @@ -1454,7 +1454,7 @@ int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, CDBG("%s:%d\n", __func__, __LINE__); if (!ctrl || !sensor_i2c_client) { - pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + pr_err("failed ctrl %pK sensor_i2c_client %pK\n", ctrl, sensor_i2c_client); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c index 41c784a7f7b6..b11d819b7823 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c @@ -27,13 +27,13 @@ void msm_camera_io_w(u32 data, void __iomem *addr) { - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); writel_relaxed((data), (addr)); } void msm_camera_io_w_mb(u32 data, void __iomem *addr) { - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); wmb(); writel_relaxed((data), (addr)); wmb(); @@ -42,7 +42,7 @@ void msm_camera_io_w_mb(u32 data, void __iomem *addr) u32 msm_camera_io_r(void __iomem *addr) { uint32_t data = readl_relaxed(addr); - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); return data; } @@ -52,7 +52,7 @@ u32 msm_camera_io_r_mb(void __iomem *addr) rmb(); data = readl_relaxed(addr); rmb(); - CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); return data; } @@ -73,12 +73,12 @@ void msm_camera_io_dump(void __iomem *addr, int size) int i; u32 *p = (u32 *) addr; u32 data; - CDBG("%s: %p %d\n", __func__, addr, size); + CDBG("%s: %pK %d\n", __func__, addr, size); line_str[0] = '\0'; p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - snprintf(p_str, 12, "0x%p: ", p); + snprintf(p_str, 12, "0x%pK: ", p); p_str += 10; } data = readl_relaxed(p++); @@ -97,7 +97,7 @@ void msm_camera_io_dump(void __iomem *addr, int size) void msm_camera_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len) { - CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + CDBG("%s: %pK %pK %d\n", __func__, dest_addr, src_addr, len); msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4); msm_camera_io_dump(dest_addr, len); } @@ -586,7 +586,7 @@ int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, int rc = 0, i = 0, err = 0; if (!gpio_tbl || !size) { - pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__, + pr_err("%s:%d invalid gpio_tbl %pK / size %d\n", __func__, __LINE__, gpio_tbl, size); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c index 3fc05395bdc4..915bc385e6e1 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c @@ -424,7 +424,7 @@ int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) struct msm_camera_i2c_client *sensor_i2c_client; if (!s_ctrl) { - pr_err("%s:%d failed: s_ctrl %p\n", + pr_err("%s:%d failed: s_ctrl %pK\n", __func__, __LINE__, s_ctrl); return -EINVAL; } @@ -434,7 +434,7 @@ int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) sensor_i2c_client = s_ctrl->sensor_i2c_client; if (!power_info || !sensor_i2c_client) { - pr_err("%s:%d failed: power_info %p sensor_i2c_client %p\n", + pr_err("%s:%d failed: power_info %pK sensor_i2c_client %pK\n", __func__, __LINE__, power_info, sensor_i2c_client); return -EINVAL; } @@ -454,7 +454,7 @@ int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) struct msm_camera_sensor_slave_info *camera_info; if (!s_ctrl) { - pr_err("%s:%d failed: %p\n", + pr_err("%s:%d failed: %pK\n", __func__, __LINE__, s_ctrl); return -EINVAL; } @@ -466,7 +466,7 @@ int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) if (!power_info || !sensor_i2c_client || !slave_info || !sensor_name) { - pr_err("%s:%d failed: %p %p %p %p\n", + pr_err("%s:%d failed: %pK %pK %pK %pK\n", __func__, __LINE__, power_info, sensor_i2c_client, slave_info, sensor_name); return -EINVAL; @@ -576,7 +576,7 @@ int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) const char *sensor_name; if (!s_ctrl) { - pr_err("%s:%d failed: %p\n", + pr_err("%s:%d failed: %pK\n", __func__, __LINE__, s_ctrl); return -EINVAL; } @@ -585,7 +585,7 @@ int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) sensor_name = s_ctrl->sensordata->sensor_name; if (!sensor_i2c_client || !slave_info || !sensor_name) { - pr_err("%s:%d failed: %p %p %p\n", + pr_err("%s:%d failed: %pK %pK %pK\n", __func__, __LINE__, sensor_i2c_client, slave_info, sensor_name); return -EINVAL; @@ -1555,7 +1555,7 @@ int32_t msm_sensor_platform_probe(struct platform_device *pdev, uint32_t session_id; unsigned long mount_pos = 0; s_ctrl->pdev = pdev; - CDBG("%s called data %p\n", __func__, data); + CDBG("%s called data %pK\n", __func__, data); CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name); if (pdev->dev.of_node) { rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl); @@ -1778,13 +1778,13 @@ int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) /* Validate input parameters */ if (!s_ctrl) { - pr_err("%s:%d failed: invalid params s_ctrl %p\n", __func__, + pr_err("%s:%d failed: invalid params s_ctrl %pK\n", __func__, __LINE__, s_ctrl); return -EINVAL; } if (!s_ctrl->sensor_i2c_client) { - pr_err("%s:%d failed: invalid params sensor_i2c_client %p\n", + pr_err("%s:%d failed: invalid params sensor_i2c_client %pK\n", __func__, __LINE__, s_ctrl->sensor_i2c_client); return -EINVAL; } @@ -1793,7 +1793,7 @@ int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( struct msm_camera_cci_client), GFP_KERNEL); if (!s_ctrl->sensor_i2c_client->cci_client) { - pr_err("%s:%d failed: no memory cci_client %p\n", __func__, + pr_err("%s:%d failed: no memory cci_client %pK\n", __func__, __LINE__, s_ctrl->sensor_i2c_client->cci_client); return -ENOMEM; } @@ -1827,7 +1827,7 @@ int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) /* Initialize clock info */ clk_info = kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); if (!clk_info) { - pr_err("%s:%d failed no memory clk_info %p\n", __func__, + pr_err("%s:%d failed no memory clk_info %pK\n", __func__, __LINE__, clk_info); rc = -ENOMEM; goto FREE_CCI_CLIENT; diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 956a6cbf8520..e42d65c9f5ea 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -459,7 +459,7 @@ static int32_t msm_sensor_get_power_down_settings(void *setting, /* Allocate memory for power down setting */ pd = kzalloc(sizeof(*pd) * size_down, GFP_KERNEL); if (!pd) { - pr_err("failed: no memory power_setting %p", pd); + pr_err("failed: no memory power_setting %pK", pd); return -EFAULT; } @@ -526,7 +526,7 @@ static int32_t msm_sensor_get_power_up_settings(void *setting, /* Allocate memory for power up setting */ pu = kzalloc(sizeof(*pu) * size, GFP_KERNEL); if (!pu) { - pr_err("failed: no memory power_setting %p", pu); + pr_err("failed: no memory power_setting %pK", pu); return -ENOMEM; } @@ -896,14 +896,14 @@ int32_t msm_sensor_driver_probe(void *setting, /* Validate input parameters */ if (!setting) { - pr_err("failed: slave_info %p", setting); + pr_err("failed: slave_info %pK", setting); return -EINVAL; } /* Allocate memory for slave info */ slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL); if (!slave_info) { - pr_err("failed: no memory slave_info %p", slave_info); + pr_err("failed: no memory slave_info %pK", slave_info); return -ENOMEM; } #ifdef CONFIG_COMPAT @@ -992,13 +992,13 @@ int32_t msm_sensor_driver_probe(void *setting, /* Extract s_ctrl from camera id */ s_ctrl = g_sctrl[slave_info->camera_id]; if (!s_ctrl) { - pr_err("failed: s_ctrl %p for camera_id %d", s_ctrl, + pr_err("failed: s_ctrl %pK for camera_id %d", s_ctrl, slave_info->camera_id); rc = -EINVAL; goto free_slave_info; } - CDBG("s_ctrl[%d] %p", slave_info->camera_id, s_ctrl); + CDBG("s_ctrl[%d] %pK", slave_info->camera_id, s_ctrl); if (s_ctrl->is_probe_succeed == 1) { /* @@ -1033,7 +1033,7 @@ int32_t msm_sensor_driver_probe(void *setting, camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL); if (!camera_info) { - pr_err("failed: no memory slave_info %p", camera_info); + pr_err("failed: no memory slave_info %pK", camera_info); goto free_slave_info; } @@ -1048,7 +1048,7 @@ int32_t msm_sensor_driver_probe(void *setting, /* Fill CCI master, slave address and CCI default params */ if (!s_ctrl->sensor_i2c_client) { - pr_err("failed: sensor_i2c_client %p", + pr_err("failed: sensor_i2c_client %pK", s_ctrl->sensor_i2c_client); rc = -EINVAL; goto free_camera_info; @@ -1061,7 +1061,7 @@ int32_t msm_sensor_driver_probe(void *setting, cci_client = s_ctrl->sensor_i2c_client->cci_client; if (!cci_client) { - pr_err("failed: cci_client %p", cci_client); + pr_err("failed: cci_client %pK", cci_client); goto free_camera_info; } cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; @@ -1225,7 +1225,7 @@ static int32_t msm_sensor_driver_get_gpio_data( /* Validate input paramters */ if (!sensordata || !of_node) { - pr_err("failed: invalid params sensordata %p of_node %p", + pr_err("failed: invalid params sensordata %pK of_node %pK", sensordata, of_node); return -EINVAL; } @@ -1408,7 +1408,7 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client), GFP_KERNEL); if (!s_ctrl->sensor_i2c_client) { - pr_err("failed: no memory sensor_i2c_client %p", + pr_err("failed: no memory sensor_i2c_client %pK", s_ctrl->sensor_i2c_client); return -ENOMEM; } @@ -1417,7 +1417,7 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex), GFP_KERNEL); if (!s_ctrl->msm_sensor_mutex) { - pr_err("failed: no memory msm_sensor_mutex %p", + pr_err("failed: no memory msm_sensor_mutex %pK", s_ctrl->msm_sensor_mutex); goto FREE_SENSOR_I2C_CLIENT; } @@ -1446,7 +1446,7 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) /* Store sensor control structure in static database */ g_sctrl[s_ctrl->id] = s_ctrl; - pr_err("g_sctrl[%d] %p", s_ctrl->id, g_sctrl[s_ctrl->id]); + pr_err("g_sctrl[%d] %pK", s_ctrl->id, g_sctrl[s_ctrl->id]); return rc; @@ -1471,7 +1471,7 @@ static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev) /* Create sensor control structure */ s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); if (!s_ctrl) { - pr_err("failed: no memory s_ctrl %p", s_ctrl); + pr_err("failed: no memory s_ctrl %pK", s_ctrl); return -ENOMEM; } @@ -1516,7 +1516,7 @@ static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, /* Create sensor control structure */ s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); if (!s_ctrl) { - pr_err("failed: no memory s_ctrl %p", s_ctrl); + pr_err("failed: no memory s_ctrl %pK", s_ctrl); return -ENOMEM; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c index a612265fc801..2505c0577137 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c @@ -64,7 +64,7 @@ static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, /* Validate input parameters */ if (!s_init || !cfg) { - pr_err("failed: s_init %p cfg %p", s_init, cfg); + pr_err("failed: s_init %pK cfg %pK", s_init, cfg); return -EINVAL; } @@ -106,7 +106,7 @@ static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, /* Validate input parameters */ if (!s_init) { - pr_err("failed: s_init %p", s_init); + pr_err("failed: s_init %pK", s_init); return -EINVAL; } @@ -168,11 +168,11 @@ static int __init msm_sensor_init_module(void) /* Allocate memory for msm_sensor_init control structure */ s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL); if (!s_init) { - pr_err("failed: no memory s_init %p", NULL); + pr_err("failed: no memory s_init %pK", NULL); return -ENOMEM; } - CDBG("MSM_SENSOR_INIT_MODULE %p", NULL); + CDBG("MSM_SENSOR_INIT_MODULE %pK", NULL); /* Initialize mutex */ mutex_init(&s_init->imutex); diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index 86df5f0a3655..aed7b394b2c6 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -408,7 +408,7 @@ static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, struct msm_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); void __user *argp = (void __user *)arg; CDBG("Enter\n"); - CDBG("%s:%d o_ctrl %p argp %p\n", __func__, __LINE__, o_ctrl, argp); + CDBG("%s:%d o_ctrl %pK argp %pK\n", __func__, __LINE__, o_ctrl, argp); switch (cmd) { case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: return msm_ois_get_subdev_id(o_ctrl, argp); @@ -492,7 +492,7 @@ static int32_t msm_ois_i2c_probe(struct i2c_client *client, goto probe_failure; } - CDBG("client = 0x%p\n", client); + CDBG("client = 0x%pK\n", client); rc = of_property_read_u32(client->dev.of_node, "cell-index", &ois_ctrl_t->subdev_id); From 3e374471e739dc7c7327d6fc3a63f66e2dc42745 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Dec 2016 17:33:06 +0100 Subject: [PATCH 021/281] ALSA: pcm : Call kill_fasync() in stream lock commit 3aa02cb664c5fb1042958c8d1aa8c35055a2ebc4 upstream. Currently kill_fasync() is called outside the stream lock in snd_pcm_period_elapsed(). This is potentially racy, since the stream may get released even during the irq handler is running. Although snd_pcm_release_substream() calls snd_pcm_drop(), this doesn't guarantee that the irq handler finishes, thus the kill_fasync() call outside the stream spin lock may be invoked after the substream is detached, as recently reported by KASAN. As a quick workaround, move kill_fasync() call inside the stream lock. The fasync is rarely used interface, so this shouldn't have a big impact from the performance POV. Ideally, we should implement some sync mechanism for the proper finish of stream and irq handler. But this oneliner should suffice for most cases, so far. Change-Id: Ic06f5367153223bb29904672fec26e8294df3529 Reported-by: Baozeng Ding Signed-off-by: Takashi Iwai Signed-off-by: Jiri Slaby --- sound/core/pcm_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f26e71cbe551..868ae20d9042 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1868,10 +1868,10 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) if (substream->timer_running) snd_timer_interrupt(substream->timer, 1); _end: + kill_fasync(&runtime->fasync, SIGIO, POLL_IN); snd_pcm_stream_unlock_irqrestore(substream, flags); if (runtime->transfer_ack_end) runtime->transfer_ack_end(substream); - kill_fasync(&runtime->fasync, SIGIO, POLL_IN); } EXPORT_SYMBOL(snd_pcm_period_elapsed); From a5aeefa2dd0cb3cc54a4dc5bb47c6facb07c48bc Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Wed, 16 Nov 2016 18:22:58 -0800 Subject: [PATCH 022/281] msm: cpp: Fix for buffer overflow in cpp. Fix for buffer overflow while handling ioctl. Instead of checking for length boundary, fix checks for exact length. CRs-Fixed: 518731 Change-Id: I9002f84b219e8b06ae0672d87c2d999e728a75aa Signed-off-by: Krishnankutty Kolathappilly --- drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 442ab81d46ff..eeafe6d66900 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -2111,8 +2111,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, uint32_t identity; struct msm_cpp_buff_queue_info_t *buff_queue_info; CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); - if ((ioctl_ptr->len == 0) || - (ioctl_ptr->len > sizeof(uint32_t))) { + if (ioctl_ptr->len != sizeof(uint32_t)) { mutex_unlock(&cpp_dev->mutex); return -EINVAL; } From 8f46d9909f1da6c95f77fb452c9cea55e36df30c Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Mon, 28 Nov 2016 18:23:33 +0530 Subject: [PATCH 023/281] qcrypto: protect potential integer overflow. Adding user passed parameters without check might lead to Integer overflow and unpredictable system behaviour. Change-Id: Iaf8259e3c4a157e1790f1447b1b62a646988b7c4 Signed-off-by: Neeraj Soni Signed-off-by: Yang Guang --- drivers/crypto/msm/qce50.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 9e5afc724df1..5522be9488ec 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -4481,6 +4481,12 @@ int qce_aead_req(void *handle, struct qce_req *q_req) else q_req->cryptlen = areq->cryptlen - authsize; + if ((q_req->cryptlen > UINT_MAX - areq->assoclen) || + (q_req->cryptlen + areq->assoclen > UINT_MAX - ivsize)) { + pr_err("Integer overflow on total aead req length.\n"); + return -EINVAL; + } + totallen = q_req->cryptlen + areq->assoclen + ivsize; if (pce_dev->support_cmd_dscr) { From e90b1b8c495f989bdc16669dae90b903fa119b38 Mon Sep 17 00:00:00 2001 From: Alberto97 Date: Thu, 5 Jan 2017 16:23:21 +0100 Subject: [PATCH 024/281] Revert unfinished sdcardfs patches Change-Id: Idc757f2f647bbe725be70c1dec567f1dd8d7a1d2 Revert "sdcardfs: override umask on mkdir and create" This reverts commit 5710070f29810bc0fecc08b3f093644d1884a2a5. Revert "sdcardfs: Added top to sdcardfs_inode_info" This reverts commit 2deb682e9d85b4623de8efba4b47f5c5e25e5b39. Revert "sdcardfs: Fix locking" This reverts commit 85917fb9514221ac6738dd011aeef5247c7f4357. --- fs/fs_struct.c | 1 - fs/sdcardfs/derived_perm.c | 72 ++++------------------------- fs/sdcardfs/inode.c | 94 +++++++++++++++++--------------------- fs/sdcardfs/lookup.c | 5 +- fs/sdcardfs/main.c | 4 +- fs/sdcardfs/packagelist.c | 40 ++++++++-------- fs/sdcardfs/sdcardfs.h | 9 ++-- 7 files changed, 82 insertions(+), 143 deletions(-) diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 8e19779c9d5e..d8ac61d0c932 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -128,7 +128,6 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) return fs; } -EXPORT_SYMBOL_GPL(copy_fs_struct); int unshare_fs_struct(void) { struct fs_struct *fs = current->fs; diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index b4cc97c47bce..903e89068170 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -30,12 +30,11 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->userid = pi->userid; ci->d_uid = pi->d_uid; ci->under_android = pi->under_android; - ci->top = pi->top; } /* helper function for derived state */ -void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, - uid_t uid, bool under_android, struct inode *top) +void setup_derived_state(struct inode *inode, perm_t perm, + userid_t userid, uid_t uid, bool under_android) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); @@ -43,7 +42,6 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, info->userid = userid; info->d_uid = uid; info->under_android = under_android; - info->top = top; } /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ @@ -73,7 +71,6 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10); - info->top = &info->vfs_inode; break; case PERM_ROOT: /* Assume masked off by default. */ @@ -81,23 +78,19 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->under_android = true; - info->top = &info->vfs_inode; } break; case PERM_ANDROID: if (!strcasecmp(newdentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; - info->top = &info->vfs_inode; } else if (!strcasecmp(newdentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; - info->top = &info->vfs_inode; /* Single OBB directory is always shared */ } else if (!strcasecmp(newdentry->d_name.name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; - info->top = &info->vfs_inode; } break; case PERM_ANDROID_DATA: @@ -107,7 +100,6 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } - info->top = &info->vfs_inode; break; } } @@ -117,63 +109,17 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) get_derived_permission_new(parent, dentry, dentry); } -static int descendant_may_need_fixup(perm_t perm) { - if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID) - return 1; - return 0; -} - -static int needs_fixup(perm_t perm) { - if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB - || perm == PERM_ANDROID_MEDIA) - return 1; - return 0; -} - -void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) { - struct dentry *child; - struct sdcardfs_inode_info *info; - if (!dentry || !dentry->d_inode) - return; - info = SDCARDFS_I(dentry->d_inode); - - if (needs_fixup(info->perm)) { - mutex_lock(&dentry->d_inode->i_mutex); - child = lookup_one_len(name, dentry, len); - mutex_unlock(&dentry->d_inode->i_mutex); - if (!IS_ERR(child)) { - if (child->d_inode) { - get_derived_permission(dentry, child); - fix_derived_permission(child->d_inode); - } - dput(child); - } - } else if (descendant_may_need_fixup(info->perm)) { - mutex_lock(&dentry->d_inode->i_mutex); - list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - fixup_perms_recursive(child, name, len); - } - mutex_unlock(&dentry->d_inode->i_mutex); - } -} - -void fixup_top_recursive(struct dentry *parent) { +void get_derive_permissions_recursive(struct dentry *parent) { struct dentry *dentry; - struct sdcardfs_inode_info *info; - if (!parent->d_inode) - return; - info = SDCARDFS_I(parent->d_inode); - spin_lock(&parent->d_lock); list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { if (dentry->d_inode) { - if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { - get_derived_permission(parent, dentry); - fix_derived_permission(dentry->d_inode); - fixup_top_recursive(dentry); - } + mutex_lock(&dentry->d_inode->i_mutex); + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + get_derive_permissions_recursive(dentry); + mutex_unlock(&dentry->d_inode->i_mutex); } } - spin_unlock(&parent->d_lock); } /* main function for updating derived permission */ @@ -189,6 +135,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ + mutex_lock(&dentry->d_inode->i_mutex); if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { @@ -199,6 +146,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) } } fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } int need_graft_path(struct dentry *dentry) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 597dcf912e9a..0f4aa17645d6 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -19,7 +19,6 @@ */ #include "sdcardfs.h" -#include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) @@ -57,8 +56,6 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; - struct fs_struct *saved_fs; - struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -77,12 +74,6 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, /* set last 16bytes of mode field to 0664 */ mode = (mode & S_IFMT) | 00664; - - /* temporarily change umask for lower fs write */ - saved_fs = current->fs; - copied_fs = copy_fs_struct(current->fs); - current->fs = copied_fs; - current->fs->umask = 0; err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -94,8 +85,6 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: - current->fs = saved_fs; - free_fs_struct(copied_fs); unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -256,9 +245,11 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); + char *page_buf; + char *nomedia_dir_name; + char *nomedia_fullpath; + int fullpath_namelen; int touch_err = 0; - struct fs_struct *saved_fs; - struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -285,12 +276,6 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; - - /* temporarily change umask for lower fs write */ - saved_fs = current->fs; - copied_fs = copy_fs_struct(current->fs); - current->fs = copied_fs; - current->fs->umask = 0; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) @@ -331,17 +316,42 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { - set_fs_pwd(current->fs, &lower_path); - touch_err = touch(".nomedia", 0664); + + page_buf = (char *)__get_free_page(GFP_KERNEL); + if (!page_buf) { + printk(KERN_ERR "sdcardfs: failed to allocate page buf\n"); + goto out; + } + + nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE); + if (IS_ERR(nomedia_dir_name)) { + free_page((unsigned long)page_buf); + printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n"); + goto out; + } + + fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; + fullpath_namelen += strlen("/.nomedia"); + nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); + if (!nomedia_fullpath) { + free_page((unsigned long)page_buf); + printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n"); + goto out; + } + + strcpy(nomedia_fullpath, nomedia_dir_name); + free_page((unsigned long)page_buf); + strcat(nomedia_fullpath, "/.nomedia"); + touch_err = touch(nomedia_fullpath, 0664); if (touch_err) { - printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n", - lower_path.dentry->d_name.name, touch_err); + printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n", + nomedia_fullpath, touch_err); + kfree(nomedia_fullpath); goto out; } + kfree(nomedia_fullpath); } out: - current->fs = saved_fs; - free_fs_struct(copied_fs); unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: @@ -502,9 +512,11 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* At this point, not all dentry information has been moved, so * we pass along new_dentry for the name.*/ + mutex_lock(&old_dentry->d_inode->i_mutex); get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); fix_derived_permission(old_dentry->d_inode); - fixup_top_recursive(old_dentry); + get_derive_permissions_recursive(old_dentry); + mutex_unlock(&old_dentry->d_inode->i_mutex); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -589,13 +601,6 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, static int sdcardfs_permission(struct inode *inode, int mask) { int err; - struct inode *top = SDCARDFS_I(inode)->top; - - /* Ensure owner is up to date */ - if (inode->i_uid != top->i_uid) { - SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid; - fix_derived_permission(inode); - } /* * Permission check on sdcardfs inode. @@ -631,24 +636,6 @@ static int sdcardfs_permission(struct inode *inode, int mask) } -static void sdcardfs_fillattr(struct inode *inode, struct kstat *stat) -{ - struct sdcardfs_inode_info *info = SDCARDFS_I(inode); - stat->dev = inode->i_sb->s_dev; - stat->ino = inode->i_ino; - stat->mode = (inode->i_mode & S_IFMT) | get_mode(SDCARDFS_I(info->top)); - stat->nlink = inode->i_nlink; - stat->uid = SDCARDFS_I(info->top)->d_uid; - stat->gid = get_gid(SDCARDFS_I(info->top)); - stat->rdev = inode->i_rdev; - stat->size = i_size_read(inode); - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; - stat->ctime = inode->i_ctime; - stat->blksize = (1 << inode->i_blkbits); - stat->blocks = inode->i_blocks; -} - static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { @@ -678,7 +665,8 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - sdcardfs_fillattr(inode, stat); + + generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return 0; } @@ -800,7 +788,9 @@ const struct inode_operations sdcardfs_symlink_iops = { const struct inode_operations sdcardfs_dir_iops = { .create = sdcardfs_create, .lookup = sdcardfs_lookup, +#if 0 .permission = sdcardfs_permission, +#endif .unlink = sdcardfs_unlink, .mkdir = sdcardfs_mkdir, .rmdir = sdcardfs_rmdir, diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 4c3b2e831e6a..a8d6792b7656 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -236,6 +236,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; + /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); @@ -386,9 +387,11 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, if (dentry->d_inode) { fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); - /* get derived permission */ + /* get drived permission */ + mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); + mutex_unlock(&dentry->d_inode->i_mutex); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 3666aef3e0f0..8326e9838069 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -268,13 +268,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); if(sb_info->options.multiuser) { - setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755);*/ } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index d1961cf5677a..0cf9c345d05e 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -44,7 +44,7 @@ struct sb_list { struct packagelist_data { DECLARE_HASHTABLE(package_to_appid,8); - spinlock_t hashtable_lock; + struct mutex hashtable_lock; }; @@ -71,15 +71,15 @@ appid_t get_appid(void *pkgl_id, const char *app_name) unsigned int hash = str_hash(app_name); appid_t ret_id; - spin_lock(&pkgl_dat->hashtable_lock); + mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(app_name, hash_cur->key)) { ret_id = (appid_t)hash_cur->value; - spin_unlock(&pkgl_dat->hashtable_lock); + mutex_unlock(&pkgl_dat->hashtable_lock); return ret_id; } } - spin_unlock(&pkgl_dat->hashtable_lock); + mutex_unlock(&pkgl_dat->hashtable_lock); return 0; } @@ -133,18 +133,20 @@ static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, return 0; } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_ATOMIC); + new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); if (!new_entry) return -ENOMEM; - new_entry->key = kstrdup(key, GFP_ATOMIC); + new_entry->key = kstrdup(key, GFP_KERNEL); new_entry->value = value; hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); return 0; } -static void fixup_perms(struct super_block *sb, const char *key) { +static void fixup_perms(struct super_block *sb) { if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - fixup_perms_recursive(sb->s_root, key, strlen(key)); + mutex_lock(&sb->s_root->d_inode->i_mutex); + get_derive_permissions_recursive(sb->s_root); + mutex_unlock(&sb->s_root->d_inode->i_mutex); } } @@ -153,13 +155,13 @@ static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, int ret; struct sdcardfs_sb_info *sbinfo; mutex_lock(&sdcardfs_super_list_lock); - spin_lock(&pkgl_dat->hashtable_lock); + mutex_lock(&pkgl_dat->hashtable_lock); ret = insert_str_to_int_lock(pkgl_dat, key, value); - spin_unlock(&pkgl_dat->hashtable_lock); + mutex_unlock(&pkgl_dat->hashtable_lock); list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { - fixup_perms(sbinfo->sb, key); + fixup_perms(sbinfo->sb); } } mutex_unlock(&sdcardfs_super_list_lock); @@ -178,17 +180,17 @@ static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key struct hashtable_entry *hash_cur; unsigned int hash = str_hash(key); mutex_lock(&sdcardfs_super_list_lock); - spin_lock(&pkgl_data_all->hashtable_lock); + mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { remove_str_to_int_lock(hash_cur); break; } } - spin_unlock(&pkgl_data_all->hashtable_lock); + mutex_unlock(&pkgl_dat->hashtable_lock); list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo) { - fixup_perms(sbinfo->sb, key); + fixup_perms(sbinfo->sb); } } mutex_unlock(&sdcardfs_super_list_lock); @@ -200,10 +202,10 @@ static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) struct hashtable_entry *hash_cur; struct hlist_node *h_t; int i; - spin_lock(&pkgl_data_all->hashtable_lock); + mutex_lock(&pkgl_dat->hashtable_lock); hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) remove_str_to_int_lock(hash_cur); - spin_unlock(&pkgl_data_all->hashtable_lock); + mutex_unlock(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); } @@ -217,7 +219,7 @@ static struct packagelist_data * packagelist_create(void) return ERR_PTR(-ENOMEM); } - spin_lock_init(&pkgl_dat->hashtable_lock); + mutex_init(&pkgl_dat->hashtable_lock); hash_init(pkgl_dat->package_to_appid); return pkgl_dat; @@ -350,7 +352,7 @@ static ssize_t packages_attr_show(struct config_item *item, int count = 0, written = 0; char errormsg[] = "\n"; - spin_lock(&pkgl_data_all->hashtable_lock); + mutex_lock(&pkgl_data_all->hashtable_lock); hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) { written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); if (count + written == PAGE_SIZE - sizeof(errormsg)) { @@ -359,7 +361,7 @@ static ssize_t packages_attr_show(struct config_item *item, } count += written; } - spin_unlock(&pkgl_data_all->hashtable_lock); + mutex_unlock(&pkgl_data_all->hashtable_lock); return count; } diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 113d722b803b..7f3dee3b1f1d 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -169,8 +169,6 @@ struct sdcardfs_inode_info { userid_t userid; uid_t d_uid; bool under_android; - /* top folder for ownership */ - struct inode *top; struct inode vfs_inode; }; @@ -405,12 +403,11 @@ extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ -extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, - uid_t uid, bool under_android, struct inode *top); +extern void setup_derived_state(struct inode *inode, perm_t perm, + userid_t userid, uid_t uid, bool under_android); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); -extern void fixup_top_recursive(struct dentry *parent); -extern void fixup_perms_recursive(struct dentry *dentry, const char *name, size_t len); +extern void get_derive_permissions_recursive(struct dentry *parent); extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); From 4cb94d082ddc61deaaf7d0610145d8b4c1c38117 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 13 Apr 2016 16:38:34 -0700 Subject: [PATCH 025/281] sdcardfs: override umask on mkdir and create The mode on files created on the lower fs should not be affected by the umask of the calling task's fs_struct. Instead, we create a copy and modify it as needed. This also lets us avoid the string shenanigans around .nomedia files. Bug: 27992761 Change-Id: Ia3a6e56c24c6e19b3b01c1827e46403bb71c2f4c Signed-off-by: Daniel Rosenberg --- fs/fs_struct.c | 1 + fs/sdcardfs/inode.c | 70 ++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/fs/fs_struct.c b/fs/fs_struct.c index d8ac61d0c932..5a1bb8242a56 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -127,6 +127,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) } return fs; } +EXPORT_SYMBOL_GPL(copy_fs_struct); int unshare_fs_struct(void) { diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 0f4aa17645d6..0b2abbfbf1e0 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -19,6 +19,7 @@ */ #include "sdcardfs.h" +#include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) @@ -56,6 +57,8 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -74,6 +77,16 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, /* set last 16bytes of mode field to 0664 */ mode = (mode & S_IFMT) | 00664; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + if (!copied_fs) { + err = -ENOMEM; + goto out_unlock; + } + current->fs = copied_fs; + current->fs->umask = 0; err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -85,6 +98,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: + current->fs = saved_fs; + free_fs_struct(copied_fs); +out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -245,11 +261,9 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); - char *page_buf; - char *nomedia_dir_name; - char *nomedia_fullpath; - int fullpath_namelen; int touch_err = 0; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" @@ -276,6 +290,16 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + if (!copied_fs) { + err = -ENOMEM; + goto out_unlock; + } + current->fs = copied_fs; + current->fs->umask = 0; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) @@ -316,42 +340,18 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { - - page_buf = (char *)__get_free_page(GFP_KERNEL); - if (!page_buf) { - printk(KERN_ERR "sdcardfs: failed to allocate page buf\n"); - goto out; - } - - nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE); - if (IS_ERR(nomedia_dir_name)) { - free_page((unsigned long)page_buf); - printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n"); - goto out; - } - - fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; - fullpath_namelen += strlen("/.nomedia"); - nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); - if (!nomedia_fullpath) { - free_page((unsigned long)page_buf); - printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n"); - goto out; - } - - strcpy(nomedia_fullpath, nomedia_dir_name); - free_page((unsigned long)page_buf); - strcat(nomedia_fullpath, "/.nomedia"); - touch_err = touch(nomedia_fullpath, 0664); + set_fs_pwd(current->fs, &lower_path); + touch_err = touch(".nomedia", 0664); if (touch_err) { - printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n", - nomedia_fullpath, touch_err); - kfree(nomedia_fullpath); + printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n", + lower_path.dentry->d_name.name, touch_err); goto out; } - kfree(nomedia_fullpath); } out: + current->fs = saved_fs; + free_fs_struct(copied_fs); +out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: From 277bab3f3997f89ca8fbc3b98a9ecab8e640599a Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 16 Aug 2016 15:19:26 -0700 Subject: [PATCH 026/281] sdcardfs: Fix locking for permission fix up Iterating over d_subdirs requires taking d_lock. Removed several unneeded locks. Change-Id: I5b1588e54c7e6ee19b756d6705171c7f829e2650 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 6 ++---- fs/sdcardfs/inode.c | 2 -- fs/sdcardfs/lookup.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 903e89068170..b0278964e535 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -111,15 +111,15 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) void get_derive_permissions_recursive(struct dentry *parent) { struct dentry *dentry; + spin_lock(&parent->d_lock); list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { if (dentry->d_inode) { - mutex_lock(&dentry->d_inode->i_mutex); get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); get_derive_permissions_recursive(dentry); - mutex_unlock(&dentry->d_inode->i_mutex); } } + spin_unlock(&parent->d_lock); } /* main function for updating derived permission */ @@ -135,7 +135,6 @@ inline void update_derived_permission_lock(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ - mutex_lock(&dentry->d_inode->i_mutex); if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { @@ -146,7 +145,6 @@ inline void update_derived_permission_lock(struct dentry *dentry) } } fix_derived_permission(dentry->d_inode); - mutex_unlock(&dentry->d_inode->i_mutex); } int need_graft_path(struct dentry *dentry) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 0b2abbfbf1e0..a61e8c821796 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -512,11 +512,9 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* At this point, not all dentry information has been moved, so * we pass along new_dentry for the name.*/ - mutex_lock(&old_dentry->d_inode->i_mutex); get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); fix_derived_permission(old_dentry->d_inode); get_derive_permissions_recursive(old_dentry); - mutex_unlock(&old_dentry->d_inode->i_mutex); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a8d6792b7656..7ffecfecc6c2 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -387,11 +387,9 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, if (dentry->d_inode) { fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); - /* get drived permission */ - mutex_lock(&dentry->d_inode->i_mutex); + /* get derived permission */ get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); - mutex_unlock(&dentry->d_inode->i_mutex); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, From 50c9de62de5972b5987d559a8356b22c700c02c7 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 10 May 2016 13:42:43 -0700 Subject: [PATCH 027/281] sdcardfs: Switch package list to RCU Switched the package id hashmap to use RCU. Change-Id: I9fdcab279009005bf28536247d11e13babab0b93 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 3 +- fs/sdcardfs/packagelist.c | 200 +++++++++++++++++-------------------- fs/sdcardfs/sdcardfs.h | 2 +- 3 files changed, 93 insertions(+), 112 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index b0278964e535..68837e724af4 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -47,7 +47,6 @@ void setup_derived_state(struct inode *inode, perm_t perm, /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry) { - struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); appid_t appid; @@ -96,7 +95,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: case PERM_ANDROID_MEDIA: - appid = get_appid(sbi->pkgl_id, newdentry->d_name.name); + appid = get_appid(newdentry->d_name.name); if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 0cf9c345d05e..608a4b50ccd8 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -29,26 +29,13 @@ #include -#define STRING_BUF_SIZE (512) - struct hashtable_entry { struct hlist_node hlist; - void *key; - unsigned int value; -}; - -struct sb_list { - struct super_block *sb; - struct list_head list; + const char *key; + atomic_t value; }; -struct packagelist_data { - DECLARE_HASHTABLE(package_to_appid,8); - struct mutex hashtable_lock; - -}; - -static struct packagelist_data *pkgl_data_all; +static DEFINE_HASHTABLE(package_to_appid, 8); static struct kmem_cache *hashtable_entry_cachep; @@ -64,22 +51,21 @@ static unsigned int str_hash(const char *key) { return h; } -appid_t get_appid(void *pkgl_id, const char *app_name) +appid_t get_appid(const char *app_name) { - struct packagelist_data *pkgl_dat = pkgl_data_all; struct hashtable_entry *hash_cur; unsigned int hash = str_hash(app_name); appid_t ret_id; - mutex_lock(&pkgl_dat->hashtable_lock); - hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(app_name, hash_cur->key)) { - ret_id = (appid_t)hash_cur->value; - mutex_unlock(&pkgl_dat->hashtable_lock); + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); return ret_id; } } - mutex_unlock(&pkgl_dat->hashtable_lock); + rcu_read_unlock(); return 0; } @@ -120,116 +106,118 @@ int open_flags_to_access_mode(int open_flags) { } } -static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, - unsigned int value) +static struct hashtable_entry *alloc_packagelist_entry(const char *key, + appid_t value) +{ + struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, + GFP_KERNEL); + if (!ret) + return NULL; + + ret->key = kstrdup(key, GFP_KERNEL); + if (!ret->key) { + kmem_cache_free(hashtable_entry_cachep, ret); + return NULL; + } + + atomic_set(&ret->value, value); + return ret; +} + +static int insert_packagelist_entry_locked(const char *key, appid_t value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; unsigned int hash = str_hash(key); - hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { - hash_cur->value = value; + atomic_set(&hash_cur->value, value); return 0; } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL); + new_entry = alloc_packagelist_entry(key, value); if (!new_entry) return -ENOMEM; - new_entry->key = kstrdup(key, GFP_KERNEL); - new_entry->value = value; - hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash); + hash_add_rcu(package_to_appid, &new_entry->hlist, hash); return 0; } static void fixup_perms(struct super_block *sb) { if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - mutex_lock(&sb->s_root->d_inode->i_mutex); get_derive_permissions_recursive(sb->s_root); - mutex_unlock(&sb->s_root->d_inode->i_mutex); } } -static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key, - unsigned int value) { - int ret; +static void fixup_all_perms(void) +{ struct sdcardfs_sb_info *sbinfo; - mutex_lock(&sdcardfs_super_list_lock); - mutex_lock(&pkgl_dat->hashtable_lock); - ret = insert_str_to_int_lock(pkgl_dat, key, value); - mutex_unlock(&pkgl_dat->hashtable_lock); - - list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { - if (sbinfo) { + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) + if (sbinfo) fixup_perms(sbinfo->sb); - } - } +} + +static int insert_packagelist_entry(const char *key, appid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_packagelist_entry_locked(key, value); + if (!err) + fixup_all_perms(); mutex_unlock(&sdcardfs_super_list_lock); - return ret; + + return err; } -static void remove_str_to_int_lock(struct hashtable_entry *h_entry) { - kfree(h_entry->key); - hash_del(&h_entry->hlist); - kmem_cache_free(hashtable_entry_cachep, h_entry); +static void free_packagelist_entry(struct hashtable_entry *entry) +{ + kfree(entry->key); + hash_del_rcu(&entry->hlist); + kmem_cache_free(hashtable_entry_cachep, entry); } -static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key) +static void remove_packagelist_entry_locked(const char *key) { - struct sdcardfs_sb_info *sbinfo; struct hashtable_entry *hash_cur; unsigned int hash = str_hash(key); - mutex_lock(&sdcardfs_super_list_lock); - mutex_lock(&pkgl_dat->hashtable_lock); - hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { + + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { - remove_str_to_int_lock(hash_cur); - break; - } - } - mutex_unlock(&pkgl_dat->hashtable_lock); - list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { - if (sbinfo) { - fixup_perms(sbinfo->sb); + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_packagelist_entry(hash_cur); + return; } } +} + +static void remove_packagelist_entry(const char *key) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_packagelist_entry_locked(key); + fixup_all_perms(); mutex_unlock(&sdcardfs_super_list_lock); return; } -static void remove_all_hashentrys(struct packagelist_data *pkgl_dat) +static void packagelist_destroy(void) { struct hashtable_entry *hash_cur; struct hlist_node *h_t; + HLIST_HEAD(free_list); int i; - mutex_lock(&pkgl_dat->hashtable_lock); - hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist) - remove_str_to_int_lock(hash_cur); - mutex_unlock(&pkgl_dat->hashtable_lock); - hash_init(pkgl_dat->package_to_appid); -} - -static struct packagelist_data * packagelist_create(void) -{ - struct packagelist_data *pkgl_dat; + mutex_lock(&sdcardfs_super_list_lock); + hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->hlist, &free_list); - pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO); - if (!pkgl_dat) { - printk(KERN_ERR "sdcardfs: Failed to create hash\n"); - return ERR_PTR(-ENOMEM); } - - mutex_init(&pkgl_dat->hashtable_lock); - hash_init(pkgl_dat->package_to_appid); - - return pkgl_dat; -} - -static void packagelist_destroy(struct packagelist_data *pkgl_dat) -{ - remove_all_hashentrys(pkgl_dat); + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, hlist) + free_packagelist_entry(hash_cur); + mutex_unlock(&sdcardfs_super_list_lock); printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); - kfree(pkgl_dat); } struct package_appid { @@ -257,9 +245,7 @@ static ssize_t package_appid_attr_show(struct config_item *item, struct configfs_attribute *attr, char *page) { - ssize_t count; - count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name)); - return count; + return scnprintf(page, PAGE_SIZE, "%u\n", get_appid(item->ci_name)); } static ssize_t package_appid_attr_store(struct config_item *item, @@ -267,17 +253,14 @@ static ssize_t package_appid_attr_store(struct config_item *item, const char *page, size_t count) { struct package_appid *package_appid = to_package_appid(item); - unsigned long tmp; - char *p = (char *) page; + unsigned int tmp; int ret; - tmp = simple_strtoul(p, &p, 10); - if (!p || (*p && (*p != '\n'))) - return -EINVAL; + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; - if (tmp > INT_MAX) - return -ERANGE; - ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp); + ret = insert_packagelist_entry(item->ci_name, tmp); package_appid->add_pid = tmp; if (ret) return ret; @@ -289,7 +272,7 @@ static void package_appid_release(struct config_item *item) { printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name); /* item->ci_name is freed already, so we rely on the dentry */ - remove_str_to_int(pkgl_data_all, item->ci_dentry->d_name.name); + remove_packagelist_entry(item->ci_dentry->d_name.name); kfree(to_package_appid(item)); } @@ -347,21 +330,21 @@ static ssize_t packages_attr_show(struct config_item *item, char *page) { struct hashtable_entry *hash_cur; - struct hlist_node *h_t; int i; int count = 0, written = 0; - char errormsg[] = "\n"; + const char errormsg[] = "\n"; - mutex_lock(&pkgl_data_all->hashtable_lock); - hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist) { - written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value); + rcu_read_lock(); + hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { + written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", + (const char *)hash_cur->key, atomic_read(&hash_cur->value)); if (count + written == PAGE_SIZE - sizeof(errormsg)) { count += scnprintf(page + count, PAGE_SIZE - count, errormsg); break; } count += written; } - mutex_unlock(&pkgl_data_all->hashtable_lock); + rcu_read_unlock(); return count; } @@ -433,7 +416,6 @@ int packagelist_init(void) return -ENOMEM; } - pkgl_data_all = packagelist_create(); configfs_sdcardfs_init(); return 0; } @@ -441,7 +423,7 @@ int packagelist_init(void) void packagelist_exit(void) { configfs_sdcardfs_exit(); - packagelist_destroy(pkgl_data_all); + packagelist_destroy(); if (hashtable_entry_cachep) kmem_cache_destroy(hashtable_entry_cachep); } diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 7f3dee3b1f1d..48de31b5a53c 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -396,7 +396,7 @@ extern struct mutex sdcardfs_super_list_lock; extern struct list_head sdcardfs_super_list; /* for packagelist.c */ -extern appid_t get_appid(void *pkgl_id, const char *app_name); +extern appid_t get_appid(const char *app_name); extern int check_caller_access_to_name(struct inode *parent_node, const char* name); extern int open_flags_to_access_mode(int open_flags); extern int packagelist_init(void); From ee7bbd8f7953f65fcd76cc1eaccff6c4b123e6da Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 18 May 2016 16:57:10 -0700 Subject: [PATCH 028/281] sdcardfs: Added top to sdcardfs_inode_info Adding packages to the package list and moving files takes a large amount of locks, and is currently a heavy operation. This adds a 'top' field to the inode_info, which points to the inode for the top most directory whose owner you would like to match. On permission checks and get_attr, we look up the owner based on the information at top. When we change a package mapping, we need only modify the information in the corresponding top inode_info's. When renaming, we must ensure top is set correctly in all children. This happens when an app specific folder gets moved outside of the folder for that app. Change-Id: Ib749c60b568e9a45a46f8ceed985c1338246ec6c Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 71 +++++++++++++++++++++--- fs/sdcardfs/inode.c | 107 ++++++++++++++++++++++++------------- fs/sdcardfs/main.c | 4 +- fs/sdcardfs/packagelist.c | 12 ++--- fs/sdcardfs/sdcardfs.h | 40 ++++++++++++-- fs/sdcardfs/super.c | 1 + 6 files changed, 179 insertions(+), 56 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 68837e724af4..6be6747f6175 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -30,11 +30,12 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->userid = pi->userid; ci->d_uid = pi->d_uid; ci->under_android = pi->under_android; + set_top(ci, pi->top); } /* helper function for derived state */ -void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, bool under_android) +void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); @@ -42,6 +43,7 @@ void setup_derived_state(struct inode *inode, perm_t perm, info->userid = userid; info->d_uid = uid; info->under_android = under_android; + set_top(info, top); } /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ @@ -70,6 +72,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10); + set_top(info, &info->vfs_inode); break; case PERM_ROOT: /* Assume masked off by default. */ @@ -77,19 +80,23 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->under_android = true; + set_top(info, &info->vfs_inode); } break; case PERM_ANDROID: if (!strcasecmp(newdentry->d_name.name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; + set_top(info, &info->vfs_inode); } else if (!strcasecmp(newdentry->d_name.name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; + set_top(info, &info->vfs_inode); /* Single OBB directory is always shared */ } else if (!strcasecmp(newdentry->d_name.name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; + set_top(info, &info->vfs_inode); } break; case PERM_ANDROID_DATA: @@ -99,6 +106,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st if (appid != 0) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } + set_top(info, &info->vfs_inode); break; } } @@ -108,14 +116,65 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) get_derived_permission_new(parent, dentry, dentry); } -void get_derive_permissions_recursive(struct dentry *parent) { +static int descendant_may_need_fixup(perm_t perm) { + if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID) + return 1; + return 0; +} + +static int needs_fixup(perm_t perm) { + if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB + || perm == PERM_ANDROID_MEDIA) + return 1; + return 0; +} + +void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) { + struct dentry *child; + struct sdcardfs_inode_info *info; + if (!dget(dentry)) + return; + if (!dentry->d_inode) { + dput(dentry); + return; + } + info = SDCARDFS_I(dentry->d_inode); + + if (needs_fixup(info->perm)) { + mutex_lock(&dentry->d_inode->i_mutex); + child = lookup_one_len(name, dentry, len); + mutex_unlock(&dentry->d_inode->i_mutex); + if (!IS_ERR(child)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fix_derived_permission(child->d_inode); + } + dput(child); + } + } else if (descendant_may_need_fixup(info->perm)) { + mutex_lock(&dentry->d_inode->i_mutex); + list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { + fixup_perms_recursive(child, name, len); + } + mutex_unlock(&dentry->d_inode->i_mutex); + } + dput(dentry); +} + +void fixup_top_recursive(struct dentry *parent) { struct dentry *dentry; + struct sdcardfs_inode_info *info; + if (!parent->d_inode) + return; + info = SDCARDFS_I(parent->d_inode); spin_lock(&parent->d_lock); list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { if (dentry->d_inode) { - get_derived_permission(parent, dentry); - fix_derived_permission(dentry->d_inode); - get_derive_permissions_recursive(dentry); + if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { + get_derived_permission(parent, dentry); + fix_derived_permission(dentry->d_inode); + fixup_top_recursive(dentry); + } } } spin_unlock(&parent->d_lock); diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index a61e8c821796..9842a92856a3 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -514,7 +514,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, * we pass along new_dentry for the name.*/ get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); fix_derived_permission(old_dentry->d_inode); - get_derive_permissions_recursive(old_dentry); + fixup_top_recursive(old_dentry); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -599,6 +599,16 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, static int sdcardfs_permission(struct inode *inode, int mask) { int err; + struct inode *top = grab_top(SDCARDFS_I(inode)); + + if (!top) + return -EINVAL; + /* Ensure owner is up to date */ + if (!uid_eq(inode->i_uid, top->i_uid)) { + SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid; + fix_derived_permission(inode); + } + release_top(SDCARDFS_I(inode)); /* * Permission check on sdcardfs inode. @@ -634,41 +644,6 @@ static int sdcardfs_permission(struct inode *inode, int mask) } -static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct dentry *lower_dentry; - struct inode *inode; - struct inode *lower_inode; - struct path lower_path; - struct dentry *parent; - - parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); - dput(parent); - return -EACCES; - } - dput(parent); - - inode = dentry->d_inode; - - sdcardfs_get_lower_path(dentry, &lower_path); - lower_dentry = lower_path.dentry; - lower_inode = sdcardfs_lower_inode(inode); - - - sdcardfs_copy_and_fix_attrs(inode, lower_inode); - fsstack_copy_inode_size(inode, lower_inode); - - - generic_fillattr(inode, stat); - sdcardfs_put_lower_path(dentry, &lower_path); - return 0; -} - static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; @@ -771,6 +746,64 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) return err; } +static int sdcardfs_fillattr(struct inode *inode, struct kstat *stat) +{ + struct sdcardfs_inode_info *info = SDCARDFS_I(inode); + struct inode *top = grab_top(info); + if (!top) + return -EINVAL; + + stat->dev = inode->i_sb->s_dev; + stat->ino = inode->i_ino; + stat->mode = (inode->i_mode & S_IFMT) | get_mode(SDCARDFS_I(top)); + stat->nlink = inode->i_nlink; + stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + stat->gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(top))); + stat->rdev = inode->i_rdev; + stat->size = i_size_read(inode); + stat->atime = inode->i_atime; + stat->mtime = inode->i_mtime; + stat->ctime = inode->i_ctime; + stat->blksize = (1 << inode->i_blkbits); + stat->blocks = inode->i_blocks; + release_top(info); + return 0; +} + +static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct dentry *parent; + int err; + + parent = dget_parent(dentry); + if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + dput(parent); + return -EACCES; + } + dput(parent); + + inode = dentry->d_inode; + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = sdcardfs_lower_inode(inode); + + sdcardfs_copy_and_fix_attrs(inode, lower_inode); + fsstack_copy_inode_size(inode, lower_inode); + + err = sdcardfs_fillattr(inode, stat); + sdcardfs_put_lower_path(dentry, &lower_path); + return err; +} + const struct inode_operations sdcardfs_symlink_iops = { .permission = sdcardfs_permission, .setattr = sdcardfs_setattr, @@ -786,9 +819,7 @@ const struct inode_operations sdcardfs_symlink_iops = { const struct inode_operations sdcardfs_dir_iops = { .create = sdcardfs_create, .lookup = sdcardfs_lookup, -#if 0 .permission = sdcardfs_permission, -#endif .unlink = sdcardfs_unlink, .mkdir = sdcardfs_mkdir, .rmdir = sdcardfs_rmdir, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 8326e9838069..3666aef3e0f0 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -268,13 +268,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); if(sb_info->options.multiuser) { - setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755);*/ } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false); + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 608a4b50ccd8..dac5d0f7d2de 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -143,18 +143,18 @@ static int insert_packagelist_entry_locked(const char *key, appid_t value) return 0; } -static void fixup_perms(struct super_block *sb) { +static void fixup_perms(struct super_block *sb, const char *key) { if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - get_derive_permissions_recursive(sb->s_root); + fixup_perms_recursive(sb->s_root, key, strlen(key)); } } -static void fixup_all_perms(void) +static void fixup_all_perms(const char *key) { struct sdcardfs_sb_info *sbinfo; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) if (sbinfo) - fixup_perms(sbinfo->sb); + fixup_perms(sbinfo->sb, key); } static int insert_packagelist_entry(const char *key, appid_t value) @@ -164,7 +164,7 @@ static int insert_packagelist_entry(const char *key, appid_t value) mutex_lock(&sdcardfs_super_list_lock); err = insert_packagelist_entry_locked(key, value); if (!err) - fixup_all_perms(); + fixup_all_perms(key); mutex_unlock(&sdcardfs_super_list_lock); return err; @@ -196,7 +196,7 @@ static void remove_packagelist_entry(const char *key) { mutex_lock(&sdcardfs_super_list_lock); remove_packagelist_entry_locked(key); - fixup_all_perms(); + fixup_all_perms(key); mutex_unlock(&sdcardfs_super_list_lock); return; } diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 48de31b5a53c..00b8f7435e62 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -169,6 +169,8 @@ struct sdcardfs_inode_info { userid_t userid; uid_t d_uid; bool under_android; + /* top folder for ownership */ + struct inode *top; struct inode vfs_inode; }; @@ -321,6 +323,35 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ SDCARDFS_DENT_FUNC(lower_path) SDCARDFS_DENT_FUNC(orig_path) +/* grab a refererence if we aren't linking to ourself */ +static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top) +{ + struct inode *old_top = NULL; + BUG_ON(IS_ERR_OR_NULL(top)); + if (info->top && info->top != &info->vfs_inode) { + old_top = info->top; + } + if (top != &info->vfs_inode) + igrab(top); + info->top = top; + iput(old_top); +} + +static inline struct inode *grab_top(struct sdcardfs_inode_info *info) +{ + struct inode *top = info->top; + if (top) { + return igrab(top); + } else { + return NULL; + } +} + +static inline void release_top(struct sdcardfs_inode_info *info) +{ + iput(info->top); +} + static inline int get_gid(struct sdcardfs_inode_info *info) { struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); if (sb_info->options.gid == AID_SDCARD_RW) { @@ -337,7 +368,7 @@ static inline int get_gid(struct sdcardfs_inode_info *info) { static inline int get_mode(struct sdcardfs_inode_info *info) { int owner_mode; int filtered_mode; - struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); + struct sdcardfs_sb_info * sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); int visible_mode = 0775 & ~sb_info->options.mask; if (info->perm == PERM_PRE_ROOT) { @@ -403,11 +434,12 @@ extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ -extern void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, bool under_android); +extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); -extern void get_derive_permissions_recursive(struct dentry *parent); +extern void fixup_top_recursive(struct dentry *parent); +extern void fixup_perms_recursive(struct dentry *dentry, const char *name, size_t len); extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 1d6490128c99..0a465395aab7 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -126,6 +126,7 @@ static void sdcardfs_evict_inode(struct inode *inode) */ lower_inode = sdcardfs_lower_inode(inode); sdcardfs_set_lower_inode(inode, NULL); + set_top(SDCARDFS_I(inode), inode); iput(lower_inode); } From 08fe7db8c8f06d10dd0fe6e4094671256a1a6c59 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 26 Sep 2016 14:48:22 -0700 Subject: [PATCH 029/281] sdcardfs: Move directory unlock before touch This removes a deadlock under low memory conditions. filp_open can call lookup_slow, which will attempt to lock the parent. Change-Id: I940643d0793f5051d1e79a56f4da2fa8ca3d8ff7 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/inode.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 9842a92856a3..49554269f955 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -296,14 +296,17 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode copied_fs = copy_fs_struct(current->fs); if (!copied_fs) { err = -ENOMEM; + unlock_dir(lower_parent_dentry); goto out_unlock; } current->fs = copied_fs; current->fs->umask = 0; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); - if (err) + if (err) { + unlock_dir(lower_parent_dentry); goto out; + } /* if it is a local obb dentry, setup it with the base obbpath */ if(need_graft_path(dentry)) { @@ -325,14 +328,18 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid); - if (err) + if (err) { + unlock_dir(lower_parent_dentry); goto out; + } fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); + unlock_dir(lower_parent_dentry); + if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; @@ -352,7 +359,6 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode current->fs = saved_fs; free_fs_struct(copied_fs); out_unlock: - unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: REVERT_CRED(saved_cred); From eccb33b84e48be85726742a447c7cf0244f9cd7a Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 15:29:51 -0700 Subject: [PATCH 030/281] mnt: Add filesystem private data to mount points This starts to add private data associated directly to mount points. The intent is to give filesystems a sense of where they have come from, as a means of letting a filesystem take different actions based on this information. Change-Id: Ie769d7b3bb2f5972afe05c1bf16cf88c91647ab2 Signed-off-by: Daniel Rosenberg --- fs/namespace.c | 28 +++++++++++++++++++++++++++- fs/pnode.c | 14 ++++++++++++++ fs/pnode.h | 1 + include/linux/fs.h | 3 +++ include/linux/mount.h | 1 + 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index e4f1f9c071b8..be512313574d 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -541,6 +541,7 @@ int sb_prepare_remount_readonly(struct super_block *sb) static void free_vfsmnt(struct mount *mnt) { + kfree(mnt->mnt.data); kfree(mnt->mnt_devname); mnt_free_id(mnt); #ifdef CONFIG_SMP @@ -784,11 +785,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void if (!mnt) return ERR_PTR(-ENOMEM); + mnt->mnt.data = NULL; + if (type->alloc_mnt_data) { + mnt->mnt.data = type->alloc_mnt_data(); + if (!mnt->mnt.data) { + mnt_free_id(mnt); + free_vfsmnt(mnt); + return ERR_PTR(-ENOMEM); + } + } if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; root = mount_fs(type, flags, name, data); if (IS_ERR(root)) { + kfree(mnt->mnt.data); free_vfsmnt(mnt); return ERR_CAST(root); } @@ -815,6 +826,14 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, if (!mnt) return ERR_PTR(-ENOMEM); + if (sb->s_op->clone_mnt_data) { + mnt->mnt.data = sb->s_op->clone_mnt_data(old->mnt.data); + if (!mnt->mnt.data) { + err = -ENOMEM; + goto out_free; + } + } + if (flag & (CL_SLAVE | CL_PRIVATE | CL_SHARED_TO_SLAVE)) mnt->mnt_group_id = 0; /* not a peer of original */ else @@ -865,6 +884,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, return mnt; out_free: + kfree(mnt->mnt.data); free_vfsmnt(mnt); return ERR_PTR(err); } @@ -1806,8 +1826,14 @@ static int do_remount(struct path *path, int flags, int mnt_flags, err = change_mount_flags(path->mnt, flags); else if (!capable(CAP_SYS_ADMIN)) err = -EPERM; - else + else { err = do_remount_sb(sb, flags, data, 0); + namespace_lock(); + br_write_lock(&vfsmount_lock); + propagate_remount(mnt); + br_write_unlock(&vfsmount_lock); + namespace_unlock(); + } if (!err) { br_write_lock(&vfsmount_lock); mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK; diff --git a/fs/pnode.c b/fs/pnode.c index 9af0df15256e..2ef946f51a11 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -359,3 +359,17 @@ int propagate_umount(struct list_head *list) __propagate_umount(mnt); return 0; } + +int propagate_remount(struct mount *mnt) { + struct mount *m; + struct super_block *sb = mnt->mnt.mnt_sb; + int ret = 0; + + if (sb->s_op->copy_mnt_data) { + for (m = first_slave(mnt); m->mnt_slave.next != &mnt->mnt_slave_list; m = next_slave(m)) { + sb->s_op->copy_mnt_data(m->mnt.data, mnt->mnt.data); + } + } + + return ret; +} diff --git a/fs/pnode.h b/fs/pnode.h index b091445c1c4a..ae8d67a9e962 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -36,6 +36,7 @@ int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, struct list_head *); int propagate_umount(struct list_head *); int propagate_mount_busy(struct mount *, int); +int propagate_remount(struct mount *); void mnt_release_group_id(struct mount *); int get_dominating_id(struct mount *mnt, const struct path *root); unsigned int mnt_get_count(struct mount *mnt); diff --git a/include/linux/fs.h b/include/linux/fs.h index 7c546b15f6b0..d362a0bafbf6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1624,6 +1624,8 @@ struct super_operations { int (*unfreeze_fs) (struct super_block *); int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); + void *(*clone_mnt_data) (void *); + void (*copy_mnt_data) (void *, void *); void (*umount_begin) (struct super_block *); int (*show_options)(struct seq_file *, struct dentry *); @@ -1833,6 +1835,7 @@ struct file_system_type { #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); + void *(*alloc_mnt_data) (void); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; diff --git a/include/linux/mount.h b/include/linux/mount.h index 16fc05d816d4..b959c28a1023 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -55,6 +55,7 @@ struct vfsmount { struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ int mnt_flags; + void *data; }; struct file; /* forward dec */ From 11ca77f170bdf1d655ed2e7555fceb21ab8b9b48 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 15:58:22 -0700 Subject: [PATCH 031/281] vfs: Allow filesystems to access their private mount data Now we pass the vfsmount when mounting and remounting. This allows the filesystem to actually set up the mount specific data, although we can't quite do anything with it yet. show_options is expanded to include data that lives with the mount. To avoid changing existing filesystems, these have been added as new vfs functions. Change-Id: If80670bfad9f287abb8ac22457e1b034c9697097 Signed-off-by: Daniel Rosenberg --- fs/internal.h | 4 +++- fs/namespace.c | 4 ++-- fs/proc_namespace.c | 8 ++++++-- fs/super.c | 28 +++++++++++++++++++++++----- include/linux/fs.h | 4 ++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index 68121584ae37..8c894601fada 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -83,9 +83,11 @@ extern struct file *get_empty_filp(void); * super.c */ extern int do_remount_sb(struct super_block *, int, void *, int); +extern int do_remount_sb2(struct vfsmount *, struct super_block *, int, + void *, int); extern bool grab_super_passive(struct super_block *sb); extern struct dentry *mount_fs(struct file_system_type *, - int, const char *, void *); + int, const char *, struct vfsmount *, void *); extern struct super_block *user_get_super(dev_t); /* diff --git a/fs/namespace.c b/fs/namespace.c index be512313574d..af3860342847 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -797,7 +797,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; - root = mount_fs(type, flags, name, data); + root = mount_fs(type, flags, name, &mnt->mnt, data); if (IS_ERR(root)) { kfree(mnt->mnt.data); free_vfsmnt(mnt); @@ -1827,7 +1827,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags, else if (!capable(CAP_SYS_ADMIN)) err = -EPERM; else { - err = do_remount_sb(sb, flags, data, 0); + err = do_remount_sb2(path->mnt, sb, flags, data, 0); namespace_lock(); br_write_lock(&vfsmount_lock); propagate_remount(mnt); diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 5fe34c355e85..9243966026c3 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -112,7 +112,9 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) if (err) goto out; show_mnt_opts(m, mnt); - if (sb->s_op->show_options) + if (sb->s_op->show_options2) + err = sb->s_op->show_options2(mnt, m, mnt_path.dentry); + else if (sb->s_op->show_options) err = sb->s_op->show_options(m, mnt_path.dentry); seq_puts(m, " 0 0\n"); out: @@ -173,7 +175,9 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) err = show_sb_opts(m, sb); if (err) goto out; - if (sb->s_op->show_options) + if (sb->s_op->show_options2) { + err = sb->s_op->show_options2(mnt, m, mnt->mnt_root); + } else if (sb->s_op->show_options) err = sb->s_op->show_options(m, mnt->mnt_root); seq_putc(m, '\n'); out: diff --git a/fs/super.c b/fs/super.c index e911552b8b93..cff09fbca393 100644 --- a/fs/super.c +++ b/fs/super.c @@ -693,7 +693,8 @@ struct super_block *user_get_super(dev_t dev) } /** - * do_remount_sb - asks filesystem to change mount options. + * do_remount_sb2 - asks filesystem to change mount options. + * @mnt: mount we are looking at * @sb: superblock in question * @flags: numeric part of options * @data: the rest of options @@ -701,7 +702,7 @@ struct super_block *user_get_super(dev_t dev) * * Alters the mount options of a mounted file system. */ -int do_remount_sb(struct super_block *sb, int flags, void *data, int force) +int do_remount_sb2(struct vfsmount *mnt, struct super_block *sb, int flags, void *data, int force) { int retval; int remount_ro; @@ -734,7 +735,16 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) sync_filesystem(sb); - if (sb->s_op->remount_fs) { + if (mnt && sb->s_op->remount_fs2) { + retval = sb->s_op->remount_fs2(mnt, sb, &flags, data); + if (retval) { + if (!force) + goto cancel_readonly; + /* If forced remount, go ahead despite any errors */ + WARN(1, "forced remount of a %s fs returned %i\n", + sb->s_type->name, retval); + } + } else if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) { if (!force) @@ -766,6 +776,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) return retval; } +int do_remount_sb(struct super_block *sb, int flags, void *data, int force) +{ + return do_remount_sb2(NULL, sb, flags, data, force); +} + static void do_emergency_remount(struct work_struct *work) { struct super_block *sb, *p = NULL; @@ -1101,7 +1116,7 @@ struct dentry *mount_single(struct file_system_type *fs_type, EXPORT_SYMBOL(mount_single); struct dentry * -mount_fs(struct file_system_type *type, int flags, const char *name, void *data) +mount_fs(struct file_system_type *type, int flags, const char *name, struct vfsmount *mnt, void *data) { struct dentry *root; struct super_block *sb; @@ -1118,7 +1133,10 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) goto out_free_secdata; } - root = type->mount(type, flags, name, data); + if (type->mount2) + root = type->mount2(mnt, type, flags, name, data); + else + root = type->mount(type, flags, name, data); if (IS_ERR(root)) { error = PTR_ERR(root); goto out_free_secdata; diff --git a/include/linux/fs.h b/include/linux/fs.h index d362a0bafbf6..e6ebd4ced34f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1624,11 +1624,13 @@ struct super_operations { int (*unfreeze_fs) (struct super_block *); int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); + int (*remount_fs2) (struct vfsmount *, struct super_block *, int *, char *); void *(*clone_mnt_data) (void *); void (*copy_mnt_data) (void *, void *); void (*umount_begin) (struct super_block *); int (*show_options)(struct seq_file *, struct dentry *); + int (*show_options2)(struct vfsmount *,struct seq_file *, struct dentry *); int (*show_devname)(struct seq_file *, struct dentry *); int (*show_path)(struct seq_file *, struct dentry *); int (*show_stats)(struct seq_file *, struct dentry *); @@ -1835,6 +1837,8 @@ struct file_system_type { #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); + struct dentry *(*mount2) (struct vfsmount *, struct file_system_type *, int, + const char *, void *); void *(*alloc_mnt_data) (void); void (*kill_sb) (struct super_block *); struct module *owner; From 15a62f74deabe91b9755a18e2440ba19263e65a8 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 16:27:45 -0700 Subject: [PATCH 032/281] vfs: Add permission2 for filesystems with per mount permissions This allows filesystems to use their mount private data to influence the permssions they return in permission2. It has been separated into a new call to avoid disrupting current permission users. Change-Id: I9d416e3b8b6eca84ef3e336bd2af89ddd51df6ca Signed-off-by: Daniel Rosenberg --- fs/exec.c | 2 +- fs/namei.c | 193 ++++++++++++++++++++--------- fs/notify/fanotify/fanotify_user.c | 2 +- fs/notify/inotify/inotify_user.c | 2 +- fs/open.c | 16 ++- fs/utimes.c | 2 +- include/linux/fs.h | 9 ++ include/linux/namei.h | 1 + ipc/mqueue.c | 10 +- security/inode.c | 2 +- 10 files changed, 166 insertions(+), 73 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 958e7a31671e..2b100a63b74a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1111,7 +1111,7 @@ EXPORT_SYMBOL(flush_old_exec); void would_dump(struct linux_binprm *bprm, struct file *file) { - if (inode_permission(file_inode(file), MAY_READ) < 0) + if (inode_permission2(file->f_path.mnt, file_inode(file), MAY_READ) < 0) bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; } EXPORT_SYMBOL(would_dump); diff --git a/fs/namei.c b/fs/namei.c index 022771a0e3b7..17a1103790d4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -355,9 +355,11 @@ int generic_permission(struct inode *inode, int mask) * flag in inode->i_opflags, that says "this has not special * permission function, use the fast case". */ -static inline int do_inode_permission(struct inode *inode, int mask) +static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask) { if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { + if (likely(mnt && inode->i_op->permission2)) + return inode->i_op->permission2(mnt, inode, mask); if (likely(inode->i_op->permission)) return inode->i_op->permission(inode, mask); @@ -381,7 +383,7 @@ static inline int do_inode_permission(struct inode *inode, int mask) * This does not check for a read-only file system. You probably want * inode_permission(). */ -int __inode_permission(struct inode *inode, int mask) +int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask) { int retval; @@ -393,7 +395,7 @@ int __inode_permission(struct inode *inode, int mask) return -EACCES; } - retval = do_inode_permission(inode, mask); + retval = do_inode_permission(mnt, inode, mask); if (retval) return retval; @@ -403,6 +405,13 @@ int __inode_permission(struct inode *inode, int mask) return security_inode_permission(inode, mask); } +EXPORT_SYMBOL(__inode_permission2); + +int __inode_permission(struct inode *inode, int mask) +{ + return __inode_permission2(NULL, inode, mask); +} +EXPORT_SYMBOL(__inode_permission); /** * sb_permission - Check superblock-level permissions @@ -436,15 +445,22 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) * * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. */ -int inode_permission(struct inode *inode, int mask) +int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask) { int retval; retval = sb_permission(inode->i_sb, inode, mask); if (retval) return retval; - return __inode_permission(inode, mask); + return __inode_permission2(mnt, inode, mask); +} +EXPORT_SYMBOL(inode_permission2); + +int inode_permission(struct inode *inode, int mask) +{ + return inode_permission2(NULL, inode, mask); } +EXPORT_SYMBOL(inode_permission); /** * path_get - get a reference to a path @@ -1459,13 +1475,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path) static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK); if (err != -ECHILD) return err; if (unlazy_walk(nd, NULL)) return -ECHILD; } - return inode_permission(nd->inode, MAY_EXEC); + return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC); } static inline int handle_dots(struct nameidata *nd, int type) @@ -1840,10 +1856,11 @@ static int path_init(int dfd, const char *name, unsigned int flags, nd->depth = 0; if (flags & LOOKUP_ROOT) { struct inode *inode = nd->root.dentry->d_inode; + struct vfsmount *mnt = nd->root.mnt; if (*name) { if (!can_lookup(inode)) return -ENOTDIR; - retval = inode_permission(inode, MAY_EXEC); + retval = inode_permission2(mnt, inode, MAY_EXEC); if (retval) return retval; } @@ -2085,6 +2102,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) /** * lookup_one_len - filesystem helper to lookup single pathname component * @name: pathname component to lookup + * @mnt: mount we are looking up on * @base: base directory to lookup from * @len: maximum length @len should be interpreted to * @@ -2093,7 +2111,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) * nameidata argument is passed to the filesystem methods and a filesystem * using this helper needs to be prepared for that. */ -struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) +struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len) { struct qstr this; unsigned int c; @@ -2127,12 +2145,19 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) return ERR_PTR(err); } - err = inode_permission(base->d_inode, MAY_EXEC); + err = inode_permission2(mnt, base->d_inode, MAY_EXEC); if (err) return ERR_PTR(err); return __lookup_hash(&this, base, 0); } +EXPORT_SYMBOL(lookup_one_len2); + +struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) +{ + return lookup_one_len2(name, NULL, base, len); +} +EXPORT_SYMBOL(lookup_one_len); int user_path_at_empty(int dfd, const char __user *name, unsigned flags, struct path *path, int *empty) @@ -2222,7 +2247,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ -static int may_delete(struct inode *dir,struct dentry *victim,int isdir) +static int may_delete(struct vfsmount *mnt, struct inode *dir,struct dentry *victim,int isdir) { int error; @@ -2232,7 +2257,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) @@ -2262,14 +2287,14 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) * 3. We should have write and exec permissions on dir * 4. We can't do it if dir is immutable (done in permission()) */ -static inline int may_create(struct inode *dir, struct dentry *child) +static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) { audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); + return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC); } /* @@ -2314,10 +2339,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) } } -int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool want_excl) +int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, + umode_t mode, bool want_excl) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -2338,10 +2363,19 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, fsnotify_create(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_create2); + +int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl) +{ + return vfs_create2(NULL, dir, dentry, mode, want_excl); +} +EXPORT_SYMBOL(vfs_create); static int may_open(struct path *path, int acc_mode, int flag) { struct dentry *dentry = path->dentry; + struct vfsmount *mnt = path->mnt; struct inode *inode = dentry->d_inode; int error; @@ -2370,7 +2404,7 @@ static int may_open(struct path *path, int acc_mode, int flag) break; } - error = inode_permission(inode, acc_mode); + error = inode_permission2(mnt, inode, acc_mode); if (error) return error; @@ -2426,7 +2460,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) if (error) return error; - error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); + error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); if (error) return error; @@ -2614,6 +2648,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, bool got_write, int *opened) { struct dentry *dir = nd->path.dentry; + struct vfsmount *mnt = nd->path.mnt; struct inode *dir_inode = dir->d_inode; struct dentry *dentry; int error; @@ -2661,7 +2696,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, error = security_path_mknod(&nd->path, dentry, mode, 0); if (error) goto out_dput; - error = vfs_create(dir->d_inode, dentry, mode, + error = vfs_create2(mnt, dir->d_inode, dentry, mode, nd->flags & LOOKUP_EXCL); if (error) goto out_dput; @@ -3122,9 +3157,9 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, } EXPORT_SYMBOL(user_path_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -3155,6 +3190,13 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) return 0; } +EXPORT_SYMBOL(vfs_mknod2); + +int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +{ + return vfs_mknod2(NULL, dir, dentry, mode, dev); +} +EXPORT_SYMBOL(vfs_mknod); static int may_mknod(umode_t mode) { @@ -3196,10 +3238,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, goto out; switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(path.dentry->d_inode,dentry,mode,true); + error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode, + error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: @@ -3220,9 +3262,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); unsigned max_links = dir->i_sb->s_max_links; if (error) @@ -3244,6 +3286,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) fsnotify_mkdir(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_mkdir2); + +int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + return vfs_mkdir2(NULL, dir, dentry, mode); +} +EXPORT_SYMBOL(vfs_mkdir); SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) { @@ -3261,7 +3310,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) mode &= ~current_umask(); error = security_path_mkdir(&path, dentry, mode); if (!error) - error = vfs_mkdir(path.dentry->d_inode, dentry, mode); + error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode); done_path_create(&path, dentry); if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; @@ -3299,9 +3348,9 @@ void dentry_unhash(struct dentry *dentry) spin_unlock(&dentry->d_lock); } -int vfs_rmdir(struct inode *dir, struct dentry *dentry) +int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry) { - int error = may_delete(dir, dentry, 1); + int error = may_delete(mnt, dir, dentry, 1); if (error) return error; @@ -3335,6 +3384,13 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) d_delete(dentry); return error; } +EXPORT_SYMBOL(vfs_rmdir2); + +int vfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + return vfs_rmdir2(NULL, dir, dentry); +} +EXPORT_SYMBOL(vfs_rmdir); static long do_rmdir(int dfd, const char __user *pathname) { @@ -3377,7 +3433,7 @@ static long do_rmdir(int dfd, const char __user *pathname) error = security_path_rmdir(&nd.path, dentry); if (error) goto exit3; - error = vfs_rmdir(nd.path.dentry->d_inode, dentry); + error = vfs_rmdir2(nd.path.mnt, nd.path.dentry->d_inode, dentry); exit3: dput(dentry); exit2: @@ -3398,9 +3454,9 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname) return do_rmdir(AT_FDCWD, pathname); } -int vfs_unlink(struct inode *dir, struct dentry *dentry) +int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry) { - int error = may_delete(dir, dentry, 0); + int error = may_delete(mnt, dir, dentry, 0); if (error) return error; @@ -3429,6 +3485,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) return error; } +EXPORT_SYMBOL(vfs_unlink2); + +int vfs_unlink(struct inode *dir, struct dentry *dentry) +{ + return vfs_unlink2(NULL, dir, dentry); +} +EXPORT_SYMBOL(vfs_unlink); /* * Make sure that the actual truncation of the file will occur outside its @@ -3472,7 +3535,7 @@ static long do_unlinkat(int dfd, const char __user *pathname) error = security_path_unlink(&nd.path, dentry); if (error) goto exit2; - error = vfs_unlink(nd.path.dentry->d_inode, dentry); + error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry); exit2: dput(dentry); } @@ -3512,9 +3575,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) return do_unlinkat(AT_FDCWD, pathname); } -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -3531,6 +3594,13 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) fsnotify_create(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_symlink2); + +int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +{ + return vfs_symlink2(NULL, dir, dentry, oldname); +} +EXPORT_SYMBOL(vfs_symlink); SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname) @@ -3552,7 +3622,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, error = security_path_symlink(&path, dentry, from->name); if (!error) - error = vfs_symlink(path.dentry->d_inode, dentry, from->name); + error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name); done_path_create(&path, dentry); if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; @@ -3568,7 +3638,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn return sys_symlinkat(oldname, AT_FDCWD, newname); } -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct inode *inode = old_dentry->d_inode; unsigned max_links = dir->i_sb->s_max_links; @@ -3577,7 +3647,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (!inode) return -ENOENT; - error = may_create(dir, new_dentry); + error = may_create(mnt, dir, new_dentry); if (error) return error; @@ -3611,6 +3681,13 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de fsnotify_link(dir, inode, new_dentry); return error; } +EXPORT_SYMBOL(vfs_link2); + +int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +{ + return vfs_link2(NULL, old_dentry, dir, new_dentry); +} +EXPORT_SYMBOL(vfs_link); /* * Hardlinks are often used in delicate situations. We avoid @@ -3664,7 +3741,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, error = security_path_link(old_path.dentry, &new_path, new_dentry); if (error) goto out_dput; - error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); + error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry); out_dput: done_path_create(&new_path, new_dentry); if (retry_estale(error, how)) { @@ -3710,8 +3787,9 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname * ->i_mutex on parents, which works but leads to some truly excessive * locking]. */ -static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) +static int vfs_rename_dir(struct vfsmount *mnt, + struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { int error = 0; struct inode *target = new_dentry->d_inode; @@ -3722,7 +3800,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = inode_permission(old_dentry->d_inode, MAY_WRITE); + error = inode_permission2(mnt, old_dentry->d_inode, MAY_WRITE); if (error) return error; } @@ -3797,7 +3875,8 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, return error; } -int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, +int vfs_rename2(struct vfsmount *mnt, + struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int error; @@ -3807,14 +3886,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (old_dentry->d_inode == new_dentry->d_inode) return 0; - error = may_delete(old_dir, old_dentry, is_dir); + error = may_delete(mnt, old_dir, old_dentry, is_dir); if (error) return error; if (!new_dentry->d_inode) - error = may_create(new_dir, new_dentry); + error = may_create(mnt, new_dir, new_dentry); else - error = may_delete(new_dir, new_dentry, is_dir); + error = may_delete(mnt, new_dir, new_dentry, is_dir); if (error) return error; @@ -3824,7 +3903,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_name = fsnotify_oldname_init(old_dentry->d_name.name); if (is_dir) - error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_dir(mnt, old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) @@ -3834,6 +3913,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, return error; } +EXPORT_SYMBOL(vfs_rename2); + +int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry); +} +EXPORT_SYMBOL(vfs_rename); SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname) @@ -3916,7 +4003,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, &newnd.path, new_dentry); if (error) goto exit5; - error = vfs_rename(old_dir->d_inode, old_dentry, + error = vfs_rename2(oldnd.path.mnt, old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); exit5: dput(new_dentry); @@ -4090,7 +4177,6 @@ EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* nfsd */ EXPORT_SYMBOL(lock_rename); -EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link_light); EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); @@ -4099,18 +4185,9 @@ EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(kern_path); EXPORT_SYMBOL(vfs_path_lookup); -EXPORT_SYMBOL(inode_permission); EXPORT_SYMBOL(unlock_rename); -EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_follow_link); -EXPORT_SYMBOL(vfs_link); -EXPORT_SYMBOL(vfs_mkdir); -EXPORT_SYMBOL(vfs_mknod); EXPORT_SYMBOL(generic_permission); EXPORT_SYMBOL(vfs_readlink); -EXPORT_SYMBOL(vfs_rename); -EXPORT_SYMBOL(vfs_rmdir); -EXPORT_SYMBOL(vfs_symlink); -EXPORT_SYMBOL(vfs_unlink); EXPORT_SYMBOL(dentry_unhash); EXPORT_SYMBOL(generic_readlink); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index f1680cdbd88b..04238f80c123 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -490,7 +490,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, } /* you can only watch an inode if you have read permissions on it */ - ret = inode_permission(path->dentry->d_inode, MAY_READ); + ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); if (ret) path_put(path); out: diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index fce2b8502237..941e59d7ffe7 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -349,7 +349,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = inode_permission(path->dentry->d_inode, MAY_READ); + error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); if (error) path_put(path); return error; diff --git a/fs/open.c b/fs/open.c index b1fd2c1d55f4..73b0a1033e13 100644 --- a/fs/open.c +++ b/fs/open.c @@ -65,9 +65,11 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, long vfs_truncate(struct path *path, loff_t length) { struct inode *inode; + struct vfsmount *mnt; long error; inode = path->dentry->d_inode; + mnt = path->mnt; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ if (S_ISDIR(inode->i_mode)) @@ -79,7 +81,7 @@ long vfs_truncate(struct path *path, loff_t length) if (error) goto out; - error = inode_permission(inode, MAY_WRITE); + error = inode_permission2(mnt, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -302,6 +304,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) struct cred *override_cred; struct path path; struct inode *inode; + struct vfsmount *mnt; int res; unsigned int lookup_flags = LOOKUP_FOLLOW; @@ -332,6 +335,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) goto out; inode = path.dentry->d_inode; + mnt = path.mnt; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { /* @@ -343,7 +347,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) goto out_path_release; } - res = inode_permission(inode, mode | MAY_ACCESS); + res = inode_permission2(mnt, inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -387,7 +391,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -407,6 +411,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); struct inode *inode; + struct vfsmount *mnt; int error = -EBADF; error = -EBADF; @@ -414,12 +419,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) goto out; inode = file_inode(f.file); + mnt = f.file->f_path.mnt; error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(mnt, inode, MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: @@ -438,7 +444,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; diff --git a/fs/utimes.c b/fs/utimes.c index f4fb7eca10e8..67250973d966 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -96,7 +96,7 @@ static int utimes_common(struct path *path, struct timespec *times) goto mnt_drop_write_and_out; if (!inode_owner_or_capable(inode)) { - error = inode_permission(inode, MAY_WRITE); + error = inode_permission2(path->mnt, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; } diff --git a/include/linux/fs.h b/include/linux/fs.h index e6ebd4ced34f..43ec29b16db9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1459,13 +1459,20 @@ extern bool inode_owner_or_capable(const struct inode *inode); * VFS helper functions.. */ extern int vfs_create(struct inode *, struct dentry *, umode_t, bool); +extern int vfs_create2(struct vfsmount *, struct inode *, struct dentry *, umode_t, bool); extern int vfs_mkdir(struct inode *, struct dentry *, umode_t); +extern int vfs_mkdir2(struct vfsmount *, struct inode *, struct dentry *, umode_t); extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); +extern int vfs_mknod2(struct vfsmount *, struct inode *, struct dentry *, umode_t, dev_t); extern int vfs_symlink(struct inode *, struct dentry *, const char *); extern int vfs_link(struct dentry *, struct inode *, struct dentry *); +extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *); extern int vfs_rmdir(struct inode *, struct dentry *); +extern int vfs_rmdir2(struct vfsmount *, struct inode *, struct dentry *); extern int vfs_unlink(struct inode *, struct dentry *); +extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *); extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *); /* * VFS dentry helper functions. @@ -1570,6 +1577,7 @@ struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); void * (*follow_link) (struct dentry *, struct nameidata *); int (*permission) (struct inode *, int); + int (*permission2) (struct vfsmount *, struct inode *, int); struct posix_acl * (*get_acl)(struct inode *, int); int (*readlink) (struct dentry *, char __user *,int); @@ -2240,6 +2248,7 @@ extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); +extern int inode_permission2(struct vfsmount *, struct inode *, int); extern int generic_permission(struct inode *, int); static inline bool execute_ok(struct inode *inode) diff --git a/include/linux/namei.h b/include/linux/namei.h index fd536a7a5d30..6983e9c8c3fa 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -75,6 +75,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); +extern struct dentry *lookup_one_len2(const char *, struct vfsmount *mnt, struct dentry *, int); extern int follow_down_one(struct path *); extern int follow_down(struct path *); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index bb0248fc5187..88d97d21a399 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -754,7 +754,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir, } mode &= ~current_umask(); - ret = vfs_create(dir, path->dentry, mode, true); + ret = vfs_create2(path->mnt, dir, path->dentry, mode, true); path->dentry->d_fsdata = NULL; if (ret) return ERR_PTR(ret); @@ -770,7 +770,7 @@ static struct file *do_open(struct path *path, int oflag) if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) return ERR_PTR(-EINVAL); acc = oflag2acc[oflag & O_ACCMODE]; - if (inode_permission(path->dentry->d_inode, acc)) + if (inode_permission2(path->mnt, path->dentry->d_inode, acc)) return ERR_PTR(-EACCES); return dentry_open(path, oflag, current_cred()); } @@ -803,7 +803,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ro = mnt_want_write(mnt); /* we'll drop it in any case */ error = 0; mutex_lock(&root->d_inode->i_mutex); - path.dentry = lookup_one_len(name->name, root, strlen(name->name)); + path.dentry = lookup_one_len2(name->name, mnt, root, strlen(name->name)); if (IS_ERR(path.dentry)) { error = PTR_ERR(path.dentry); goto out_putfd; @@ -874,7 +874,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) if (err) goto out_name; mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); - dentry = lookup_one_len(name->name, mnt->mnt_root, + dentry = lookup_one_len2(name->name, mnt, mnt->mnt_root, strlen(name->name)); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); @@ -886,7 +886,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) err = -ENOENT; } else { ihold(inode); - err = vfs_unlink(dentry->d_parent->d_inode, dentry); + err = vfs_unlink2(mnt, dentry->d_parent->d_inode, dentry); } dput(dentry); diff --git a/security/inode.c b/security/inode.c index 43ce6e19015f..94466a5eed50 100644 --- a/security/inode.c +++ b/security/inode.c @@ -105,7 +105,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode, dir = parent->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_one_len(name, parent, strlen(name)); + dentry = lookup_one_len2(name, mount, parent, strlen(name)); if (IS_ERR(dentry)) goto out; From 073332ded48eb4d51253ed90ec4f0ee7e0b731ad Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 16:33:11 -0700 Subject: [PATCH 033/281] vfs: Add setattr2 for filesystems with per mount permissions This allows filesystems to use their mount private data to influence the permssions they use in setattr2. It has been separated into a new call to avoid disrupting current setattr users. Change-Id: I19959038309284448f1b7f232d579674ef546385 Signed-off-by: Daniel Rosenberg --- fs/attr.c | 12 ++++++++++-- fs/coredump.c | 2 +- fs/inode.c | 6 +++--- fs/open.c | 21 ++++++++++++++------- fs/utimes.c | 2 +- include/linux/fs.h | 4 ++++ 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 66fa6251c398..64fc5985c598 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -167,7 +167,7 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) } EXPORT_SYMBOL(setattr_copy); -int notify_change(struct dentry * dentry, struct iattr * attr) +int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; @@ -239,7 +239,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (error) return error; - if (inode->i_op->setattr) + if (mnt && inode->i_op->setattr2) + error = inode->i_op->setattr2(mnt, dentry, attr); + else if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); @@ -252,4 +254,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr) return error; } +EXPORT_SYMBOL(notify_change2); + +int notify_change(struct dentry * dentry, struct iattr * attr) +{ + return notify_change2(NULL, dentry, attr); +} EXPORT_SYMBOL(notify_change); diff --git a/fs/coredump.c b/fs/coredump.c index dafafbafa731..6c5ce07a87ab 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -644,7 +644,7 @@ void do_coredump(siginfo_t *siginfo) goto close_fail; if (!cprm.file->f_op || !cprm.file->f_op->write) goto close_fail; - if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) + if (do_truncate2(cprm.file->f_path.mnt, cprm.file->f_path.dentry, 0, 0, cprm.file)) goto close_fail; } diff --git a/fs/inode.c b/fs/inode.c index 1b300a06b8be..77e54c44adbb 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1599,12 +1599,12 @@ int should_remove_suid(struct dentry *dentry) } EXPORT_SYMBOL(should_remove_suid); -static int __remove_suid(struct dentry *dentry, int kill) +static int __remove_suid(struct vfsmount *mnt, struct dentry *dentry, int kill) { struct iattr newattrs; newattrs.ia_valid = ATTR_FORCE | kill; - return notify_change(dentry, &newattrs); + return notify_change2(mnt, dentry, &newattrs); } int file_remove_suid(struct file *file) @@ -1627,7 +1627,7 @@ int file_remove_suid(struct file *file) if (killpriv) error = security_inode_killpriv(dentry); if (!error && killsuid) - error = __remove_suid(dentry, killsuid); + error = __remove_suid(file->f_path.mnt, dentry, killsuid); if (!error && (inode->i_sb->s_flags & MS_NOSEC)) inode->i_flags |= S_NOSEC; diff --git a/fs/open.c b/fs/open.c index 73b0a1033e13..eec8b7f525d5 100644 --- a/fs/open.c +++ b/fs/open.c @@ -34,8 +34,8 @@ #include "internal.h" -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) +int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length, + unsigned int time_attrs, struct file *filp) { int ret; struct iattr newattrs; @@ -57,10 +57,15 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, newattrs.ia_valid |= ret | ATTR_FORCE; mutex_lock(&dentry->d_inode->i_mutex); - ret = notify_change(dentry, &newattrs); + ret = notify_change2(mnt, dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); return ret; } +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + struct file *filp) +{ + return do_truncate2(NULL, dentry, length, time_attrs, filp); +} long vfs_truncate(struct path *path, loff_t length) { @@ -105,7 +110,7 @@ long vfs_truncate(struct path *path, loff_t length) if (!error) error = security_path_truncate(path); if (!error) - error = do_truncate(path->dentry, length, 0, NULL); + error = do_truncate2(mnt, path->dentry, length, 0, NULL); put_write_and_out: put_write_access(inode); @@ -154,6 +159,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode *inode; struct dentry *dentry; + struct vfsmount *mnt; struct fd f; int error; @@ -170,6 +176,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) small = 0; dentry = f.file->f_path.dentry; + mnt = f.file->f_path.mnt; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) @@ -189,7 +196,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) if (!error) error = security_path_truncate(&f.file->f_path); if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); + error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); sb_end_write(inode->i_sb); out_putf: fdput(f); @@ -482,7 +489,7 @@ static int chmod_common(struct path *path, umode_t mode) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); out_unlock: mutex_unlock(&inode->i_mutex); mnt_drop_write(path->mnt); @@ -556,7 +563,7 @@ static int chown_common(struct path *path, uid_t user, gid_t group) mutex_lock(&inode->i_mutex); error = security_path_chown(path, uid, gid); if (!error) - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); return error; diff --git a/fs/utimes.c b/fs/utimes.c index 67250973d966..7216a079d569 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -102,7 +102,7 @@ static int utimes_common(struct path *path, struct timespec *times) } } mutex_lock(&inode->i_mutex); - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); mnt_drop_write_and_out: diff --git a/include/linux/fs.h b/include/linux/fs.h index 43ec29b16db9..3e7961ccc8f8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1593,6 +1593,7 @@ struct inode_operations { int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); int (*setattr) (struct dentry *, struct iattr *); + int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); @@ -2036,6 +2037,8 @@ struct filename { extern long vfs_truncate(struct path *, loff_t); extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, struct file *filp); +extern int do_truncate2(struct vfsmount *, struct dentry *, loff_t start, + unsigned int time_attrs, struct file *filp); extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, @@ -2247,6 +2250,7 @@ extern int unregister_fs_notifier(struct notifier_block *nb); extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); +extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); extern int inode_permission2(struct vfsmount *, struct inode *, int); extern int generic_permission(struct inode *, int); From 1de9ad1ddc491064c0ad41dc04df59fd790e13fc Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 16:48:45 -0700 Subject: [PATCH 034/281] sdcardfs: User new permission2 functions Change-Id: Ic7e0fb8fdcebb31e657b079fe02ac834c4a50db9 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/inode.c | 26 ++++++++++++++++++++------ fs/sdcardfs/sdcardfs.h | 4 ++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 49554269f955..98c9aec3ce0a 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -54,6 +54,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, { int err = 0; struct dentry *lower_dentry; + struct vfsmount *lower_dentry_mnt; struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; @@ -73,6 +74,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; + lower_dentry_mnt = lower_path.mnt; lower_parent_dentry = lock_parent(lower_dentry); /* set last 16bytes of mode field to 0664 */ @@ -87,7 +89,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, } current->fs = copied_fs; current->fs->umask = 0; - err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); + err = vfs_create2(lower_dentry_mnt, lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -154,6 +156,7 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct inode *lower_dir_inode = sdcardfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; @@ -172,10 +175,11 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); - err = vfs_unlink(lower_dir_inode, lower_dentry); + err = vfs_unlink2(lower_mnt, lower_dir_inode, lower_dentry); /* * Note: unlinking on top of NFS can cause silly-renamed files. @@ -256,6 +260,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode int err = 0; int make_nomedia_in_obb = 0; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); @@ -286,6 +291,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; lower_parent_dentry = lock_parent(lower_dentry); /* set last 16bytes of mode field to 0775 */ @@ -301,7 +307,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } current->fs = copied_fs; current->fs->umask = 0; - err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); + err = vfs_mkdir2(lower_mnt, lower_parent_dentry->d_inode, lower_dentry, mode); if (err) { unlock_dir(lower_parent_dentry); @@ -370,6 +376,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; struct dentry *lower_dir_dentry; + struct vfsmount *lower_mnt; int err; struct path lower_path; const struct cred *saved_cred = NULL; @@ -390,9 +397,10 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) sdcardfs_get_real_lower(dentry, &lower_path); lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; lower_dir_dentry = lock_parent(lower_dentry); - err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + err = vfs_rmdir2(lower_mnt, lower_dir_dentry->d_inode, lower_dentry); if (err) goto out; @@ -456,6 +464,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; + struct vfsmount *lower_mnt = NULL; struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; @@ -477,6 +486,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, sdcardfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; + lower_mnt = lower_old_path.mnt; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); @@ -492,7 +502,8 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; } - err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, + err = vfs_rename2(lower_mnt, + lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out; @@ -654,6 +665,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct inode *inode; struct inode *lower_inode; struct path lower_path; @@ -687,6 +699,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; lower_inode = sdcardfs_lower_inode(inode); /* prepare our own lower struct iattr (with the lower file) */ @@ -730,7 +743,8 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) * tries to open(), unlink(), then ftruncate() a file. */ mutex_lock(&lower_dentry->d_inode->i_mutex); - err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ + err = notify_change2(lower_mnt, lower_dentry, &lower_ia); /* note: lower_ia */ + mutex_unlock(&lower_dentry->d_inode->i_mutex); if (current->mm) up_write(¤t->mm->mmap_sem); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 00b8f7435e62..1931d5bd6cdd 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -476,7 +476,7 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m goto out_unlock; } - err = vfs_mkdir(parent.dentry->d_inode, dent, mode); + err = vfs_mkdir2(parent.mnt, parent.dentry->d_inode, dent, mode); if (err) { if (err == -EEXIST) err = 0; @@ -487,7 +487,7 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m attrs.ia_gid = gid; attrs.ia_valid = ATTR_UID | ATTR_GID; mutex_lock(&dent->d_inode->i_mutex); - notify_change(dent, &attrs); + notify_change2(parent.mnt, dent, &attrs); mutex_unlock(&dent->d_inode->i_mutex); out_dput: From 2dda0ba1133eac03fb820e03e10cd151805bba15 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 17:36:05 -0700 Subject: [PATCH 035/281] sdcardfs: Add gid and mask to private mount data Adds support for mount2, remount2, and the functions to allocate/clone/copy the private data The next patch will switch over to actually using it. Change-Id: I8a43da26021d33401f655f0b2784ead161c575e3 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/main.c | 103 ++++++++++++++++++++++++++++++++++++----- fs/sdcardfs/sdcardfs.h | 8 ++++ fs/sdcardfs/super.c | 64 ++++++++++++++++++++++--- 3 files changed, 157 insertions(+), 18 deletions(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 3666aef3e0f0..a693a35928ad 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -49,7 +49,8 @@ static const match_table_t sdcardfs_tokens = { }; static int parse_options(struct super_block *sb, char *options, int silent, - int *debug, struct sdcardfs_mount_options *opts) + int *debug, struct sdcardfs_vfsmount_options *vfsopts, + struct sdcardfs_mount_options *opts) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -58,9 +59,11 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, we use AID_MEDIA_RW as uid, gid */ opts->fs_low_uid = AID_MEDIA_RW; opts->fs_low_gid = AID_MEDIA_RW; + vfsopts->mask = 0; opts->mask = 0; opts->multiuser = false; opts->fs_user_id = 0; + vfsopts->gid = 0; opts->gid = 0; /* by default, 0MB is reserved */ opts->reserved_mb = 0; @@ -95,6 +98,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, if (match_int(&args[0], &option)) return 0; opts->gid = option; + vfsopts->gid = option; break; case Opt_userid: if (match_int(&args[0], &option)) @@ -105,6 +109,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, if (match_int(&args[0], &option)) return 0; opts->mask = option; + vfsopts->mask = option; break; case Opt_multiuser: opts->multiuser = true; @@ -135,6 +140,65 @@ static int parse_options(struct super_block *sb, char *options, int silent, return 0; } +int parse_options_remount(struct super_block *sb, char *options, int silent, + struct sdcardfs_vfsmount_options *vfsopts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + int debug; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, sdcardfs_tokens, args); + + switch (token) { + case Opt_debug: + debug = 1; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + vfsopts->gid = option; + + break; + case Opt_mask: + if (match_int(&args[0], &option)) + return 0; + vfsopts->mask = option; + break; + case Opt_multiuser: + case Opt_userid: + case Opt_fsuid: + case Opt_fsgid: + case Opt_reserved_mb: + printk( KERN_WARNING "Option \"%s\" can't be changed during remount\n", p); + break; + /* unknown option */ + default: + if (!silent) { + printk( KERN_ERR "Unrecognized mount option \"%s\" " + "or missing value", p); + } + return -EINVAL; + } + } + + if (debug) { + printk( KERN_INFO "sdcardfs : options - debug:%d\n", debug); + printk( KERN_INFO "sdcardfs : options - gid:%d\n", vfsopts->gid); + printk( KERN_INFO "sdcardfs : options - mask:%d\n", vfsopts->mask); + } + + return 0; +} + #if 0 /* * our custom d_alloc_root work-alike @@ -172,14 +236,15 @@ EXPORT_SYMBOL_GPL(sdcardfs_super_list); * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ -static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, - void *raw_data, int silent) +static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, + const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; + struct sdcardfs_vfsmount_options *mnt_opt = mnt->data; struct inode *inode; printk(KERN_INFO "sdcardfs version 2.0\n"); @@ -212,7 +277,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, sb_info = sb->s_fs_info; /* parse options */ - err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); + err = parse_options(sb, raw_data, silent, &debug, mnt_opt, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options\n"); goto out_freesbi; @@ -306,9 +371,9 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, } /* A feature which supports mount_nodev() with options */ -static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, const char *, void *, int)) +static struct dentry *mount_nodev_with_options(struct vfsmount *mnt, + struct file_system_type *fs_type, int flags, const char *dev_name, void *data, + int (*fill_super)(struct vfsmount *, struct super_block *, const char *, void *, int)) { int error; @@ -319,7 +384,7 @@ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, s->s_flags = flags; - error = fill_super(s, dev_name, data, flags & MS_SILENT ? 1 : 0); + error = fill_super(mnt, s, dev_name, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(s); return ERR_PTR(error); @@ -328,15 +393,27 @@ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, return dget(s->s_root); } -struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags, +static struct dentry *sdcardfs_mount(struct vfsmount *mnt, + struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) { /* * dev_name is a lower_path_name, * raw_data is a option string. */ - return mount_nodev_with_options(fs_type, flags, dev_name, - raw_data, sdcardfs_read_super); + return mount_nodev_with_options(mnt, fs_type, flags, dev_name, + raw_data, sdcardfs_read_super); +} + +static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) +{ + WARN(1, "sdcardfs does not support mount. Use mount2.\n"); + return ERR_PTR(-EINVAL); +} + +void *sdcardfs_alloc_mnt_data(void) { + return kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); } void sdcardfs_kill_sb(struct super_block *sb) { @@ -353,7 +430,9 @@ void sdcardfs_kill_sb(struct super_block *sb) { static struct file_system_type sdcardfs_fs_type = { .owner = THIS_MODULE, .name = SDCARDFS_NAME, - .mount = sdcardfs_mount, + .mount = sdcardfs_mount_wrn, + .mount2 = sdcardfs_mount, + .alloc_mnt_data = sdcardfs_alloc_mnt_data, .kill_sb = sdcardfs_kill_sb, .fs_flags = 0, }; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 1931d5bd6cdd..8ed143a16fcc 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -193,6 +193,14 @@ struct sdcardfs_mount_options { unsigned int reserved_mb; }; +struct sdcardfs_vfsmount_options { + gid_t gid; + mode_t mask; +}; + +extern int parse_options_remount(struct super_block *sb, char *options, int silent, + struct sdcardfs_vfsmount_options *vfsopts); + /* sdcardfs super-block data in memory */ struct sdcardfs_sb_info { struct super_block *sb; diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 0a465395aab7..edda32b68dc0 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -108,6 +108,50 @@ static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options return err; } +/* + * @mnt: mount point we are remounting + * @sb: superblock we are remounting + * @flags: numeric mount options + * @options: mount options string + */ +static int sdcardfs_remount_fs2(struct vfsmount *mnt, struct super_block *sb, + int *flags, char *options) +{ + int err = 0; + + /* + * The VFS will take care of "ro" and "rw" flags among others. We + * can safely accept a few flags (RDONLY, MANDLOCK), and honor + * SILENT, but anything else left over is an error. + */ + if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT | MS_REMOUNT)) != 0) { + printk(KERN_ERR + "sdcardfs: remount flags 0x%x unsupported\n", *flags); + err = -EINVAL; + } + printk(KERN_INFO "Remount options were %s for vfsmnt %p.\n", options, mnt); + err = parse_options_remount(sb, options, *flags & ~MS_SILENT, mnt->data); + + + return err; +} + +static void* sdcardfs_clone_mnt_data(void *data) { + struct sdcardfs_vfsmount_options* opt = kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); + struct sdcardfs_vfsmount_options* old = data; + if(!opt) return NULL; + opt->gid = old->gid; + opt->mask = old->mask; + return opt; +} + +static void sdcardfs_copy_mnt_data(void *data, void *newdata) { + struct sdcardfs_vfsmount_options* old = data; + struct sdcardfs_vfsmount_options* new = newdata; + old->gid = new->gid; + old->mask = new->mask; +} + /* * Called by iput() when the inode reference count reached zero * and the inode is not hashed anywhere. Used to clear anything @@ -191,19 +235,24 @@ static void sdcardfs_umount_begin(struct super_block *sb) lower_sb->s_op->umount_begin(lower_sb); } -static int sdcardfs_show_options(struct seq_file *m, struct dentry *root) +static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, struct dentry *root) { struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb); struct sdcardfs_mount_options *opts = &sbi->options; + struct sdcardfs_vfsmount_options *vfsopts = mnt->data; if (opts->fs_low_uid != 0) - seq_printf(m, ",uid=%u", opts->fs_low_uid); + seq_printf(m, ",fsuid=%u", opts->fs_low_uid); if (opts->fs_low_gid != 0) - seq_printf(m, ",gid=%u", opts->fs_low_gid); - + seq_printf(m, ",fsgid=%u", opts->fs_low_gid); + if (vfsopts->gid != 0) + seq_printf(m, ",gid=%u", vfsopts->gid); if (opts->multiuser) seq_printf(m, ",multiuser"); - + if (vfsopts->mask) + seq_printf(m, ",mask=%u", vfsopts->mask); + if (opts->fs_user_id) + seq_printf(m, ",userid=%u", opts->fs_user_id); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); @@ -214,9 +263,12 @@ const struct super_operations sdcardfs_sops = { .put_super = sdcardfs_put_super, .statfs = sdcardfs_statfs, .remount_fs = sdcardfs_remount_fs, + .remount_fs2 = sdcardfs_remount_fs2, + .clone_mnt_data = sdcardfs_clone_mnt_data, + .copy_mnt_data = sdcardfs_copy_mnt_data, .evict_inode = sdcardfs_evict_inode, .umount_begin = sdcardfs_umount_begin, - .show_options = sdcardfs_show_options, + .show_options2 = sdcardfs_show_options, .alloc_inode = sdcardfs_alloc_inode, .destroy_inode = sdcardfs_destroy_inode, .drop_inode = generic_delete_inode, From a0b17571b8b1bd3f0bda6e80a88a8e1712503dfe Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 26 Oct 2016 20:27:20 -0700 Subject: [PATCH 036/281] sdcardfs: Use per mount permissions This switches sdcardfs over to using permission2. Instead of mounting several sdcardfs instances onto the same underlaying directory, you bind mount a single mount several times, and remount with the options you want. These are stored in the private mount data, allowing you to maintain the same tree, but have different permissions for different mount points. Warning functions have been added for permission, as it should never be called, and the correct behavior is unclear. Change-Id: I841b1d70ec60cf2b866fa48edeb74a0b0f8334f5 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 18 ++++-- fs/sdcardfs/inode.c | 127 ++++++++++++++++++++++++++++++------- fs/sdcardfs/lookup.c | 4 +- fs/sdcardfs/main.c | 8 +-- fs/sdcardfs/sdcardfs.h | 45 ++++++++----- 5 files changed, 150 insertions(+), 52 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 6be6747f6175..9e3e78229b41 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -141,13 +141,23 @@ void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) info = SDCARDFS_I(dentry->d_inode); if (needs_fixup(info->perm)) { + /* We need permission to fix up these values. + * Since permissions are based of of the mount, and + * we are accessing without the mount point, we create + * a fake mount with the permissions we will be using. + */ + struct vfsmount fakemnt; + struct sdcardfs_vfsmount_options opts; + fakemnt.data = &opts; + opts.gid = AID_SDCARD_RW; + opts.mask = 0; mutex_lock(&dentry->d_inode->i_mutex); - child = lookup_one_len(name, dentry, len); + child = lookup_one_len2(name, &fakemnt, dentry, len); mutex_unlock(&dentry->d_inode->i_mutex); if (!IS_ERR(child)) { if (child->d_inode) { get_derived_permission(dentry, child); - fix_derived_permission(child->d_inode); + fixup_tmp_permissions(child->d_inode); } dput(child); } @@ -172,7 +182,7 @@ void fixup_top_recursive(struct dentry *parent) { if (dentry->d_inode) { if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { get_derived_permission(parent, dentry); - fix_derived_permission(dentry->d_inode); + fixup_tmp_permissions(dentry->d_inode); fixup_top_recursive(dentry); } } @@ -202,7 +212,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) dput(parent); } } - fix_derived_permission(dentry->d_inode); + fixup_tmp_permissions(dentry->d_inode); } int need_graft_path(struct dentry *dentry) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 98c9aec3ce0a..892fe8cfb4c8 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -530,7 +530,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* At this point, not all dentry information has been moved, so * we pass along new_dentry for the name.*/ get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); - fix_derived_permission(old_dentry->d_inode); + fixup_tmp_permissions(old_dentry->d_inode); fixup_top_recursive(old_dentry); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); @@ -613,26 +613,63 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, } #endif -static int sdcardfs_permission(struct inode *inode, int mask) +static int sdcardfs_permission_wrn(struct inode *inode, int mask) +{ + WARN(1, "sdcardfs does not support permission. Use permission2.\n"); + return -EINVAL; +} + +void copy_attrs(struct inode *dest, const struct inode *src) +{ + dest->i_mode = src->i_mode; + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; +#ifdef CONFIG_FS_POSIX_ACL + dest->i_acl = src->i_acl; +#endif +#ifdef CONFIG_SECURITY + dest->i_security = src->i_security; +#endif +} + +static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int mask) { int err; + struct inode tmp; struct inode *top = grab_top(SDCARDFS_I(inode)); - if (!top) + if (!top) { + release_top(SDCARDFS_I(inode)); + WARN(1, "Top value was null!\n"); return -EINVAL; - /* Ensure owner is up to date */ - if (!uid_eq(inode->i_uid, top->i_uid)) { - SDCARDFS_I(inode)->d_uid = SDCARDFS_I(top)->d_uid; - fix_derived_permission(inode); } - release_top(SDCARDFS_I(inode)); /* * Permission check on sdcardfs inode. * Calling process should have AID_SDCARD_RW permission + * Since generic_permission only needs i_mode, i_uid, + * i_gid, and i_sb, we can create a fake inode to pass + * this information down in. + * + * The underlying code may attempt to take locks in some + * cases for features we're not using, but if that changes, + * locks must be dealt with to avoid undefined behavior. */ - err = generic_permission(inode, mask); - + copy_attrs(&tmp, inode); + tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); + tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); + release_top(SDCARDFS_I(inode)); + tmp.i_sb = inode->i_sb; + if (IS_POSIXACL(inode)) + printk(KERN_WARNING "%s: This may be undefined behavior... \n", __func__); + err = generic_permission(&tmp, mask); /* XXX * Original sdcardfs code calls inode_permission(lower_inode,.. ) * for checking inode permission. But doing such things here seems @@ -661,7 +698,13 @@ static int sdcardfs_permission(struct inode *inode, int mask) } -static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) +static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia) +{ + WARN(1, "sdcardfs does not support setattr. User setattr2.\n"); + return -EINVAL; +} + +static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; @@ -671,17 +714,45 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) struct path lower_path; struct iattr lower_ia; struct dentry *parent; + struct inode tmp; + struct inode *top; + const struct cred *saved_cred = NULL; inode = dentry->d_inode; + top = grab_top(SDCARDFS_I(inode)); + + if (!top) { + release_top(SDCARDFS_I(inode)); + return -EINVAL; + } + + /* + * Permission check on sdcardfs inode. + * Calling process should have AID_SDCARD_RW permission + * Since generic_permission only needs i_mode, i_uid, + * i_gid, and i_sb, we can create a fake inode to pass + * this information down in. + * + * The underlying code may attempt to take locks in some + * cases for features we're not using, but if that changes, + * locks must be dealt with to avoid undefined behavior. + * + */ + copy_attrs(&tmp, inode); + tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); + tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); + tmp.i_size = i_size_read(inode); + release_top(SDCARDFS_I(inode)); + tmp.i_sb = inode->i_sb; /* * Check if user has permission to change inode. We don't check if * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ - err = inode_change_ok(inode, ia); + err = inode_change_ok(&tmp, ia); - /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ if (!err) { /* check the Android group ID */ parent = dget_parent(dentry); @@ -697,6 +768,9 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) if (err) goto out_err; + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred); + sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_mnt = lower_path.mnt; @@ -720,7 +794,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) if (current->mm) down_write(¤t->mm->mmap_sem); if (ia->ia_valid & ATTR_SIZE) { - err = inode_newsize_ok(inode, ia->ia_size); + err = inode_newsize_ok(&tmp, ia->ia_size); if (err) { if (current->mm) up_write(¤t->mm->mmap_sem); @@ -762,11 +836,12 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) out: sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); out_err: return err; } -static int sdcardfs_fillattr(struct inode *inode, struct kstat *stat) +static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode, struct kstat *stat) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); struct inode *top = grab_top(info); @@ -775,10 +850,10 @@ static int sdcardfs_fillattr(struct inode *inode, struct kstat *stat) stat->dev = inode->i_sb->s_dev; stat->ino = inode->i_ino; - stat->mode = (inode->i_mode & S_IFMT) | get_mode(SDCARDFS_I(top)); + stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); stat->nlink = inode->i_nlink; stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); - stat->gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(top))); + stat->gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); stat->rdev = inode->i_rdev; stat->size = i_size_read(inode); stat->atime = inode->i_atime; @@ -819,14 +894,14 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, sdcardfs_copy_and_fix_attrs(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); - err = sdcardfs_fillattr(inode, stat); + err = sdcardfs_fillattr(mnt, inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return err; } const struct inode_operations sdcardfs_symlink_iops = { - .permission = sdcardfs_permission, - .setattr = sdcardfs_setattr, + .permission2 = sdcardfs_permission, + .setattr2 = sdcardfs_setattr, /* XXX Following operations are implemented, * but FUSE(sdcard) or FAT does not support them * These methods are *NOT* perfectly tested. @@ -839,12 +914,14 @@ const struct inode_operations sdcardfs_symlink_iops = { const struct inode_operations sdcardfs_dir_iops = { .create = sdcardfs_create, .lookup = sdcardfs_lookup, - .permission = sdcardfs_permission, + .permission = sdcardfs_permission_wrn, + .permission2 = sdcardfs_permission, .unlink = sdcardfs_unlink, .mkdir = sdcardfs_mkdir, .rmdir = sdcardfs_rmdir, .rename = sdcardfs_rename, - .setattr = sdcardfs_setattr, + .setattr = sdcardfs_setattr_wrn, + .setattr2 = sdcardfs_setattr, .getattr = sdcardfs_getattr, /* XXX Following operations are implemented, * but FUSE(sdcard) or FAT does not support them @@ -856,7 +933,9 @@ const struct inode_operations sdcardfs_dir_iops = { }; const struct inode_operations sdcardfs_main_iops = { - .permission = sdcardfs_permission, - .setattr = sdcardfs_setattr, + .permission = sdcardfs_permission_wrn, + .permission2 = sdcardfs_permission, + .setattr = sdcardfs_setattr_wrn, + .setattr2 = sdcardfs_setattr, .getattr = sdcardfs_getattr, }; diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 7ffecfecc6c2..d02501213620 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -244,6 +244,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, if (err == -ENOENT) { struct dentry *child; struct dentry *match = NULL; + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); spin_lock(&lower_dir_dentry->d_lock); list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) { if (child && child->d_inode) { @@ -254,6 +255,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, } } spin_unlock(&lower_dir_dentry->d_lock); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (match) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, @@ -389,7 +391,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, sdcardfs_lower_inode(dentry->d_inode)); /* get derived permission */ get_derived_permission(parent, dentry); - fix_derived_permission(dentry->d_inode); + fixup_tmp_permissions(dentry->d_inode); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index a693a35928ad..8d16e4d16d96 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -28,7 +28,6 @@ enum { Opt_fsgid, Opt_gid, Opt_debug, - Opt_lower_fs, Opt_mask, Opt_multiuser, // May need? Opt_userid, @@ -60,11 +59,9 @@ static int parse_options(struct super_block *sb, char *options, int silent, opts->fs_low_uid = AID_MEDIA_RW; opts->fs_low_gid = AID_MEDIA_RW; vfsopts->mask = 0; - opts->mask = 0; opts->multiuser = false; opts->fs_user_id = 0; vfsopts->gid = 0; - opts->gid = 0; /* by default, 0MB is reserved */ opts->reserved_mb = 0; @@ -97,7 +94,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_gid: if (match_int(&args[0], &option)) return 0; - opts->gid = option; vfsopts->gid = option; break; case Opt_userid: @@ -108,7 +104,6 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_mask: if (match_int(&args[0], &option)) return 0; - opts->mask = option; vfsopts->mask = option; break; case Opt_multiuser: @@ -258,6 +253,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); + printk(KERN_INFO "sdcardfs: mnt -> %p\n", mnt); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, @@ -342,7 +338,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } - fix_derived_permission(sb->s_root->d_inode); + fixup_tmp_permissions(sb->s_root->d_inode); sb_info->sb = sb; list_add(&sb_info->list, &sdcardfs_super_list); mutex_unlock(&sdcardfs_super_list_lock); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 8ed143a16fcc..b47bc0b93315 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -68,14 +68,20 @@ #define AID_PACKAGE_INFO 1027 -#define fix_derived_permission(x) \ + +/* + * Permissions are handled by our permission function. + * We don't want anyone who happens to look at our inode value to prematurely + * block access, so store more permissive values. These are probably never + * used. + */ +#define fixup_tmp_permissions(x) \ do { \ (x)->i_uid = SDCARDFS_I(x)->d_uid; \ - (x)->i_gid = get_gid(SDCARDFS_I(x)); \ - (x)->i_mode = ((x)->i_mode & S_IFMT) | get_mode(SDCARDFS_I(x));\ + (x)->i_gid = AID_SDCARD_RW; \ + (x)->i_mode = ((x)->i_mode & S_IFMT) | 0775;\ } while (0) - /* OVERRIDE_CRED() and REVERT_CRED() * OVERRID_CRED() * backup original task->cred @@ -187,8 +193,6 @@ struct sdcardfs_mount_options { uid_t fs_low_uid; gid_t fs_low_gid; userid_t fs_user_id; - gid_t gid; - mode_t mask; bool multiuser; unsigned int reserved_mb; }; @@ -360,9 +364,10 @@ static inline void release_top(struct sdcardfs_inode_info *info) iput(info->top); } -static inline int get_gid(struct sdcardfs_inode_info *info) { - struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); - if (sb_info->options.gid == AID_SDCARD_RW) { +static inline int get_gid(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { + struct sdcardfs_vfsmount_options *opts = mnt->data; + + if (opts->gid == AID_SDCARD_RW) { /* As an optimization, certain trusted system components only run * as owner but operate across all users. Since we're now handing * out the sdcard_rw GID only to trusted apps, we're okay relaxing @@ -370,14 +375,15 @@ static inline int get_gid(struct sdcardfs_inode_info *info) { * assigned to app directories are still multiuser aware. */ return AID_SDCARD_RW; } else { - return multiuser_get_uid(info->userid, sb_info->options.gid); + return multiuser_get_uid(info->userid, opts->gid); } } -static inline int get_mode(struct sdcardfs_inode_info *info) { +static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { int owner_mode; int filtered_mode; - struct sdcardfs_sb_info * sb_info = SDCARDFS_SB(info->vfs_inode.i_sb); - int visible_mode = 0775 & ~sb_info->options.mask; + struct sdcardfs_vfsmount_options *opts = mnt->data; + int visible_mode = 0775 & ~opts->mask; + if (info->perm == PERM_PRE_ROOT) { /* Top of multi-user view should always be visible to ensure @@ -387,7 +393,7 @@ static inline int get_mode(struct sdcardfs_inode_info *info) { /* Block "other" access to Android directories, since only apps * belonging to a specific user should be in there; we still * leave +x open for the default view. */ - if (sb_info->options.gid == AID_SDCARD_RW) { + if (opts->gid == AID_SDCARD_RW) { visible_mode = visible_mode & ~0006; } else { visible_mode = visible_mode & ~0007; @@ -553,12 +559,17 @@ static inline int check_min_free_space(struct dentry *dentry, size_t size, int d return 1; } -/* Copies attrs and maintains sdcardfs managed attrs */ +/* + * Copies attrs and maintains sdcardfs managed attrs + * Since our permission check handles all special permissions, set those to be open + */ static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src) { - dest->i_mode = (src->i_mode & S_IFMT) | get_mode(SDCARDFS_I(dest)); + + dest->i_mode = (src->i_mode & S_IFMT) | S_IRWXU | S_IRWXG | + S_IROTH | S_IXOTH; /* 0775 */ dest->i_uid = SDCARDFS_I(dest)->d_uid; - dest->i_gid = get_gid(SDCARDFS_I(dest)); + dest->i_gid = AID_SDCARD_RW; dest->i_rdev = src->i_rdev; dest->i_atime = src->i_atime; dest->i_mtime = src->i_mtime; From 8f818a5edf1e4036edaa095811c6d84ea1d5838d Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 15 Nov 2016 13:35:18 -0800 Subject: [PATCH 037/281] sdcardfs: Change magic value Sdcardfs uses the same magic value as wrapfs. This should not be the case. As it is entirely in memory, the value can be changed without any loss of compatibility. Change-Id: I24200b805d5e6d32702638be99e47d50d7f2f746 Signed-off-by: Daniel Rosenberg --- include/uapi/linux/magic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index c932046eea12..17685df8637c 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -53,7 +53,7 @@ #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" #define ESDFS_SUPER_MAGIC 0xb550ca10 -#define SDCARDFS_SUPER_MAGIC 0xb550ca10 +#define SDCARDFS_SUPER_MAGIC 0x5dca2df5 #define SMB_SUPER_MAGIC 0x517B #define CGROUP_SUPER_MAGIC 0x27e0eb From 198dfc5154f061c877c2ea28788dd7d88c65083c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 27 Dec 2016 16:36:40 -0800 Subject: [PATCH 038/281] ANDROID: vfs: Missed updating truncate to truncate2 Bug: 30954918 Change-Id: I8163d3f86dd7aadb2ab3fc11816754f331986f05 Signed-off-by: Daniel Rosenberg --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index 17a1103790d4..827f0eb25bf3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2439,7 +2439,7 @@ static int handle_truncate(struct file *filp) if (!error) error = security_path_truncate(path); if (!error) { - error = do_truncate(path->dentry, 0, + error = do_truncate2(path->mnt, path->dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, filp); } From 31508734472759f3f6d23b0fc71a4464616c32bf Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 27 Dec 2016 12:36:29 -0800 Subject: [PATCH 039/281] ANDROID: sdcardfs: Fix locking issue with permision fix up Don't use lookup_one_len so we can grab the spinlock that protects d_subdirs. Bug: 30954918 Change-Id: I0c6a393252db7beb467e0d563739a3a14e1b5115 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 9e3e78229b41..d6aa3a34c250 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -141,32 +141,26 @@ void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) info = SDCARDFS_I(dentry->d_inode); if (needs_fixup(info->perm)) { - /* We need permission to fix up these values. - * Since permissions are based of of the mount, and - * we are accessing without the mount point, we create - * a fake mount with the permissions we will be using. - */ - struct vfsmount fakemnt; - struct sdcardfs_vfsmount_options opts; - fakemnt.data = &opts; - opts.gid = AID_SDCARD_RW; - opts.mask = 0; - mutex_lock(&dentry->d_inode->i_mutex); - child = lookup_one_len2(name, &fakemnt, dentry, len); - mutex_unlock(&dentry->d_inode->i_mutex); - if (!IS_ERR(child)) { - if (child->d_inode) { - get_derived_permission(dentry, child); - fixup_tmp_permissions(child->d_inode); - } - dput(child); + spin_lock(&dentry->d_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { + dget(child); + if (!strncasecmp(child->d_name.name, name, len)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fixup_tmp_permissions(child->d_inode); + dput(child); + break; + } + } + dput(child); } + spin_unlock(&dentry->d_lock); } else if (descendant_may_need_fixup(info->perm)) { - mutex_lock(&dentry->d_inode->i_mutex); + spin_lock(&dentry->d_lock); list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { fixup_perms_recursive(child, name, len); } - mutex_unlock(&dentry->d_inode->i_mutex); + spin_unlock(&dentry->d_lock); } dput(dentry); } From 550ab811e07eab5338fe88d2d062486df8ebd3a1 Mon Sep 17 00:00:00 2001 From: Agrawal Ashish Date: Thu, 29 Sep 2016 13:03:45 +0530 Subject: [PATCH 040/281] wlan: Fix GuestAP start up failure when PrimaryAP specifies [HT40] qcacld-2.0 to prima propagation This is caused by changing con_mode to STA_MODE regardless Guest AP status the fix is to set con_mode to STA only when non-SAP concurrency mode exists Change-Id: I35dfc15fce0c835ac8bb8e38e31c53011a64d83d CRs-fixed: 644492 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 6 +++++- drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 529c5b17f6a3..ff2f0b5e458d 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -97,6 +97,7 @@ #include "wlan_hdd_dev_pwr.h" #include "qwlan_version.h" #include "wlan_logging_sock_svc.h" +#include "wlan_hdd_misc.h" #define g_mode_rates_size (12) @@ -10586,7 +10587,10 @@ int __wlan_hdd_cfg80211_change_iface( struct wiphy *wiphy, pAdapter->device_mode = (type == NL80211_IFTYPE_STATION) ? WLAN_HDD_INFRA_STATION: WLAN_HDD_P2P_CLIENT; } - hdd_set_conparam(0); + + /* set con_mode to STA only when no SAP concurrency mode */ + if (!(hdd_get_concurrency_mode() & (VOS_SAP | VOS_P2P_GO))) + hdd_set_conparam(0); pHddCtx->change_iface = type; memset(&pAdapter->sessionCtx, 0, sizeof(pAdapter->sessionCtx)); hdd_set_station_ops( pAdapter->dev ); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 6f2ae14eec45..01c017a3113d 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -8222,7 +8222,9 @@ void hdd_deinit_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, tANI_U hdd_cleanup_actionframe(pHddCtx, pAdapter); hdd_unregister_hostapd(pAdapter, rtnl_held); - hdd_set_conparam( 0 ); + /* set con_mode to STA only when no SAP concurrency mode */ + if (!(hdd_get_concurrency_mode() & (VOS_SAP | VOS_P2P_GO))) + hdd_set_conparam(0); break; } From d56d3614dd58368e98de83a15edfe4e008825959 Mon Sep 17 00:00:00 2001 From: Agrawal Ashish Date: Thu, 29 Sep 2016 14:22:16 +0530 Subject: [PATCH 041/281] wlan: Cancel remain on channel without con mode At the time of driver exit, driver set con mode to VOS_STA_MODE. If Remain on channel is in progress, at the time of hdd_stop_adapter driver do cancel remain on channel. WLANSAP_CancelRemainOnChannel cancel remain on channel if con mode is VOS_STA_SAP_MODE which is not valid any more. Fix this issue by not constraining cancel remain on channel on basis of con mode. Change-Id: I0f14c92f24b0f1b38a46142175e0e6d31e8bb318 CRs-Fixed: 1072605 --- .../staging/prima/CORE/SAP/src/sapModule.c | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/drivers/staging/prima/CORE/SAP/src/sapModule.c b/drivers/staging/prima/CORE/SAP/src/sapModule.c index a1d90717c2d9..5376ce607894 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapModule.c +++ b/drivers/staging/prima/CORE/SAP/src/sapModule.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2211,36 +2211,31 @@ VOS_STATUS WLANSAP_CancelRemainOnChannel( v_PVOID_t pvosGCtx ) v_PVOID_t hHal = NULL; eHalStatus halStatus = eHAL_STATUS_FAILURE; - if( VOS_STA_SAP_MODE == vos_get_conparam ( ) ) + pSapCtx = VOS_GET_SAP_CB(pvosGCtx); + if (NULL == pSapCtx) { - pSapCtx = VOS_GET_SAP_CB( pvosGCtx ); - if (NULL == pSapCtx) - { - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid SAP pointer from pvosGCtx", __func__); - return VOS_STATUS_E_FAULT; - } - hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx); - if( ( NULL == hHal ) || ( eSAP_TRUE != pSapCtx->isSapSessionOpen ) ) - { - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", - __func__, hHal, pSapCtx->isSapSessionOpen ); - return VOS_STATUS_E_FAULT; - } - - halStatus = sme_CancelRemainOnChannel( hHal, pSapCtx->sessionId ); - - if( eHAL_STATUS_SUCCESS == halStatus ) - { - return VOS_STATUS_SUCCESS; - } + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pvosGCtx", __func__); + return VOS_STATUS_E_FAULT; + } + hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) + { + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen ); + return VOS_STATUS_E_FAULT; } - VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - "Failed to Cancel Remain on Channel"); + halStatus = sme_CancelRemainOnChannel(hHal, pSapCtx->sessionId); - return VOS_STATUS_E_FAULT; + if (eHAL_STATUS_SUCCESS != halStatus) + { + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + "Failed to Cancel Remain on Channel"); + return VOS_STATUS_E_FAULT; + } + return VOS_STATUS_SUCCESS; } /*========================================================================== From d4775f06a46f1521e5c0d9264f76bde855b08f08 Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Tue, 4 Oct 2016 20:26:22 +0530 Subject: [PATCH 042/281] wlan: Add SSR protect for ndo hard_start_xmit ops qcacld-2.0 to prima propagation. SSR should wait until ndo hard_start_xmit ops is completed. Change-Id: Ic3148cfb655f87d22c40bca7825809648c7b4b4a CRs-Fixed: 952660 --- .../CORE/HDD/src/wlan_hdd_softap_tx_rx.c | 21 +++++++++++++------ .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 13 ++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 6e02ec36b306..9c881f3b2992 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -314,10 +314,10 @@ v_U8_t hdd_softap_get_connected_sta(hdd_adapter_t *pHostapdAdapter) } /**============================================================================ - @brief hdd_softap_hard_start_xmit() - Function registered with the Linux OS for - transmitting packets. There are 2 versions of this function. One that uses - locked queue and other that uses lockless queues. Both have been retained to - do some performance testing + @brief __hdd_softap_hard_start_xmit() - Function registered with the Linux OS + for transmitting packets. There are 2 versions of this function. One that + uses locked queue and other that uses lockless queues. Both have been + retained to do some performance testing @param skb : [in] pointer to OS packet (sk_buff) @param dev : [in] pointer to Libra network device @@ -325,7 +325,7 @@ v_U8_t hdd_softap_get_connected_sta(hdd_adapter_t *pHostapdAdapter) @return : NET_XMIT_DROP if packets are dropped : NET_XMIT_SUCCESS if packet is enqueued succesfully ===========================================================================*/ -int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +int __hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_STATUS status; WLANTL_ACEnumType ac = WLANTL_AC_BE; @@ -562,6 +562,15 @@ int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return os_status; } +int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + vos_ssr_protect(__func__); + ret = __hdd_softap_hard_start_xmit(skb, dev); + vos_ssr_unprotect(__func__); + return ret; +} + /**============================================================================ @brief hdd_softap_sta_2_sta_xmit This function for Transmitting the frames when the traffic is between two stations. diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index 5404e1ad6769..06d5b60f6a4e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -793,7 +793,7 @@ void hdd_dump_dhcp_pkt(struct sk_buff *skb, int path) } /**============================================================================ - @brief hdd_hard_start_xmit() - Function registered with the Linux OS for + @brief __hdd_hard_start_xmit() - Function registered with the Linux OS for transmitting packets. There are 2 versions of this function. One that uses locked queue and other that uses lockless queues. Both have been retained to do some performance testing @@ -804,7 +804,7 @@ void hdd_dump_dhcp_pkt(struct sk_buff *skb, int path) @return : NET_XMIT_DROP if packets are dropped : NET_XMIT_SUCCESS if packet is enqueued succesfully ===========================================================================*/ -int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_STATUS status; WLANTL_ACEnumType qid, ac; @@ -1039,6 +1039,15 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + vos_ssr_protect(__func__); + ret = __hdd_hard_start_xmit(skb, dev); + vos_ssr_unprotect(__func__); + return ret; +} + /**============================================================================ @brief hdd_Ibss_GetStaId() - Get the StationID using the Peer Mac address From 5d170c7631626d1a8e2be89713003b5c12b58eb9 Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Mon, 10 Oct 2016 16:47:26 +0530 Subject: [PATCH 043/281] Wlan: Release 3.0.11.62 Release 3.0.11.62 Change-Id: I9ec0502d2e7779d07b95ac3ced06e6f38b8cf995 CRs-Fixed: 688141 --- drivers/staging/prima/CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index b885a07c01ea..ebfb7b7c8044 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -44,8 +44,8 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 61 +#define QWLAN_VERSION_BUILD 62 -#define QWLAN_VERSIONSTR "3.0.11.61" +#define QWLAN_VERSIONSTR "3.0.11.62" #endif /* QWLAN_VERSION_H */ From cdacb23c3b366be2c29d764959f40ccd8e0cb9af Mon Sep 17 00:00:00 2001 From: "Aggarwal, Nishank" Date: Mon, 10 Oct 2016 14:27:43 +0530 Subject: [PATCH 044/281] Prima: Change default value of gTDLSExternalControl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently wpa_supplicant.conf have enabled external control (“tdls_external_control=1”) & INI settings as Explicit Trigger by default. So, here is the mismatch of the wpa_supplicant.conf & INI setting which leads in failure of some test case manually as well these settings. Fix the issue by making the default value of gTDLSExternalControl same as wpa_supplicant.conf. Change-Id: Ifb187768ac387b6ae5f6bb3283efb48225e1e909 CRs-Fixed: 1074998 --- drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 5a51247fbc65..674fb9712ca4 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2025,7 +2025,7 @@ static __inline tANI_U32 defHddRateToDefCfgRate( tANI_U32 defRateIndex ) #define CFG_TDLS_EXTERNAL_CONTROL "gTDLSExternalControl" #define CFG_TDLS_EXTERNAL_CONTROL_MIN (0) #define CFG_TDLS_EXTERNAL_CONTROL_MAX (1) -#define CFG_TDLS_EXTERNAL_CONTROL_DEFAULT (0) +#define CFG_TDLS_EXTERNAL_CONTROL_DEFAULT (1) #define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE "gEnableTDLSOffChannel" #define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN (0) From 0d595d97e12b61fd38b85f220e53f001f9dff2df Mon Sep 17 00:00:00 2001 From: "Selvaraj, Sridhar" Date: Wed, 12 Oct 2016 12:34:08 +0530 Subject: [PATCH 045/281] wlan: Update qie_age->age to match the BSS age in the driver Lowi expects the timestamp of bss in units of 1/10 ms. In driver all bss related timestamp is in units of ms. Due to this when scan results are sent to lowi the scan age is high. To address this, send age in units of 1/10 ms. CRs-Fixed: 1075045 Change-Id: Id0a5794357a232105352c1b38d1ce404eabcc4fd --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index ff2f0b5e458d..0e5ed0dfd7ab 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -12225,7 +12225,13 @@ wlan_hdd_cfg80211_inform_bss_frame( hdd_adapter_t *pAdapter, qie_age->oui_2 = QCOM_OUI2; qie_age->oui_3 = QCOM_OUI3; qie_age->type = QCOM_VENDOR_IE_AGE_TYPE; - qie_age->age = vos_timer_get_system_time() - bss_desc->nReceivedTime; + /* Lowi expects the timestamp of bss in units of 1/10 ms. In driver all + * bss related timestamp is in units of ms. Due to this when scan results + * are sent to lowi the scan age is high.To address this, send age in units + * of 1/10 ms. + */ + qie_age->age = (vos_timer_get_system_time() - + bss_desc->nReceivedTime)/10; #endif memcpy(mgmt->u.probe_resp.variable, ie, ie_length); From 3dbfe579142df16b9bdfb3e206343f2aa7eadfb9 Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Wed, 12 Oct 2016 18:32:38 +0530 Subject: [PATCH 046/281] Wlan: Release 3.0.11.63 Release 3.0.11.63 Change-Id: I2c74b2f3e90dcbd7230e5878b032a5788af667d7 CRs-Fixed: 688141 --- drivers/staging/prima/CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index ebfb7b7c8044..3dbf2a91ede1 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -44,8 +44,8 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 62 +#define QWLAN_VERSION_BUILD 63 -#define QWLAN_VERSIONSTR "3.0.11.62" +#define QWLAN_VERSIONSTR "3.0.11.63" #endif /* QWLAN_VERSION_H */ From 999f1ec0c764b57d3d8b3b3667550c251852fa72 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Wed, 12 Oct 2016 13:32:32 +0530 Subject: [PATCH 047/281] wlan: Destroy the lock before freeing WDA context Currently mutex mgmt_pkt_lock destroy is called after freeing the WDA context. In this change fix is to destroy the lock before freeing the context in order to avoid possible system crash Change-Id: Iab55d2e64f80b2d40e0e080c9c80fcf5e1713cd4 CRs-Fixed: 1076848 --- drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 7563dc04ce9e..5fafafef450b 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -2645,6 +2645,9 @@ VOS_STATUS WDA_close(v_PVOID_t pVosContext) "VOS Event destroy failed - status = %d", status); status = VOS_STATUS_E_FAILURE; } + + vos_lock_destroy(&wdaContext->mgmt_pkt_lock); + /* free WDA context */ vstatus = vos_free_context(pVosContext, VOS_MODULE_ID_WDA, wdaContext); if ( !VOS_IS_STATUS_SUCCESS(vstatus) ) @@ -2653,7 +2656,7 @@ VOS_STATUS WDA_close(v_PVOID_t pVosContext) "error in WDA close " ); status = VOS_STATUS_E_FAILURE; } - vos_lock_destroy(&wdaContext->mgmt_pkt_lock); + return status; } /* From efc8aec43507495064d0e50b65d650947c7bee35 Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Thu, 13 Oct 2016 13:10:39 +0530 Subject: [PATCH 048/281] Wlan: Release 3.0.11.64 Release 3.0.11.64 Change-Id: Idc503c162c4c5b0036e4e2be655c11cfb2229cf4 CRs-Fixed: 688141 --- drivers/staging/prima/CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index 3dbf2a91ede1..9ecce9bd83fd 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -44,8 +44,8 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 63 +#define QWLAN_VERSION_BUILD 64 -#define QWLAN_VERSIONSTR "3.0.11.63" +#define QWLAN_VERSIONSTR "3.0.11.64" #endif /* QWLAN_VERSION_H */ From 127e1f362a9b7a1680db481da8232129b61ae9c2 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Wed, 12 Oct 2016 15:30:14 +0530 Subject: [PATCH 049/281] wlan: Fix suspicious dereference of pointer Dereference of 'roamSession' pointer before NULL check in csrScanningStateMsgProcessor(). Change-Id: If302bdbd70be3fc235158744aa1be2334f24edb2 CRs-Fixed: 1076882 --- .../prima/CORE/SME/src/csr/csrApiScan.c | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 7ae5f941580c..51a59c6b53a3 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -3253,36 +3253,42 @@ eHalStatus csrScanningStateMsgProcessor( tpAniSirGlobal pMac, void *pMsgBuf ) smsLog( pMac, LOG1, FL("eWNI_SME_DISCONNECT_DONE_IND RC:%d"), pDisConDoneInd->reasonCode); - if( CSR_IS_SESSION_VALID(pMac, pDisConDoneInd->sessionId)) + pSession = CSR_GET_SESSION(pMac,pDisConDoneInd->sessionId); + if (pSession) { - roamInfo.reasonCode = pDisConDoneInd->reasonCode; - roamInfo.statusCode = eSIR_SME_STA_DISASSOCIATED; - vos_mem_copy(roamInfo.peerMac, pDisConDoneInd->peerMacAddr, - sizeof(tSirMacAddr)); - status = csrRoamCallCallback(pMac, - pDisConDoneInd->sessionId, - &roamInfo, 0, - eCSR_ROAM_LOSTLINK, - eCSR_ROAM_RESULT_DISASSOC_IND); - pSession = CSR_GET_SESSION(pMac, + if( CSR_IS_SESSION_VALID(pMac, pDisConDoneInd->sessionId)) + { + roamInfo.reasonCode = pDisConDoneInd->reasonCode; + roamInfo.statusCode = eSIR_SME_STA_DISASSOCIATED; + vos_mem_copy(roamInfo.peerMac, pDisConDoneInd->peerMacAddr, + sizeof(tSirMacAddr)); + status = csrRoamCallCallback(pMac, + pDisConDoneInd->sessionId, + &roamInfo, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + /* + * Update the previous state if + * previous state was eCSR_ROAMING_STATE_JOINED + * as we are disconnected and + * currunt state is scanning + */ + if (!CSR_IS_INFRA_AP(&pSession->connectedProfile) + && (eCSR_ROAMING_STATE_IDLE != + pMac->roam.prev_state[pDisConDoneInd->sessionId])) + pMac->roam.prev_state[pDisConDoneInd->sessionId] = + eCSR_ROAMING_STATE_IDLE; + } + else + { + smsLog(pMac, LOGE, FL("Inactive session %d"), pDisConDoneInd->sessionId); - /* - * Update the previous state if - * previous state was eCSR_ROAMING_STATE_JOINED - * as we are disconnected and - * currunt state is scanning - */ - if (pSession && - !CSR_IS_INFRA_AP(&pSession->connectedProfile) - && (eCSR_ROAMING_STATE_IDLE != - pMac->roam.prev_state[pDisConDoneInd->sessionId])) - pMac->roam.prev_state[pDisConDoneInd->sessionId] = - eCSR_ROAMING_STATE_IDLE; + status = eHAL_STATUS_FAILURE; + } } else { - smsLog(pMac, LOGE, FL("Inactive session %d"), - pDisConDoneInd->sessionId); + smsLog(pMac, LOGE, FL("Invalid session")); status = eHAL_STATUS_FAILURE; } break; From b90bb51fcf42c107f9f4272d118e89da04d4a3dc Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Fri, 14 Oct 2016 16:18:26 +0530 Subject: [PATCH 050/281] Wlan: Release 3.0.11.65 Release 3.0.11.65 Change-Id: Icc3e05a8c842e36405677a2084a8ea3063934064 CRs-Fixed: 688141 --- drivers/staging/prima/CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index 9ecce9bd83fd..f93e43d3859e 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -44,8 +44,8 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 64 +#define QWLAN_VERSION_BUILD 65 -#define QWLAN_VERSIONSTR "3.0.11.64" +#define QWLAN_VERSIONSTR "3.0.11.65" #endif /* QWLAN_VERSION_H */ From def8f3113bdf06baa0b8fc4a90fd1ea890c1ee70 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Wed, 15 Jun 2016 12:51:57 +0530 Subject: [PATCH 051/281] wlan: Do not trigger del sta if it is already in progress qcacld-2.0 to prima propagation If SAP receive auth from an already connected STA, it post eWNI_SME_DISASSOC_IND msg to SME to delete the STA context and return. STA may try to send auth again as it didnt receive auth resp. Now many frames (probe req, auth etc) may get accumulated in PE message queue and unless PE queue is fully processed SME queue will not be processed and thus del sta will get delayed. This may again cause STA to send more auth req and every time MC thread process an auth req before the sta is deleted, eWNI_SME_DISASSOC_IND msg is posted in SME message queue. And if PE keeps on getting auth before the sta is deleted, SME queue will pile up leading to crash. To fix this do not trigger del sta if it is already in progress. Change-Id: Icff3778d35ef7ea646463fe49c4335e260e9e156 CRs-Fixed: 982329 --- drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c | 5 +++-- .../staging/prima/CORE/MAC/src/include/dphGlobal.h | 3 ++- .../prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c | 11 +++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c index 161779d76912..f73bcb8a0be9 100644 --- a/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c +++ b/drivers/staging/prima/CORE/MAC/src/dph/dphHashTable.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -295,6 +295,7 @@ tpDphHashNode dphInitStaState(tpAniSirGlobal pMac, tSirMacAddr staAddr, #ifdef WLAN_FEATURE_11W pStaDs->last_assoc_received_time = 0; #endif + pStaDs->sta_deletion_in_progress = false; pStaDs->valid = 1; return pStaDs; } @@ -443,7 +444,7 @@ tSirRetStatus dphDeleteHashEntry(tpAniSirGlobal pMac, tSirMacAddr staAddr, tANI_ #ifdef WLAN_FEATURE_11W ptr->last_assoc_received_time = 0; #endif - + ptr->sta_deletion_in_progress = false; ptr->next = 0; } else diff --git a/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h b/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h index 5a6b27876b10..3dac65ae0c14 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h +++ b/drivers/staging/prima/CORE/MAC/src/include/dphGlobal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -638,6 +638,7 @@ typedef struct sDphHashNode */ tANI_U8 isDisassocDeauthInProgress; + bool sta_deletion_in_progress; struct sDphHashNode *next; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c index 6632497d652e..36b7a68a8b12 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c @@ -305,13 +305,16 @@ limTriggerSTAdeletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPESession pse } if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || - (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)|| + pStaDs->sta_deletion_in_progress) { /* Already in the process of deleting context for the peer */ - PELOGE(limLog(pMac, LOGE, - FL("Deletion is in progress for peer:%pM"), pStaDs->staAddr);) + limLog(pMac, LOG1, + FL("Deletion is in progress (%d) for peer:%p in mlmState %d"), + pStaDs->sta_deletion_in_progress, pStaDs->staAddr, + pStaDs->mlmStaContext.mlmState); return; } - + pStaDs->sta_deletion_in_progress = true; pStaDs->mlmStaContext.disassocReason = eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; pStaDs->mlmStaContext.cleanupTrigger = eLIM_LINK_MONITORING_DISASSOC; From e2a5396ef433af9879c4cc73a12a2896ddd93adf Mon Sep 17 00:00:00 2001 From: kaliu Date: Fri, 25 Mar 2016 11:12:12 +0800 Subject: [PATCH 052/281] wlan: Del sta if auth frame is received while connecting qcacld-2.0 to prima propagation It's a fix for sns issue. Set DUT as sap, ref client sends assoc req to DUT and as part of this frame processing lim does ADD_STA and posts eWNI_SME_ASSOC_IND to sme layer. Before SME layer sends eWNI_SME_ASSOC_CNF, DUT receives auth frame which triggers deauth. In this case lim layer will delete ref client's related info, but wma layer doesn't get any notification. To fix this lim has to notify wma to do DEL_STA for that peer. Change-Id: Id4aae51aae3fb68e752d09793ad3bce17665fc2e CRs-Fixed: 979687 --- drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c index 44c301ed75ec..5af2f978bc60 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c @@ -690,13 +690,13 @@ limCleanupRxPath(tpAniSirGlobal pMac, tpDphHashNode pStaDs,tpPESession psessionE * There is no context at Polaris to delete. * Release our assigned AID back to the free pool */ - if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) || + if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) || (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE)) - { + { + limDelSta(pMac, pStaDs, false, psessionEntry); limReleasePeerIdx(pMac, pStaDs->assocId, psessionEntry); } limDeleteDphHashEntry(pMac, pStaDs->staAddr, pStaDs->assocId,psessionEntry); - return retCode; } } From 811fb568929a6f86d956c96b54f32d2da3e63372 Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Wed, 19 Oct 2016 15:16:09 +0530 Subject: [PATCH 053/281] Prima: Add config_ini configure BMISS & BWAIT Add ini params to configure & reduce the consecutive BMISS threshold when gEnableModulatedDTIM/gMaxLIModulatedDTIM are big, so that to compensate the side effect of BH failure. Change-Id: Id68e4bf5110e021b3c59b69898732f66eb298f32 CRs-Fixed: 1072240 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 13 ++++++ .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 31 ++++++++++++++ drivers/staging/prima/CORE/MAC/inc/wniCfg.h | 16 ++++++-- .../prima/CORE/MAC/src/cfg/cfgProcMsg.c | 10 +++++ .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 41 +++++++++++++++++-- drivers/staging/prima/riva/inc/wlan_hal_cfg.h | 6 ++- 6 files changed, 109 insertions(+), 8 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 674fb9712ca4..3092de7e30a7 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2042,6 +2042,17 @@ static __inline tANI_U32 defHddRateToDefCfgRate( tANI_U32 defRateIndex ) #define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_MAX (1) #define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_DEFAULT (0) +/* Enable/Disable Consecutive Beacon miss */ +#define CFG_ENABLE_CONSECUTIVE_BMISS_NAME "gEnableConcBmiss" +#define CFG_ENABLE_CONSECUTIVE_BMISS_MIN ( 2 ) +#define CFG_ENABLE_CONSECUTIVE_BMISS_MAX ( 10 ) +#define CFG_ENABLE_CONSECUTIVE_BMISS_DEFAULT ( 5 ) + +/* Enable/Disable units of beacon wait time */ +#define CFG_ENABLE_UNITS_BEACON_WAIT_NAME "gEnableUnitBwait" +#define CFG_ENABLE_UNITS_BEACON_WAIT_MIN ( 2 ) +#define CFG_ENABLE_UNITS_BEACON_WAIT_MAX ( 10 ) +#define CFG_ENABLE_UNITS_BEACON_WAIT_DEFAULT ( 2 ) /* if gEnableTDLSScan * 0: Same as gEnableTDLSScanCoexistence ; driver will do disconnect if @@ -3252,6 +3263,8 @@ typedef struct v_BOOL_t fEnableActiveModeOffload; #endif v_U32_t enableLpwrImgTransition; + v_U8_t enable_conc_bmiss; + v_U8_t enable_units_bwait; v_U8_t scanAgingTimeout; v_BOOL_t enableTxLdpc; v_U8_t disableLDPCWithTxbfAP; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index a14cca2c216e..faaede9f4a9c 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -2636,6 +2636,21 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, CFG_ENABLE_LPWR_IMG_TRANSITION_MAX ), + REG_VARIABLE( CFG_ENABLE_CONSECUTIVE_BMISS_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_conc_bmiss, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CONSECUTIVE_BMISS_DEFAULT, + CFG_ENABLE_CONSECUTIVE_BMISS_MIN, + CFG_ENABLE_CONSECUTIVE_BMISS_MAX ), + + REG_VARIABLE( CFG_ENABLE_UNITS_BEACON_WAIT_NAME, WLAN_PARAM_Integer, + hdd_config_t, enable_units_bwait, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_UNITS_BEACON_WAIT_DEFAULT, + CFG_ENABLE_UNITS_BEACON_WAIT_MIN, + CFG_ENABLE_UNITS_BEACON_WAIT_MAX ), + + #ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE REG_VARIABLE( CFG_ACTIVEMODE_OFFLOAD_ENABLE, WLAN_PARAM_Integer, hdd_config_t, fEnableActiveModeOffload, @@ -4103,6 +4118,8 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [ignoreDynamicDtimInP2pMode] Value = [%u] ",pHddCtx->cfg_ini->ignoreDynamicDtimInP2pMode); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enableRxSTBC] Value = [%u] ",pHddCtx->cfg_ini->enableRxSTBC); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableLpwrImgTransition] Value = [%u] ",pHddCtx->cfg_ini->enableLpwrImgTransition); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enable_conc_bmiss] Value = [%u] ",pHddCtx->cfg_ini->enable_conc_bmiss); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [enable_units_bwait] Value = [%u] ",pHddCtx->cfg_ini->enable_units_bwait); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableSSR] Value = [%u] ",pHddCtx->cfg_ini->enableSSR); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gEnableVhtFor24GHzBand] Value = [%u] ",pHddCtx->cfg_ini->enableVhtFor24GHzBand); @@ -5395,6 +5412,20 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) fStatus = FALSE; hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_LPWR_IMG_TRANSITION to CCM"); } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_CONC_BMISS, + pConfig->enable_conc_bmiss, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_CONC_BMISS to CCM"); + } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_UNITS_BWAIT, + pConfig->enable_units_bwait, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_UNITS_BWAIT to CCM"); + } if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, pConfig->enableMCCAdaptiveScheduler, NULL, eANI_BOOLEAN_FALSE)==eHAL_STATUS_FAILURE) diff --git a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h index 5c2f926b8df1..81d3e7d10c08 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniCfg.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniCfg.h @@ -391,7 +391,9 @@ enum { WNI_CFG_EXT_SCAN_CONC_MODE, WNI_CFG_ENABLE_MAC_ADDR_SPOOFING, WNI_CFG_DISABLE_BAR_WAKE_UP_HOST, - WNI_CFG_SAR_BOFFSET_SET_CORRECTION + WNI_CFG_SAR_BOFFSET_SET_CORRECTION, + WNI_CFG_ENABLE_UNITS_BWAIT, + WNI_CFG_ENABLE_CONC_BMISS }; /* @@ -1657,6 +1659,14 @@ enum { #define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX 1 #define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF 0 +#define WNI_CFG_ENABLE_CONC_BMISS_STAMIN 2 +#define WNI_CFG_ENABLE_CONC_BMISS_STAMAX 10 +#define WNI_CFG_ENABLE_CONC_BMISS_STADEF 5 + +#define WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN 2 +#define WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX 10 +#define WNI_CFG_ENABLE_UNITS_BWAIT_STADEF 2 + #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN 0 #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX 1 #define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF 0 @@ -1917,8 +1927,8 @@ enum { #define WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT 0 -#define CFG_PARAM_MAX_NUM 358 -#define CFG_STA_IBUF_MAX_SIZE 292 +#define CFG_PARAM_MAX_NUM 360 +#define CFG_STA_IBUF_MAX_SIZE 294 #define CFG_STA_SBUF_MAX_SIZE 3389 #define CFG_STA_MAGIC_DWORD 0xbeefbeef diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c index ab7ed153e1fe..630d53acf34d 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1385,6 +1385,16 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF}, + {WNI_CFG_ENABLE_CONC_BMISS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_CONC_BMISS_STAMIN, + WNI_CFG_ENABLE_CONC_BMISS_STAMAX, + WNI_CFG_ENABLE_CONC_BMISS_STADEF}, + {WNI_CFG_ENABLE_UNITS_BWAIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX, + WNI_CFG_ENABLE_UNITS_BWAIT_STADEF}, {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 5fafafef450b..8a4af1ac56d4 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -1689,9 +1689,40 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, "Failed to get value for WNI_CFG_ENABLE_LPWR_IMG_TRANSITION"); goto handle_failure; } - - tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct - + sizeof(tHalCfg) + tlvStruct->length) ; + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + + /* QWLAN_HAL_CFG_CONS_BCNMISS_COUNT */ + tlvStruct->type = QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_CONC_BMISS, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_CONC_BMISS"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + + /* QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME */ + tlvStruct->type = QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_UNITS_BWAIT, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_UNITS_BWAIT"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + #ifdef WLAN_SOFTAP_VSTA_FEATURE tlvStruct->type = QWLAN_HAL_CFG_MAX_ASSOC_LIMIT; tlvStruct->length = sizeof(tANI_U32); @@ -5305,6 +5336,10 @@ static inline v_U8_t WDA_ConvertWniCfgIdToHALCfgId(v_U32_t wniCfgId) return QWLAN_HAL_CFG_ENABLE_CLOSE_LOOP; case WNI_CFG_ENABLE_LPWR_IMG_TRANSITION: return QWLAN_HAL_CFG_ENABLE_LPWR_IMG_TRANSITION; + case WNI_CFG_ENABLE_CONC_BMISS: + return QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; + case WNI_CFG_ENABLE_UNITS_BWAIT: + return QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; case WNI_CFG_ENABLE_RTSCTS_HTVHT: return QWLAN_HAL_CFG_ENABLE_RTSCTS_HTVHT; default: diff --git a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h index 9540b3c2fb84..115c120d5d75 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_cfg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_cfg.h @@ -276,11 +276,13 @@ #define QWLAN_HAL_CFG_EXT_SCAN_CONC_MODE 218 #define QWLAN_HAL_CFG_BAR_WAKEUP_HOST_DISABLE 219 #define QWLAN_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE 220 +#define QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME 221 +#define QWLAN_HAL_CFG_CONS_BCNMISS_COUNT 222 -#define QWLAN_HAL_CFG_MAX_PARAMS 221 +#define QWLAN_HAL_CFG_MAX_PARAMS 223 /* Total number of Integer CFGs. This is used while allocating the memory for TLV */ -#define QWLAN_HAL_CFG_INTEGER_PARAM 221 +#define QWLAN_HAL_CFG_INTEGER_PARAM 223 /*------------------------------------------------------------------------- Configuration Parameter min, max, defaults From e9ee0683b9b34eaf900c9aaa5a027745e1ce8720 Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Wed, 19 Oct 2016 15:22:05 +0530 Subject: [PATCH 054/281] Wlan: Release 3.0.11.66 Release 3.0.11.66 Change-Id: Ib81f1c8d51f0718a831b0f4368f106468ea294f5 CRs-Fixed: 688141 --- drivers/staging/prima/CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index f93e43d3859e..d49b49462d91 100644 --- a/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h @@ -44,8 +44,8 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_PATCH 11 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 65 +#define QWLAN_VERSION_BUILD 66 -#define QWLAN_VERSIONSTR "3.0.11.65" +#define QWLAN_VERSIONSTR "3.0.11.66" #endif /* QWLAN_VERSION_H */ From 8dc3a856e23dbd52ae6e95369be29e0b513f3da2 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Fri, 21 Oct 2016 11:22:33 +0530 Subject: [PATCH 055/281] wlan: Use offset to get the ie length from bss descriptor The length of bss descriptor is calculated using offset of IE field but when lim tries to get the IE length it doesnt use the offset which results in incorrect IE length. To fix use offset to get the ie length from bss descriptor Change-Id: I7abbde83aea1e0a1cfcd7bdb1a184158f75f2455 CRs-Fixed: 1082001 --- .../prima/CORE/MAC/src/pe/lim/limAssocUtils.c | 2 +- .../staging/prima/CORE/MAC/src/pe/lim/limFT.c | 8 ++-- .../MAC/src/pe/lim/limProcessAssocRspFrame.c | 8 ++-- .../MAC/src/pe/lim/limProcessMlmRspMessages.c | 18 +++++---- .../MAC/src/pe/lim/limProcessSmeReqMessages.c | 40 +++++++++---------- .../MAC/src/pe/lim/limSendSmeRspMessages.c | 6 +-- .../CORE/MAC/src/pe/lim/limSerDesUtils.c | 2 +- .../prima/CORE/MAC/src/pe/lim/limTypes.h | 36 +---------------- .../prima/CORE/SAP/src/sapApiLinkCntl.c | 3 +- .../staging/prima/CORE/SAP/src/sapChSelect.c | 4 +- .../prima/CORE/SME/src/csr/csrApiScan.c | 8 ++-- .../staging/prima/CORE/SME/src/csr/csrUtil.c | 4 +- 12 files changed, 52 insertions(+), 87 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c index 5af2f978bc60..188f2e578688 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c @@ -4028,7 +4028,7 @@ tSirRetStatus limStaSendAddBssPreAssoc( tpAniSirGlobal pMac, tANI_U8 updateEntry limExtractApCapabilities( pMac, (tANI_U8 *) bssDescription->ieFields, - limGetIElenFromBssDescription( bssDescription ), + GET_IE_LEN_IN_BSS(bssDescription->length), pBeaconStruct ); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c index 8058e13799d3..6a51b3387772 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c @@ -440,7 +440,7 @@ tSirRetStatus limFTPrepareAddBssReq( tpAniSirGlobal pMac, limExtractApCapabilities( pMac, (tANI_U8 *) bssDescription->ieFields, - limGetIElenFromBssDescription( bssDescription ), pBeaconStruct ); + GET_IE_LEN_IN_BSS(bssDescription->length), pBeaconStruct); if (pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, pftSessionEntry); @@ -734,7 +734,7 @@ tpPESession limFillFTSession(tpAniSirGlobal pMac, limExtractApCapabilities( pMac, (tANI_U8 *) pbssDescription->ieFields, - limGetIElenFromBssDescription( pbssDescription ), + GET_IE_LEN_IN_BSS(pbssDescription->length), pBeaconStruct ); pftSessionEntry->rateSet.numRates = pBeaconStruct->supportedRates.numRates; @@ -856,8 +856,8 @@ tpPESession limFillFTSession(tpAniSirGlobal pMac, regMax = cfgGetRegulatoryMaxTransmitPower( pMac, pftSessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, (tANI_U8 *) pbssDescription->ieFields, - limGetIElenFromBssDescription(pbssDescription), + limExtractApCapability(pMac, (tANI_U8 *) pbssDescription->ieFields, + GET_IE_LEN_IN_BSS(pbssDescription->length), &pftSessionEntry->limCurrentBssQosCaps, &pftSessionEntry->limCurrentBssPropCap, ¤tBssUapsd , &localPowerConstraint, psessionEntry); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c index 6a257c88a595..d08df5b6355c 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessAssocRspFrame.c @@ -877,10 +877,10 @@ limProcessAssocRspFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U8 sub limUpdateAssocStaDatas(pMac, pStaDs, pAssocRsp,psessionEntry); // Extract the AP capabilities from the beacon that was received earlier // TODO - Watch out for an error response! - limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimJoinReq->bssDescription ), - pBeaconStruct ); + limExtractApCapabilities(pMac, + (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS(psessionEntry->pLimJoinReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c index 20b68ad57790..1393690c5147 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c @@ -4820,9 +4820,11 @@ limHandleDelBssInReAssocContext(tpAniSirGlobal pMac, tpDphHashNode pStaDs,tpPESe limUpdateAssocStaDatas(pMac, pStaDs, assocRsp,psessionEntry); limUpdateReAssocGlobals(pMac, assocRsp,psessionEntry); limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimReAssocReq->bssDescription ), - pBeaconStruct ); + (tANI_U8 *) + psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); if(pBeaconStruct->erpPresent) { @@ -4996,10 +4998,12 @@ limHandleAddBssInReAssocContext(tpAniSirGlobal pMac, tpDphHashNode pStaDs, tpPES assocRsp = (tpSirAssocRsp)psessionEntry->limAssocResponseData; limUpdateAssocStaDatas(pMac, pStaDs, assocRsp, psessionEntry); limUpdateReAssocGlobals(pMac, assocRsp, psessionEntry); - limExtractApCapabilities( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( &psessionEntry->pLimReAssocReq->bssDescription ), - pBeaconStruct ); + limExtractApCapabilities(pMac, + (tANI_U8 *) + psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + pBeaconStruct); if(pMac->lim.gLimProtectionControl != WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) limDecideStaProtectionOnAssoc(pMac, pBeaconStruct, psessionEntry); diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c index 9f7f4b871e2a..72840abcec44 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c @@ -1863,9 +1863,7 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->bWPSAssociation = pSmeJoinReq->bWPSAssociation; /* Store vendor specfic IE for CISCO AP */ - ieLen = (pSmeJoinReq->bssDescription.length + - sizeof( pSmeJoinReq->bssDescription.length ) - - GET_FIELD_OFFSET( tSirBssDescription, ieFields )); + ieLen = GET_IE_LEN_IN_BSS(pSmeJoinReq->bssDescription.length); vendorIE = limGetVendorIEOuiPtr(pMac, SIR_MAC_CISCO_OUI, SIR_MAC_CISCO_OUI_SIZE, @@ -2070,15 +2068,14 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) regMax = cfgGetRegulatoryMaxTransmitPower( pMac, psessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, - (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, - limGetIElenFromBssDescription(&psessionEntry->pLimJoinReq->bssDescription), - &psessionEntry->limCurrentBssQosCaps, - &psessionEntry->limCurrentBssPropCap, - &pMac->lim.gLimCurrentBssUapsd //TBD-RAJESH make gLimCurrentBssUapsd this session specific - , &localPowerConstraint, - psessionEntry - ); + limExtractApCapability(pMac, + (tANI_U8 *) psessionEntry->pLimJoinReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS(psessionEntry->pLimJoinReq->bssDescription.length), + &psessionEntry->limCurrentBssQosCaps, + &psessionEntry->limCurrentBssPropCap, + &pMac->lim.gLimCurrentBssUapsd, + &localPowerConstraint, + psessionEntry); #ifdef FEATURE_WLAN_ESE psessionEntry->maxTxPower = limGetMaxTxPower(regMax, localPowerConstraint, pMac->roam.configParam.nTxPowerCap); @@ -2352,16 +2349,15 @@ __limProcessSmeReassocReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) psessionEntry->pLimReAssocReq->bssDescription.capabilityInfo; regMax = cfgGetRegulatoryMaxTransmitPower( pMac, psessionEntry->currentOperChannel ); localPowerConstraint = regMax; - limExtractApCapability( pMac, - (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, - limGetIElenFromBssDescription( - &psessionEntry->pLimReAssocReq->bssDescription), - &psessionEntry->limReassocBssQosCaps, - &psessionEntry->limReassocBssPropCap, - &pMac->lim.gLimCurrentBssUapsd //TBD-RAJESH make gLimReassocBssUapsd session specific - , &localPowerConstraint, - psessionEntry - ); + limExtractApCapability(pMac, + (tANI_U8 *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, + GET_IE_LEN_IN_BSS( + psessionEntry->pLimReAssocReq->bssDescription.length), + &psessionEntry->limReassocBssQosCaps, + &psessionEntry->limReassocBssPropCap, + &pMac->lim.gLimCurrentBssUapsd, + &localPowerConstraint, + psessionEntry); psessionEntry->maxTxPower = VOS_MIN( regMax, (localPowerConstraint) ); if (!psessionEntry->maxTxPower) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c index 618c71fc6583..85c577b1dd58 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendSmeRspMessages.c @@ -657,9 +657,9 @@ limSendSmeStartBssRsp(tpAniSirGlobal pMac, //subtracting size of length indicator itself and size of pointer to ieFields - pSirSmeRsp->bssDescription.length = sizeof(tSirBssDescription) - - sizeof(tANI_U16) - sizeof(tANI_U32) + - ieLen; + pSirSmeRsp->bssDescription.length = + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)) + - sizeof(pSirSmeRsp->bssDescription.length) + ieLen; //This is the size of the message, subtracting the size of the pointer to ieFields size += ieLen - sizeof(tANI_U32); } diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c index e879a07bfd3c..3fb524bf1ea4 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSerDesUtils.c @@ -404,7 +404,7 @@ limCopyBssDescription(tpAniSirGlobal pMac, tANI_U8 *pBuf, tSirBssDescription *pB len++; vos_mem_copy( pBuf, (tANI_U8 *) &(pBssDescription->ieFields), - limGetIElenFromBssDescription(pBssDescription)); + GET_IE_LEN_IN_BSS(pBssDescription->length)); return (len + sizeof(tANI_U16)); } /*** end limCopyBssDescription() ***/ diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h index 35137b854b02..a375494faa07 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1002,40 +1002,6 @@ limGetCurrentScanChannel(tpAniSirGlobal pMac) return (*(pChanNum + pMac->lim.gLimCurrentScanChannelId)); } /*** end limGetCurrentScanChannel() ***/ - - -/** - * limGetIElenFromBssDescription() - * - *FUNCTION: - * This function is called in various places to get IE length - * from tSirBssDescription structure - * number being scanned. - * - *PARAMS: - * - *LOGIC: - * - *ASSUMPTIONS: - * NA - * - *NOTE: - * NA - * - * @param pBssDescr - * @return Total IE length - */ - -static inline tANI_U16 -limGetIElenFromBssDescription(tpSirBssDescription pBssDescr) -{ - if (!pBssDescr) - return 0; - - return ((tANI_U16) (pBssDescr->length + sizeof(tANI_U16) + - sizeof(tANI_U32) - sizeof(tSirBssDescription))); -} /*** end limGetIElenFromBssDescription() ***/ - /** * limSendBeaconInd() * diff --git a/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c b/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c index 9d4d19316ef2..a0234c68eac7 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c +++ b/drivers/staging/prima/CORE/SAP/src/sapApiLinkCntl.c @@ -865,8 +865,7 @@ eHalStatus sapCheck40Mhz24G(tHalHandle halHandle, ptSapContext psapCtx, if ((pScanResult->BssDescriptor.ieFields != NULL)) { - ieLen = (pScanResult->BssDescriptor.length + sizeof(tANI_U16)); - ieLen += (sizeof(tANI_U32) - sizeof(tSirBssDescription)); + ieLen = GET_IE_LEN_IN_BSS(pScanResult->BssDescriptor.length); vos_mem_set((tANI_U8 *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); diff --git a/drivers/staging/prima/CORE/SAP/src/sapChSelect.c b/drivers/staging/prima/CORE/SAP/src/sapChSelect.c index aa4c7462c605..dda7fa195618 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapChSelect.c +++ b/drivers/staging/prima/CORE/SAP/src/sapChSelect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1372,7 +1372,7 @@ void sapComputeSpectWeight( tSapChSelSpectInfo* pSpectInfoParams, if (pScanResult->BssDescriptor.ieFields != NULL) { - ieLen = (pScanResult->BssDescriptor.length + sizeof(tANI_U16) + sizeof(tANI_U32) - sizeof(tSirBssDescription)); + ieLen = GET_IE_LEN_IN_BSS(pScanResult->BssDescriptor.length); vos_mem_set((tANI_U8 *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); if ((sirParseBeaconIE(pMac, pBeaconStruct,(tANI_U8 *)( pScanResult->BssDescriptor.ieFields), ieLen)) == eSIR_SUCCESS) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 51a59c6b53a3..7a5829e6e40f 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -3325,8 +3325,8 @@ void csrCheckNSaveWscIe(tpAniSirGlobal pMac, tSirBssDescription *pNewBssDescr, t (0 == pNewBssDescr->WscIeLen)) { idx = 0; - len = pOldBssDescr->length - sizeof(tSirBssDescription) + - sizeof(tANI_U16) + sizeof(tANI_U32) - DOT11F_IE_WSCPROBERES_MIN_LEN - 2; + len = GET_IE_LEN_IN_BSS(pOldBssDescr->length) + - DOT11F_IE_WSCPROBERES_MIN_LEN - 2; pbIe = (tANI_U8 *)pOldBssDescr->ieFields; //Save WPS IE if it exists pNewBssDescr->WscIeLen = 0; @@ -9013,8 +9013,8 @@ eHalStatus csrScanSavePreferredNetworkFound(tpAniSirGlobal pMac, * that holds the next BSS description */ pBssDescr->length = (tANI_U16)( - sizeof(tSirBssDescription) - sizeof(tANI_U16) - - sizeof(tANI_U32) + uLen); + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)) + - sizeof(pBssDescr->length) + uLen); if (pParsedFrame->dsParamsPresent) { pBssDescr->channelId = pParsedFrame->channelNumber; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c b/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c index 3e2732f81a4a..52687fe9c68e 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrUtil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2064,7 +2064,7 @@ eHalStatus csrParseBssDescriptionIEs(tHalHandle hHal, tSirBssDescription *pBssDe { eHalStatus status = eHAL_STATUS_FAILURE; tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); - int ieLen = (int)(pBssDesc->length + sizeof( pBssDesc->length ) - GET_FIELD_OFFSET( tSirBssDescription, ieFields )); + int ieLen = (int)GET_IE_LEN_IN_BSS(pBssDesc->length); if(ieLen > 0 && pIEStruct) { From 31d014b7584ce1bd36b288dc55befbbeb296433e Mon Sep 17 00:00:00 2001 From: "Padma, Santhosh Kumar" Date: Mon, 24 Oct 2016 18:13:11 +0530 Subject: [PATCH 056/281] prima: Fix oem data response length OEM_DATA_RSP_SIZE is maximum data response length exchanged between driver and firmware. Currently OEM_DATA_RSP_SIZE is used always in copying data from SMD. But firmware may not send OEM_DATA_RSP_SIZE amount of data. This can result in reading from unauthorized location and thus can lead to crash. Fix this by getting appropriate length of oem data response and use that length in copying. Change-Id: I2011aca892e7702ad1991ec0a4c8f7be15d1dedf CRs-Fixed: 1081497 --- drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 46bd75813eab..535237aeed06 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -18779,8 +18779,12 @@ WDI_ProcessStartOemDataRsp return WDI_STATUS_E_FAILURE; } + wpalMemoryZero(wdiOemDataRspParams->oemDataRsp, OEM_DATA_RSP_SIZE); + /* Populate WDI structure members */ - wpalMemoryCopy(wdiOemDataRspParams->oemDataRsp, halStartOemDataRspParams->oemDataRsp, OEM_DATA_RSP_SIZE); + wpalMemoryCopy(wdiOemDataRspParams->oemDataRsp, + halStartOemDataRspParams->oemDataRsp, + pEventData->uEventDataSize); /*Notify UMAC*/ wdiOemDataRspCb(wdiOemDataRspParams, pWDICtx->pRspCBUserData); From b5c40da848b3d54ae81e87b2f478ec4debef68d7 Mon Sep 17 00:00:00 2001 From: "Agrawal, Ashish" Date: Wed, 26 Oct 2016 12:41:13 +0530 Subject: [PATCH 057/281] wlan: check for SSR in wlan_hdd_set_filter function wlan_hdd_set_filter is not checking if SSR is in progress or not. fix this by protecting wlan_hdd_set_filter with SSR check Change-Id: I58eb632b9ed100dd73b27983035f6f459bb34852 CRs-Fixed: 1080754 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index d181ed768449..0de3d0d6258a 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -8970,6 +8970,12 @@ int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, __func__ ); return 0; } + if (pHddCtx->isLogpInProgress) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + return -EBUSY; + } /* Debug display of request components. */ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Packet Filter Request : FA %d params %d", __func__, pRequest->filterAction, pRequest->numParams); From d911f4551dd2ba1fc272017299f90626d2f2e0fc Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Wed, 19 Oct 2016 20:26:42 +0530 Subject: [PATCH 058/281] prima: Acquire read lock before accessing the address list qcacld2.0 to prima propagation WLAN host driver access the inet6_dev address list without acquiring the read lock, if the kernel network stack deletes the address while driver is accessing the list, it can lead to referencing already freed address by the driver. Hence, fix is to take the read lock before accessing the address list. Change-Id: I934e9f2039f3ab8540e439b9e8a87efced98807c CRs-Fixed: 1048897 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index a6a9e89daf5d..202a5595a11d 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -816,6 +816,7 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) in6_dev = __in6_dev_get(pAdapter->dev); if (NULL != in6_dev) { + read_lock_bh(&in6_dev->lock); list_for_each(p, &in6_dev->addr_list) { if (i >= slot_index) @@ -856,6 +857,7 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) i++; } } + read_unlock_bh(&in6_dev->lock); vos_mem_zero(&offLoadRequest, sizeof(offLoadRequest)); for (i =0; i < slot_index; i++) From 681e761515eabbfb21635bef94f72c20988c8ba1 Mon Sep 17 00:00:00 2001 From: c_manjee Date: Wed, 26 Oct 2016 11:36:55 +0530 Subject: [PATCH 059/281] prima: Validate Adapter in scan done callback From static analysis it is found that adapter is not being validated before being accessed.This can lead to null pointer exception during corner cases. Do NULL check for Adapter before accessing. Change-Id: I8abec02d3cf546c1e7790c3f7dfaff9ac373ff6d CRs-Fixed: 1082363 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 0e5ed0dfd7ab..961162c4f9d0 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -12694,6 +12694,11 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, ENTER(); + if (!pAdapter || pAdapter->magic != WLAN_HDD_ADAPTER_MAGIC || + !pAdapter->dev) { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Adapter is not valid")); + return 0; + } pHddCtx = WLAN_HDD_GET_CTX(pAdapter); if (NULL == pHddCtx) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD context is Null")); From c94bd361181acf42c4df1dd20e5b51d794da9478 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 25 Oct 2016 14:15:20 +0530 Subject: [PATCH 060/281] wlan: Cancel scan request before issuing connect request Scan should be aborted before sending join request since DUT needs to be at home channel during connection. Add changes to abort current scans before try to connect to AP. Change-Id: Ifa445a6e0898789ec6b57b446936565405c51328 CRs-Fixed: 1081496 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 961162c4f9d0..d775ae16a1db 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -14767,6 +14767,12 @@ static int __wlan_hdd_cfg80211_connect( struct wiphy *wiphy, channel = req->channel->hw_value; else channel = 0; + + /* Abort if any scan is going on */ + status = wlan_hdd_scan_abort(pAdapter); + if (0 != status) + hddLog(VOS_TRACE_LEVEL_ERROR, FL("scan abort failed")); + status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, req->ssid_len, req->bssid, bssid_hint, channel); From 44e5e168814bc9caa1624dc12f5c14242a1b1667 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 25 Oct 2016 13:03:20 +0530 Subject: [PATCH 061/281] wlan: Add callback handler for SSID scan request SSID scan is done as part of join request, if scan aborted it should be informed to HDD otherwise HDD may have incorrect connection state. Add changes to inform scan status using callback handler. Change-Id: Ia2b064a78554a2c0260e0f87609b3e274698f7a4 CRs-Fixed: 1081496 --- .../prima/CORE/SME/src/csr/csrApiScan.c | 59 ++++++++++++++++--- .../prima/CORE/SME/src/csr/csrInsideApi.h | 15 ++++- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 7a5829e6e40f..1ccbf5ef5ac1 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -7023,14 +7023,17 @@ void csrScanCallCallback(tpAniSirGlobal pMac, tSmeCmd *pCommand, eCsrScanStatus if(pCommand->u.scanCmd.callback) { if (pCommand->u.scanCmd.abortScanIndication){ - smsLog( pMac, LOG1, FL("scanDone due to abort")); - scanStatus = eCSR_SCAN_ABORT; + if ((pCommand->u.scanCmd.reason != eCsrScanForSsid) || + (scanStatus != eCSR_SCAN_SUCCESS)) { + smsLog( pMac, LOG1, FL("scanDone due to abort")); + scanStatus = eCSR_SCAN_ABORT; + } } -// sme_ReleaseGlobalLock( &pMac->sme ); pCommand->u.scanCmd.callback(pMac, pCommand->u.scanCmd.pContext, pCommand->u.scanCmd.scanID, scanStatus); -// sme_AcquireGlobalLock( &pMac->sme ); } else { - smsLog( pMac, LOG2, "%s:%d - Callback NULL!!!", __func__, __LINE__); + smsLog(pMac, LOG2, + FL("Callback NULL cmd reason %d"), + pCommand->u.scanCmd.reason); } } @@ -7919,6 +7922,37 @@ static void csr_scan_request_set_chan_time(tpAniSirGlobal pMac, } #endif +/** + * csr_ssid_scan_done_callback() - Callback to indicate + * scan is done for ssid scan + * @halHandle: handle to hal + * @context: SSID scan context + * @scanId: Scan id for the scheduled scan + * @status: scan done status + * + * Return - eHalStatus + */ +static eHalStatus csr_ssid_scan_done_callback(tHalHandle halHandle, + void *context, + tANI_U32 scanId, + eCsrScanStatus status) +{ + struct csr_scan_for_ssid_context *scan_context = + (struct csr_scan_for_ssid_context *)context; + + if (NULL == scan_context) + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("scan for ssid context not found")); + + if (eCSR_SCAN_ABORT == status) + csrRoamCallCallback(scan_context->pMac, scan_context->sessionId, + NULL, scan_context->roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + vos_mem_free(scan_context); + return eHAL_STATUS_SUCCESS; +} + //This function is usually used for BSSs that suppresses SSID so the profile //shall have one and only one SSID eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfile *pProfile, tANI_U32 roamId, tANI_BOOLEAN notify) @@ -7928,6 +7962,7 @@ eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi tANI_U8 bAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; tANI_U8 index = 0; tANI_U32 numSsid = pProfile->SSIDs.numOfSSIDs; + struct csr_scan_for_ssid_context *context; smsLog(pMac, LOG2, FL("called")); //For WDS, we use the index 0. There must be at least one in there @@ -7955,13 +7990,23 @@ eHalStatus csrScanForSSID(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi { status = csrRoamCopyProfile(pMac, pScanCmd->u.scanCmd.pToRoamProfile, pProfile); } + context = vos_mem_malloc(sizeof(*context)); + if (NULL == context) + { + smsLog(pMac, LOGE, + "Failed to allocate memory for ssid scan context"); + status = eHAL_STATUS_FAILED_ALLOC; + } if(!HAL_STATUS_SUCCESS(status)) break; + context->pMac = pMac; + context->sessionId = sessionId; + context->roamId = roamId; pScanCmd->u.scanCmd.roamId = roamId; pScanCmd->command = eSmeCommandScan; pScanCmd->sessionId = (tANI_U8)sessionId; - pScanCmd->u.scanCmd.callback = NULL; - pScanCmd->u.scanCmd.pContext = NULL; + pScanCmd->u.scanCmd.callback = csr_ssid_scan_done_callback; + pScanCmd->u.scanCmd.pContext = context; pScanCmd->u.scanCmd.reason = eCsrScanForSsid;//Need to check: might need a new reason for SSID scan for LFR during multisession with p2p pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID++; //let it wrap around vos_mem_set(&pScanCmd->u.scanCmd.u.scanRequest, sizeof(tCsrScanRequest), 0); diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h index b297d3d45e58..9bd0e51ff4c6 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h +++ b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h @@ -223,8 +223,19 @@ typedef struct tListElem *pCurEntry; }tScanResultList; - - +/** + * csr_scan_for_ssid_context() - Callback context for SSID scan + * + * @pMac: pMac handle + * @sessionId: scan session id + * @roamId: roam Id + */ +struct csr_scan_for_ssid_context +{ + tpAniSirGlobal pMac; + tANI_U32 sessionId; + tANI_U32 roamId; +}; #define CSR_IS_ROAM_REASON( pCmd, reason ) ( (reason) == (pCmd)->roamCmd.roamReason ) #define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2)) From 8d5d8205a6e27b98d09c1a211d6a31a2dfc5bf92 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Thu, 27 Oct 2016 12:13:30 +0530 Subject: [PATCH 062/281] wlan: Generate bug report if scan rejected by driver Currently SSR got triggered if scan rejected by driver due to connection states. Add driver changes to generate bug report before SSR triggers if current session id, rejected reason matches with last rejected sesssion id, reason and time delta between current time and rejected timestamp is greater than 5 mins. Change-Id: Ic64a6fd443104b291b5b7f6cda3bfbe8273c671a CRs-Fixed: 1081489 --- .../prima/CORE/HDD/inc/wlan_hdd_assoc.h | 1 - .../prima/CORE/HDD/inc/wlan_hdd_main.h | 24 ++++++- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 63 ++++++++++++++++--- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 4 +- .../prima/CORE/HDD/src/wlan_hdd_main.c | 4 +- .../staging/prima/CORE/HDD/src/wlan_hdd_p2p.c | 3 +- drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 4 +- drivers/staging/prima/CORE/VOSS/src/vos_api.c | 3 +- 8 files changed, 88 insertions(+), 18 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_assoc.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_assoc.h index 652f1ab56c8a..81947302e55d 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_assoc.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_assoc.h @@ -47,7 +47,6 @@ /* Timeout in ms for peer info request commpletion */ #define IBSS_PEER_INFO_REQ_TIMOEUT 1000 #endif -#define SCAN_ABORT_THRESHOLD 35 typedef enum { /** Not associated in Infra or participating in an IBSS / Ad-hoc network.*/ diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 9f773184e585..2a7defc8ee66 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -236,6 +236,7 @@ typedef v_U8_t tWlanHddMacAddr[HDD_MAC_ADDR_LEN]; #define MIN(a, b) (a > b ? b : a) #endif +#define SCAN_REJECT_THRESHOLD_TIME 300000 /* Time is in msec, equal to 5 mins */ #define WLAN_WAIT_TIME_EXTSCAN 1000 @@ -954,6 +955,22 @@ typedef enum #endif +/* + * @eHDD_SCAN_REJECT_DEFAULT: default value + * @eHDD_CONNECTION_IN_PROGRESS: connection is in progress + * @eHDD_REASSOC_IN_PROGRESS: reassociation is in progress + * @eHDD_EAPOL_IN_PROGRESS: STa/drivers/staging/prima/P2P-CLI is in middle of EAPOL/WPS exchange + * @eHDD_SAP_EAPOL_IN_PROGRESS: SAP/P2P-GO is in middle of EAPOL/WPS exchange + */ +typedef enum +{ + eHDD_SCAN_REJECT_DEFAULT = 0, + eHDD_CONNECTION_IN_PROGRESS, + eHDD_REASSOC_IN_PROGRESS, + eHDD_EAPOL_IN_PROGRESS, + eHDD_SAP_EAPOL_IN_PROGRESS, +} scan_reject_states; + typedef struct { struct completion completion; @@ -1605,7 +1622,9 @@ struct hdd_context_s vos_timer_t tdls_source_timer; v_U64_t extscan_start_time_since_boot; - v_U8_t con_scan_abort_cnt; + v_U8_t last_scan_reject_session_id; + scan_reject_states last_scan_reject_reason; + v_TIME_t last_scan_reject_timestamp; }; typedef enum { @@ -1766,7 +1785,8 @@ v_BOOL_t hdd_is_valid_mac_address(const tANI_U8* pMacAddr); VOS_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx); VOS_STATUS hdd_is_any_session_connected(hdd_context_t *pHddCtx); void hdd_ipv4_notifier_work_queue(struct work_struct *work); -v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx); +v_BOOL_t hdd_isConnectionInProgress(hdd_context_t *pHddCtx, v_U8_t *session_id, + scan_reject_states *reason); void hdd_set_ibss_ops(hdd_adapter_t *pAdapter); #ifdef WLAN_FEATURE_PACKET_FILTERING int wlan_hdd_setIPv6Filter(hdd_context_t *pHddCtx, tANI_U8 filterType, tANI_U8 sessionId); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index d775ae16a1db..b49f4c4b7944 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -12879,7 +12879,8 @@ static eHalStatus hdd_cfg80211_scan_done_callback(tHalHandle halHandle, * Go through each adapter and check if Connection is in progress * */ -v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) +v_BOOL_t hdd_isConnectionInProgress(hdd_context_t *pHddCtx, v_U8_t *session_id, + scan_reject_states *reason) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; hdd_station_ctx_t *pHddStaCtx = NULL; @@ -12909,6 +12910,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %p(%d) Connection is in progress", __func__, WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), pAdapter->sessionId); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_CONNECTION_IN_PROGRESS; + } return VOS_TRUE; } if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && @@ -12917,6 +12923,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %p(%d) Reassociation is in progress", __func__, WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), pAdapter->sessionId); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_REASSOC_IN_PROGRESS; + } return VOS_TRUE; } if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || @@ -12932,6 +12943,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) "%s: client " MAC_ADDRESS_STR " is in the middle of WPS/EAPOL exchange.", __func__, MAC_ADDR_ARRAY(staMac)); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_EAPOL_IN_PROGRESS; + } return VOS_TRUE; } } @@ -12957,6 +12973,11 @@ v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx) "%s: client " MAC_ADDRESS_STR " of SoftAP/P2P-GO is in the " "middle of WPS/EAPOL exchange.", __func__, MAC_ADDR_ARRAY(staMac)); + if (session_id && reason) + { + *session_id = pAdapter->sessionId; + *reason = eHDD_SAP_EAPOL_IN_PROGRESS; + } return VOS_TRUE; } } @@ -13013,6 +13034,8 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, int ret = 0; v_U8_t *pWpsIe=NULL; bool is_p2p_scan = false; + v_U8_t curr_session_id; + scan_reject_states curr_reason; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) struct net_device *dev = NULL; @@ -13119,20 +13142,40 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, FL("BTCoex Mode operation in progress")); return -EBUSY; } - if (hdd_isConnectionInProgress(pHddCtx)) + if (hdd_isConnectionInProgress(pHddCtx, &curr_session_id, &curr_reason)) { hddLog(VOS_TRACE_LEVEL_ERROR, FL("Scan not allowed")); - if (SCAN_ABORT_THRESHOLD < pHddCtx->con_scan_abort_cnt) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - FL("Triggering SSR, SSR status = %d"), status); - vos_wlanRestart(); + if (pHddCtx->last_scan_reject_session_id != curr_session_id || + pHddCtx->last_scan_reject_reason != curr_reason || + !pHddCtx->last_scan_reject_timestamp) + { + pHddCtx->last_scan_reject_session_id = curr_session_id; + pHddCtx->last_scan_reject_reason = curr_reason; + pHddCtx->last_scan_reject_timestamp = vos_timer_get_system_time(); + } + else { + if ((vos_timer_get_system_time() - + pHddCtx->last_scan_reject_timestamp) >= + SCAN_REJECT_THRESHOLD_TIME) + { + pHddCtx->last_scan_reject_timestamp = 0; + if (pHddCtx->cfg_ini->enableFatalEvent) + vos_fatal_event_logs_req(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + FALSE, FALSE); + else + { + hddLog(LOGE, FL("Triggering SSR")); + vos_wlanRestart(); + } + } } - else - pHddCtx->con_scan_abort_cnt++; - return -EBUSY; } - pHddCtx->con_scan_abort_cnt = 0; + pHddCtx->last_scan_reject_timestamp = 0; + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; vos_mem_zero( &scanRequest, sizeof(scanRequest)); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index 202a5595a11d..1607774db2ce 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2307,7 +2307,9 @@ VOS_STATUS hdd_wlan_re_init(void) /* Restart all adapters */ hdd_start_all_adapters(pHddCtx); - pHddCtx->con_scan_abort_cnt = 0; + pHddCtx->last_scan_reject_session_id = 0; + pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_timestamp = 0; pHddCtx->hdd_mcastbcast_filter_set = FALSE; pHddCtx->btCoexModeSet = FALSE; hdd_register_mcast_bcast_filter(pHddCtx); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 01c017a3113d..08481e71c9bc 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -11520,7 +11520,9 @@ int hdd_wlan_startup(struct device *dev ) ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx; pHddCtx->parent_dev = dev; - pHddCtx->con_scan_abort_cnt = 0; + pHddCtx->last_scan_reject_session_id = 0; + pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_timestamp = 0; init_completion(&pHddCtx->full_pwr_comp_var); init_completion(&pHddCtx->standby_comp_var); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c index 90f5d73cc9c3..2e4852ce1147 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_p2p.c @@ -778,7 +778,8 @@ static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, return -EBUSY; } - if(hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx)) + if(hdd_isConnectionInProgress((hdd_context_t *)pAdapter->pHddCtx, NULL, + NULL)) { hddLog( LOGE, "%s: Connection is in progress", __func__); diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index 3cb282ec34d2..99039cd3cc4a 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -182,7 +182,8 @@ enum log_event_indicator { * @WLAN_LOG_REASON_EXIT_IMPS_BMPS_FAIL: Exit IMPS/BMPS rsp failure * @WLAN_LOG_REASON_HDD_TIME_OUT: Wait for event Timeout in HDD layer * @WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT:Management frame timedout - @WLAN_LOG_REASON_SME_OUT_OF_CMD_BUFL sme out of cmd buffer + * @WLAN_LOG_REASON_SME_OUT_OF_CMD_BUFL sme out of cmd buffer + * @WLAN_LOG_REASON_SCAN_NOT_ALLOWED: scan not allowed due to connection states * This enum contains the different reason codes for bug report */ enum log_event_host_reason_code { @@ -204,6 +205,7 @@ enum log_event_host_reason_code { WLAN_LOG_REASON_HDD_TIME_OUT, WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT, WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, }; /*------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index 747851ff770c..d46888eea0a2 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -1748,7 +1748,8 @@ void vos_send_fatal_event_done(void) */ if ((WLAN_LOG_INDICATOR_HOST_DRIVER == indicator) && (WLAN_LOG_REASON_SME_COMMAND_STUCK == reason_code || - WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF == reason_code)) + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF == reason_code || + WLAN_LOG_REASON_SCAN_NOT_ALLOWED == reason_code)) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "Do SSR for reason_code=%d", reason_code); From 327b1f5281c3dbafeb36a3b67ed0a6e1b83c8bc5 Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Wed, 26 Oct 2016 15:54:47 +0530 Subject: [PATCH 063/281] wlan: Fix compilation error Compilation error happening with WLAN_FEATURE_RMC disabled. Remove ifdef WLAN_FEATURE_RMC macro in wlan_hdd_main.h. CRs-Fixed: 1082451 Change-Id: I390c65ffc8fb534c801831f879053eb9664f0738 --- drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 2a7defc8ee66..03ce521eef05 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -667,7 +667,6 @@ typedef enum{ HDD_SSR_DISABLED, }e_hdd_ssr_required; -#ifdef WLAN_FEATURE_RMC /*--------------------------------------------------------------------------- hdd_ibss_peer_info_params_t ---------------------------------------------------------------------------*/ @@ -726,7 +725,6 @@ typedef struct /** Peer Info parameters */ hdd_ibss_peer_info_params_t ibssPeerList[HDD_MAX_NUM_IBSS_STA]; }hdd_ibss_peer_info_t; -#endif struct hdd_station_ctx { @@ -755,9 +753,7 @@ struct hdd_station_ctx /*Save the wep/wpa-none keys*/ tCsrRoamSetKey ibss_enc_key; -#ifdef WLAN_FEATURE_RMC hdd_ibss_peer_info_t ibss_peer_info; -#endif v_BOOL_t hdd_ReassocScenario; From 5ff4f39226c5facc9682ddc435bc14f80f4cfa7f Mon Sep 17 00:00:00 2001 From: Ravi Kumar Bokka Date: Thu, 27 Oct 2016 13:52:34 +0530 Subject: [PATCH 064/281] wlan: Send number of radios in radio stats wifi-hal expects number of radios as part of radio stats. So send the number of radios supported as 1 in radio stats. Change-Id: I088ae47ed75d610ed8d1f6eaae30b569885254e9 CRs-Fixed: 1082999 --- drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h | 6 ++++++ drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h index b673717dc9c9..f236369aa5c3 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -102,6 +102,12 @@ #define MAX_CHANNEL NUM_2_4GHZ_CHANNELS + NUM_5GHZ_CHANNELS +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +/* Number of Radios */ +#define NUM_RADIOS 0x1 +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + typedef struct { u8 element_id; u8 len; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index b49f4c4b7944..7522bb713e17 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -1440,12 +1440,14 @@ static v_VOID_t hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, hddLog(VOS_TRACE_LEVEL_INFO, "LL_STATS_RADIO" + " number of radios = %u" " radio is %d onTime is %u " " txTime is %u rxTime is %u " " onTimeScan is %u onTimeNbd is %u " " onTimeEXTScan is %u onTimeRoamScan is %u " " onTimePnoScan is %u onTimeHs20 is %u " " numChannels is %u", + NUM_RADIOS, pWifiRadioStat->radio, pWifiRadioStat->onTime, pWifiRadioStat->txTime, pWifiRadioStat->rxTime, pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd, @@ -1478,6 +1480,9 @@ static v_VOID_t hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, pWifiRadioStat->radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + NUM_RADIOS) || nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, pWifiRadioStat->onTime) || From d63eb13a531f3e47376613b010ebe303651d6885 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Tue, 8 Nov 2016 12:01:07 +0530 Subject: [PATCH 065/281] prima: Initialize thread stuck timer after driver loading is done Presently, thread stuck timer starts before initializing timer work queue(along with work queue spinlock and linked-list are initialized), which is scheduled on timer expire, leading to crash if timer expires before work queue is initialized. Also, as thread stuck timer callback won't be processed during driver loading, initializing thread stuck timer once done with driver loading. Change-Id: Ibb289f93481ae39585a6c2c56e8eefca267d6330 CRs-Fixed: 1086969 --- .../prima/CORE/HDD/src/wlan_hdd_main.c | 7 ++++ drivers/staging/prima/CORE/VOSS/src/vos_api.c | 2 - .../staging/prima/CORE/VOSS/src/vos_sched.c | 40 ++++++++++++------- .../staging/prima/CORE/VOSS/src/vos_sched.h | 4 +- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 08481e71c9bc..80d85593befa 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -12297,6 +12297,13 @@ int hdd_wlan_startup(struct device *dev ) // Initialize the restart logic wlan_hdd_restart_init(pHddCtx); + if (pHddCtx->cfg_ini->fIsLogpEnabled) { + vos_wdthread_init_timer_work(vos_process_wd_timer); + /* Initialize the timer to detect thread stuck issues */ + vos_thread_stuck_timer_init( + &((VosContextType*)pVosContext)->vosWatchdog); + } + //Register the traffic monitor timer now if ( pHddCtx->cfg_ini->dynSplitscan) { diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index d46888eea0a2..7d347fbdaa4a 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -269,8 +269,6 @@ VOS_STATUS vos_open( v_CONTEXT_t *pVosContext, void *devHandle ) /* Initialize the timer module */ vos_timer_module_init(); - vos_wdthread_init_timer_work(vos_process_wd_timer); - /* Initialize the probe event */ if (vos_event_init(&gpVosContext->ProbeEvent) != VOS_STATUS_SUCCESS) { diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c index 95f551bd12dd..0dafd2531e1a 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c @@ -752,6 +752,31 @@ static void vos_wd_detect_thread_stuck_cb(void *priv) } } +/** + * vos_thread_stuck_timer_init - Initialize thread stuck timer + * + * @pWdContext: watchdog context. + * + * Return: void + */ +void vos_thread_stuck_timer_init(pVosWatchdogContext pWdContext) +{ + if (vos_timer_init_deferrable(&pWdContext->threadStuckTimer, + VOS_TIMER_TYPE_SW, + vos_wd_detect_thread_stuck_cb, NULL)) + hddLog(LOGE, FL("Unable to initialize thread stuck timer")); + else + { + if (VOS_STATUS_SUCCESS != + vos_timer_start(&pWdContext->threadStuckTimer, + THREAD_STUCK_TIMER_VAL)) + hddLog(LOGE, FL("Unable to start thread stuck timer")); + else + hddLog(LOG1, FL("Successfully started thread stuck timer")); + } + +} + /** * wlan_logging_reset_thread_stuck_count()- Callback to * probe msg sent to Threads. @@ -827,21 +852,6 @@ VosWDThread #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)) daemonize("WD_Thread"); #endif - /* Initialize the timer to detect thread stuck issues */ - if (vos_timer_init_deferrable(&pWdContext->threadStuckTimer, - VOS_TIMER_TYPE_SW, - vos_wd_detect_thread_stuck_cb, NULL)) { - hddLog(LOGE, FL("Unable to initialize thread stuck timer")); - } - else - { - if (VOS_STATUS_SUCCESS != - vos_timer_start(&pWdContext->threadStuckTimer, - THREAD_STUCK_TIMER_VAL)) - hddLog(LOGE, FL("Unable to start thread stuck timer")); - else - hddLog(LOG1, FL("Successfully started thread stuck timer")); - } /* ** Ack back to the context from which the Watchdog thread has been diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h index e73cf39aa808..5082757578f6 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -376,6 +376,8 @@ typedef struct _VosContextType int vos_sched_is_tx_thread(int threadID); int vos_sched_is_rx_thread(int threadID); int vos_sched_is_mc_thread(int threadID); +void vos_thread_stuck_timer_init(pVosWatchdogContext pWdContext); + /*--------------------------------------------------------------------------- \brief vos_sched_open() - initialize the vOSS Scheduler From 412d2ad3315ee163e06c6c37d369f15d24ce094a Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Tue, 8 Nov 2016 15:17:23 +0530 Subject: [PATCH 066/281] prima: On thread stuck timer expire, call timer callback Presently, thread stuck timer callback is called only if userdata is valid, from WD timer worker thread. But while initializing timer, userdata is set to NULL. Hence timer callback isn't called. Don't validate userdata in WD timer worker thread, before calling thread stuck timer expire. Change-Id: I1bca1d931e42941deab7c5fdbaee88fa2ec75f35 CRs-Fixed: 1087146 --- drivers/staging/prima/CORE/VOSS/src/vos_timer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_timer.c b/drivers/staging/prima/CORE/VOSS/src/vos_timer.c index 2ce724e584bf..44e8681f2609 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_timer.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_timer.c @@ -1066,10 +1066,8 @@ static void __vos_process_wd_timer(void) node); list_del(pos); spin_unlock(&vos_global_context->wdthread_work_lock); - if ((NULL != wdthread_timer_work->callback) && - (NULL != wdthread_timer_work->userData)) { + if (NULL != wdthread_timer_work->callback) wdthread_timer_work->callback(wdthread_timer_work->userData); - } vos_mem_free(wdthread_timer_work); spin_lock(&vos_global_context->wdthread_work_lock); } From b2cde06d35e19ebb8db25cdde87616eba997a1cb Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Fri, 25 Nov 2016 14:40:11 +0530 Subject: [PATCH 067/281] wlan: Fix Sequencing in config TLV Due to improper sequencing, data sent to firmware gets corrupted, fix this issue with proper sequencing of the commands. Change-Id: I71d2b304a4b8df863c61d884ba907bd37a5e41b8 CRs-Fixed: 1093499 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 4 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 28 ++++----- .../prima/CORE/MAC/src/cfg/cfgProcMsg.c | 20 +++---- .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 60 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 3092de7e30a7..0e8764293e57 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -3263,8 +3263,8 @@ typedef struct v_BOOL_t fEnableActiveModeOffload; #endif v_U32_t enableLpwrImgTransition; - v_U8_t enable_conc_bmiss; - v_U8_t enable_units_bwait; + v_U32_t enable_conc_bmiss; + v_U32_t enable_units_bwait; v_U8_t scanAgingTimeout; v_BOOL_t enableTxLdpc; v_U8_t disableLDPCWithTxbfAP; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index faaede9f4a9c..6094d8686496 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -5412,20 +5412,6 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) fStatus = FALSE; hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_LPWR_IMG_TRANSITION to CCM"); } - if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_CONC_BMISS, - pConfig->enable_conc_bmiss, NULL, eANI_BOOLEAN_FALSE) - ==eHAL_STATUS_FAILURE) - { - fStatus = FALSE; - hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_CONC_BMISS to CCM"); - } - if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_UNITS_BWAIT, - pConfig->enable_units_bwait, NULL, eANI_BOOLEAN_FALSE) - ==eHAL_STATUS_FAILURE) - { - fStatus = FALSE; - hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_UNITS_BWAIT to CCM"); - } if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, pConfig->enableMCCAdaptiveScheduler, NULL, eANI_BOOLEAN_FALSE)==eHAL_STATUS_FAILURE) @@ -5895,6 +5881,20 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) fStatus = FALSE; hddLog(LOGE, "Could not pass on WNI_CFG_DISABLE_BAR_WAKE_UP_HOST to CCM"); } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_CONC_BMISS, + pConfig->enable_conc_bmiss, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_CONC_BMISS to CCM"); + } + if(ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_UNITS_BWAIT, + pConfig->enable_units_bwait, NULL, eANI_BOOLEAN_FALSE) + ==eHAL_STATUS_FAILURE) + { + fStatus = FALSE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_UNITS_BWAIT to CCM"); + } if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_SAR_BOFFSET_SET_CORRECTION, pConfig->boffset_correction_enable, diff --git a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c index 630d53acf34d..39a53fc1b367 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1385,16 +1385,6 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF}, - {WNI_CFG_ENABLE_CONC_BMISS, - CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, - WNI_CFG_ENABLE_CONC_BMISS_STAMIN, - WNI_CFG_ENABLE_CONC_BMISS_STAMAX, - WNI_CFG_ENABLE_CONC_BMISS_STADEF}, - {WNI_CFG_ENABLE_UNITS_BWAIT, - CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, - WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN, - WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX, - WNI_CFG_ENABLE_UNITS_BWAIT_STADEF}, {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, @@ -1713,6 +1703,16 @@ tAniSirCgStatic cfgStatic[CFG_PARAM_MAX_NUM] = WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MIN, WNI_CFG_SAR_BOFFSET_SET_CORRECTION_MAX, WNI_CFG_SAR_BOFFSET_SET_CORRECTION_DEFAULT}, + {WNI_CFG_ENABLE_CONC_BMISS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_CONC_BMISS_STAMIN, + WNI_CFG_ENABLE_CONC_BMISS_STAMAX, + WNI_CFG_ENABLE_CONC_BMISS_STADEF}, + {WNI_CFG_ENABLE_UNITS_BWAIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMIN, + WNI_CFG_ENABLE_UNITS_BWAIT_STAMAX, + WNI_CFG_ENABLE_UNITS_BWAIT_STADEF}, }; tAniSirCfgStaticString cfgStaticString[CFG_MAX_STATIC_STRING] = diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 8a4af1ac56d4..345f8cd9664d 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -1693,36 +1693,6 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length); - /* QWLAN_HAL_CFG_CONS_BCNMISS_COUNT */ - tlvStruct->type = QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; - tlvStruct->length = sizeof(tANI_U32); - configDataValue = (tANI_U32 *)(tlvStruct + 1); - if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_CONC_BMISS, configDataValue) - != eSIR_SUCCESS) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_ENABLE_CONC_BMISS"); - goto handle_failure; - } - - tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct - + sizeof(tHalCfg) + tlvStruct->length); - - /* QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME */ - tlvStruct->type = QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; - tlvStruct->length = sizeof(tANI_U32); - configDataValue = (tANI_U32 *)(tlvStruct + 1); - if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_UNITS_BWAIT, configDataValue) - != eSIR_SUCCESS) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Failed to get value for WNI_CFG_ENABLE_UNITS_BWAIT"); - goto handle_failure; - } - - tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct - + sizeof(tHalCfg) + tlvStruct->length); - #ifdef WLAN_SOFTAP_VSTA_FEATURE tlvStruct->type = QWLAN_HAL_CFG_MAX_ASSOC_LIMIT; tlvStruct->length = sizeof(tANI_U32); @@ -2427,6 +2397,36 @@ VOS_STATUS WDA_prepareConfigTLV(v_PVOID_t pVosContext, tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + sizeof(tHalCfg) + tlvStruct->length) ; + /* QWLAN_HAL_CFG_CONS_BCNMISS_COUNT */ + tlvStruct->type = QWLAN_HAL_CFG_CONS_BCNMISS_COUNT; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_CONC_BMISS, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_CONC_BMISS"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + + /* QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME */ + tlvStruct->type = QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + if(wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_UNITS_BWAIT, configDataValue) + != eSIR_SUCCESS) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_ENABLE_UNITS_BWAIT"); + goto handle_failure; + } + + tlvStruct = (tHalCfg *)( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length); + wdiStartParams->usConfigBufferLen = (tANI_U8 *)tlvStruct - tlvStructStart ; #ifdef WLAN_DEBUG { From 7f498fc4e21a3608d2d9bc0e6c1bd8952a39cd5c Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Mon, 21 Nov 2016 12:02:44 +0530 Subject: [PATCH 068/281] wlan: Avoid dereferencing suspicious pointer In csr_ssid_scan_done_callback(), Return failure status if scan_context is NULL to avoid dereferencing NULL pointer. Change-Id: Ic679e99cef9869aa5349b1b1892b8ed065286e62 CRs-Fixed: 1092464 --- drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 1ccbf5ef5ac1..e31b94b4a290 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -7940,9 +7940,11 @@ static eHalStatus csr_ssid_scan_done_callback(tHalHandle halHandle, struct csr_scan_for_ssid_context *scan_context = (struct csr_scan_for_ssid_context *)context; - if (NULL == scan_context) + if (NULL == scan_context) { VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, FL("scan for ssid context not found")); + return eHAL_STATUS_FAILURE; + } if (eCSR_SCAN_ABORT == status) csrRoamCallCallback(scan_context->pMac, scan_context->sessionId, From fe24c62fea0ef2a31fc839b8471b1687d4ff5c48 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Fri, 25 Nov 2016 15:16:51 +0530 Subject: [PATCH 069/281] prima: FTM: During unload, don't do LIM de-initialization Presently, LIM de-initialization is happening during FTM unload though LIM is not initialized during FTM load. In FTM mode, during driver unload don't de-initialize LIM module. Change-Id: Icd2ce2681587f92e5d8311f2f69c79dc4127be9a CRs-Fixed: 1094268 --- .../prima/CORE/SYS/legacy/src/system/src/macInitApi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/system/src/macInitApi.c b/drivers/staging/prima/CORE/SYS/legacy/src/system/src/macInitApi.c index ced0a4826416..60a167877ae2 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/system/src/macInitApi.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/system/src/macInitApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -154,7 +154,11 @@ tSirRetStatus macStop(tHalHandle hHal, tHalStopType stopType) { tANI_U8 i; tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; - peStop(pMac); + + //In FTM mode, peStart is not called during driver load. + if (pMac->gDriverType != eDRIVER_TYPE_MFG) + peStop(pMac); + cfgCleanup( pMac ); // need to free memory if not called in reset context. // in reset context this memory will be freed by HDD. From cb72aef2c86f8021c2aa40c705ff9705dfda28d2 Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Tue, 22 Nov 2016 16:16:26 +0530 Subject: [PATCH 070/281] prima: Validate station id In function __hdd_softap_hard_start_xmit, station id is not validated with max station count, this might lead to a buffer overflow situation for array aStaInfo in SapCtx. Validate station id with max sta count. CRs-Fixed: 1093122 Change-Id: If9f59c5a7b76845bb7783a96453e595b5afa4f30 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 9c881f3b2992..58d1c9a4be89 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -386,7 +386,7 @@ int __hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) else { STAId = hdd_sta_id_find_from_mac_addr(pAdapter, pDestMacAddress); - if (STAId == HDD_WLAN_INVALID_STA_ID) + if (STAId == HDD_WLAN_INVALID_STA_ID || STAId >= WLAN_MAX_STA_COUNT) { VOS_TRACE( VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_WARN, "%s: Failed to find right station", __func__); From 09d188660c9c4322561dfd5bff35bbec69032f9f Mon Sep 17 00:00:00 2001 From: Manjeet Singh Date: Mon, 21 Nov 2016 18:21:17 +0530 Subject: [PATCH 071/281] prima: Validate pkt buffer size In function parse_Bufferforpkt, pkt data index is not validated. This may lead to a buffer overflow if the incoming buffer is too large. Validate packet buffer length with the total allowed pkt buffer size. Change-Id: I9b9ffa592cbe3a0d87af3cbbef3608bc59e01cfc CRs-Fixed: 1092599 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 0de3d0d6258a..86a09a317eee 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -4025,6 +4025,9 @@ static void parse_Bufferforpkt(tSirpkt80211 *pkt, u8 *pBuffer, u16 len) length += getByte(&temp) << 8; hddLog(VOS_TRACE_LEVEL_INFO,"Payload length : %d", length); + if (length >= WLAN_DISA_MAX_PAYLOAD_SIZE) + length = WLAN_DISA_MAX_PAYLOAD_SIZE; + pkt->data.length = length; for (i = 0; i< length; i++) { From 128a8ef0916dc28d5b1c3745b328e71ae3b1b3f5 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Fri, 7 Oct 2016 12:14:11 +0530 Subject: [PATCH 072/281] prima: Validate netlink packet length While processing netlink packet(logger app), packet length is validated incorrectly, leading packets to drop without processing. Validate netlink packet lenght properly, by checking whole (including header) netlink packet size with skb's len. Change-Id: Ia6fc1a4c090084ad197ae198404c9083d0acb8e4 CRs-Fixed: 1075397 --- .../CORE/SVC/src/logging/wlan_logging_sock_svc.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c index b19bd42c8fee..64a252b8a954 100644 --- a/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c +++ b/drivers/staging/prima/CORE/SVC/src/logging/wlan_logging_sock_svc.c @@ -280,7 +280,7 @@ static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio, tAniNlHdr *wnl = NULL; struct sk_buff *skb; struct nlmsghdr *nlh; - int wmsg_length = wmsg->length; + int wmsg_length = ntohs(wmsg->length); static int nlmsg_seq; if (radio < 0 || radio > ANI_MAX_RADIOS) { @@ -290,6 +290,7 @@ static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio, } payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(tAniHdr); + tot_msg_len = NLMSG_SPACE(payload_len); skb = dev_alloc_skb(tot_msg_len); if (skb == NULL) { @@ -1275,7 +1276,7 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) tAniNlHdr *wnl; int radio; int type; - int ret; + int ret, len; unsigned long flags; if (TRUE == vos_isUnloadInProgress()) @@ -1294,10 +1295,12 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) return -EINVAL; } - if (wnl->wmsg.length > skb->data_len) + len = ntohs(wnl->wmsg.length) + sizeof(tAniNlHdr); + + if (len > skb_headlen(skb)) { - pr_err("%s: invalid length msgLen:%x skb data_len:%x \n", - __func__, wnl->wmsg.length, skb->data_len); + pr_err("%s: invalid length, msgLen:%x skb len:%x headLen: %d data_len: %d", + __func__, len, skb->len, skb_headlen(skb), skb->data_len); return -EINVAL; } From 3b4db741521dad9fd42a525cbd3135616c77f621 Mon Sep 17 00:00:00 2001 From: Manjeet Singh Date: Mon, 21 Nov 2016 19:02:08 +0530 Subject: [PATCH 073/281] prima: Validate station id In function hdd_hostapd_select_queue, station id is not validated with max station count, this might lead to a buffer overflow situation for array aStaInfo in SapCtx. Validate station id with max sta count. Change-Id: Ic1dd825b6437e4b0d7d8ed133184674bbfa53699 CRs-Fixed: 1092611 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c index b6d5c2140902..dcea728e7435 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c @@ -2120,7 +2120,7 @@ v_U16_t hdd_hostapd_select_queue(struct net_device * dev, struct sk_buff *skb } /*Get the Station ID*/ STAId = hdd_sta_id_find_from_mac_addr(pAdapter, pDestMacAddress); - if (STAId == HDD_WLAN_INVALID_STA_ID) { + if (STAId == HDD_WLAN_INVALID_STA_ID || STAId >= WLAN_MAX_STA_COUNT) { VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_INFO, "%s: Failed to find right station", __func__); goto done; From 6e5e4f9a3affaf6bc00a84888f7e8f89d830ad63 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Wed, 23 Nov 2016 10:59:12 +0530 Subject: [PATCH 074/281] wlan: Fix passive to active channel conversion issue As part of SETDFSSCANMODE cmd all the DFS channels are reset to passive channels in WNI_CFG_SCAN_CONTROL_LIST, but the timestamp of the last received beacon on these passive channels is not reset. Thus even if beacon is received on these channels the passive to active conversion does not happen as the timestamp is non 0. To fix this reset the timestamp of the last received beacon on the passive channels whenever the WNI_CFG_SCAN_CONTROL_LIST is reset. Change-Id: I83887cc43c38d5b045415278459c7be455085e34 CRs-Fixed: 1095474 --- drivers/staging/prima/CORE/MAC/inc/sirApi.h | 2 +- drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c | 6 +++--- .../prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c | 8 ++++++++ drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 7 ++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 08f6c2253d7d..dc9e9a76fb79 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -766,7 +766,7 @@ typedef struct sSirChannelList typedef struct sSirDFSChannelList { - tANI_U32 timeStamp[SIR_MAX_24G_5G_CHANNEL_RANGE]; + v_TIME_t timeStamp[SIR_MAX_24G_5G_CHANNEL_RANGE]; } tSirDFSChannelList, *tpSirDFSChannelList; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c index d3028fe4ec97..b420404340ec 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limP2P.c @@ -504,9 +504,9 @@ void limProcessInsertSingleShotNOATimeout(tpAniSirGlobal pMac) *------------------------------------------------------------------*/ void limConvertActiveChannelToPassiveChannel(tpAniSirGlobal pMac ) { - tANI_U32 currentTime; - tANI_U32 lastTime = 0; - tANI_U32 timeDiff; + v_TIME_t currentTime; + v_TIME_t lastTime = 0; + v_TIME_t timeDiff; tANI_U8 i; currentTime = vos_timer_get_system_time(); for (i = 1; i < SIR_MAX_24G_5G_CHANNEL_RANGE ; i++) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c index fcf5a014ecd6..d0eab9bab7b0 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMlmReqMessages.c @@ -734,6 +734,14 @@ void limSetDFSChannelList(tpAniSirGlobal pMac,tANI_U8 channelNum, tSirDFSChannel limLog(pMac, LOG1, FL("Received first beacon on DFS channel: %d"), channelNum); limCovertChannelScanType(pMac,channelNum, passiveToActive); } + + if (!pMac->fActiveScanOnDFSChannels && + dfsChannelList->timeStamp[channelNum] && + !limActiveScanAllowed(pMac, channelNum)) + limLog(pMac, LOGE, + FL("Received beacon on DFS channel %d with dfs time stamp %lu, but channel is still DFS"), + channelNum, dfsChannelList->timeStamp[channelNum]); + dfsChannelList->timeStamp[channelNum] = vos_timer_get_system_time(); } else diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index e31b94b4a290..984836e7625b 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -4057,8 +4057,6 @@ void csrApplyChannelPowerCountryInfo( tpAniSirGlobal pMac, tCsrChannel *pChannel // extend scan capability // build a scan list based on the channel list : channel# + active/passive scan csrSetCfgScanControlList(pMac, countryCode, &ChannelList); - /*Send msg to Lim to clear DFS channel list */ - csrClearDfsChannelList(pMac); #ifdef FEATURE_WLAN_SCAN_PNO if (updateRiva) { @@ -8517,7 +8515,6 @@ void csrSetCfgScanControlList( tpAniSirGlobal pMac, tANI_U8 *countryCode, tCsrCh } } } - smsLog(pMac, LOG1, FL("fEnableDFSChnlScan %d"), pMac->scan.fEnableDFSChnlScan); VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, @@ -8529,6 +8526,10 @@ void csrSetCfgScanControlList( tpAniSirGlobal pMac, tANI_U8 *countryCode, tCsrCh }//Successfully getting scan control list vos_mem_free(pControlList); }//AllocateMemory + + /* Send msg to Lim to clear DFS channel list */ + smsLog(pMac, LOG1, FL("csrClearDfsChannelList")); + csrClearDfsChannelList(pMac); } //if bgPeriod is 0, background scan is disabled. It is in millisecond units From 064dce8ab0925593899859b00d8f5b95ca42999b Mon Sep 17 00:00:00 2001 From: mukul sharma Date: Wed, 23 Nov 2016 19:29:18 +0530 Subject: [PATCH 075/281] prima: Create interface for updating cfg ini param Create interface for updating cfg ini param to firmware dynamically using WLAN_HAL_UPDATE_CFG_REQ Change-Id: I9d147a805e9628e35fd4fd2c3babcfb14d2f91f9 CRs-Fixed: 1096029 --- drivers/staging/prima/CORE/MAC/inc/sirApi.h | 6 + .../prima/CORE/MAC/src/include/sirParams.h | 1 + drivers/staging/prima/CORE/SME/inc/sme_Api.h | 1 + .../prima/CORE/SME/src/sme_common/sme_Api.c | 64 ++++++ .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 2 + .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 190 +++++++++++++++++- 6 files changed, 259 insertions(+), 5 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index dc9e9a76fb79..86892bec8428 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -3767,6 +3767,12 @@ typedef struct sSirWlanSetRxpFilters tANI_U8 setMcstBcstFilter; }tSirWlanSetRxpFilters,*tpSirWlanSetRxpFilters; + +typedef struct sSirUpdateCfgIntParam +{ + tANI_U32 cfgId; +}tSirUpdateCfgIntParam,*tpSirUpdateCfgIntParam; + typedef struct { //FW mail box address diff --git a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h index 1f6473698ca4..b91e2fe6378d 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h +++ b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h @@ -764,6 +764,7 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_PER_ROAM_SCAN_TRIGGER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 288) #define SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 289) #endif +#define SIR_HAL_UPDATE_CFG_INT_PARAM (SIR_HAL_ITC_MSG_TYPES_BEGIN + 290) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) // CFG message types diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 842f9981495f..41a1640ae520 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h @@ -3960,4 +3960,5 @@ eHalStatus sme_remove_bssid_from_scan_list(tHalHandle hal, tSirMacAddr bssid); void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, tANI_BOOLEAN sendMgmtPktViaWQ5); +eHalStatus sme_update_cfg_int_param(tHalHandle hHal, tANI_U32 cfg_id); #endif //#if !defined( __SME_API_H ) diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index 182040c6b782..9a1d36fe243e 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -8219,6 +8219,70 @@ eHalStatus sme_ConfigureRxpFilter( tHalHandle hHal, return(status); } +/* --------------------------------------------------------------------------- + + \fn sme_update_hal_int_param + + \brief + SME will pass this request to lower mac to indicate that the host needs to + update the cfg item + + \param + + hHal - The handle returned by macOpen. + + cfg_id- cfg param id + + + \return eHalStatus + + +--------------------------------------------------------------------------- */ + +eHalStatus sme_update_cfg_int_param(tHalHandle hHal, + tANI_U32 cfg_id) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t vosMessage; + tpSirUpdateCfgIntParam updateCfgIntParam = + vos_mem_malloc(sizeof(tSirUpdateCfgIntParam)); + + if (updateCfgIntParam == NULL) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + "%s: vos_mem_alloc for updateCfgIntParam", __func__); + return eHAL_STATUS_FAILURE; + } + + updateCfgIntParam->cfgId = cfg_id; + /* + * This API expect user must have updated cfg item using cfg API's. + * Hence it just need the cfg param id not the cfg value. + */ + status = sme_AcquireGlobalLock(&pMac->sme); + if (eHAL_STATUS_SUCCESS == status) + { + /* serialize the req through MC thread */ + vosMessage.bodyptr = updateCfgIntParam; + vosMessage.type = WDA_UPDATE_CFG_INT_PARAM; + vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage); + if (!VOS_IS_STATUS_SUCCESS(vosStatus)) + { + status = eHAL_STATUS_FAILURE; + vos_mem_free(updateCfgIntParam); + } + sme_ReleaseGlobalLock(&pMac->sme); + } + else + { + status = eHAL_STATUS_FAILURE; + vos_mem_free(updateCfgIntParam); + } + return(status); +} + /* --------------------------------------------------------------------------- \fn sme_ConfigureSuspendInd diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index ef48cd80e360..d058e45ac0dd 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -453,6 +453,7 @@ typedef struct v_PVOID_t pWdiContext; /* WDI context */ WDA_state wdaState ; /* WDA state tracking */ v_PVOID_t wdaWdiCfgApiMsgParam ; /* WDI API paramter tracking */ + v_PVOID_t wdaWdiCfgUpdateIntMsg ; /* WDI API CFG update param tracking */ vos_event_t wdaWdiEvent; /* WDI API sync event */ /* Event to wait for tx completion */ @@ -1187,6 +1188,7 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_PER_ROAM_SCAN_TRIGGER_REQ SIR_HAL_PER_ROAM_SCAN_TRIGGER_REQ #define WDA_PER_ROAM_SCAN_TRIGGER_RSP SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP #endif +#define WDA_UPDATE_CFG_INT_PARAM SIR_HAL_UPDATE_CFG_INT_PARAM #ifdef WLAN_WAKEUP_EVENTS #define WDA_WAKE_REASON_IND SIR_HAL_WAKE_REASON_IND diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 345f8cd9664d..90f795a3d7fd 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -5234,7 +5234,7 @@ void WDA_UpdateSTAParams(tWDA_CbContext *pWDA, * FUNCTION: WDA_ConvertWniCfgIdToHALCfgId * Convert the WNI CFG ID to HAL CFG ID */ -static inline v_U8_t WDA_ConvertWniCfgIdToHALCfgId(v_U32_t wniCfgId) +static inline tANI_U16 WDA_ConvertWniCfgIdToHALCfgId(v_U32_t wniCfgId) { switch(wniCfgId) { @@ -5342,12 +5342,14 @@ static inline v_U8_t WDA_ConvertWniCfgIdToHALCfgId(v_U32_t wniCfgId) return QWLAN_HAL_CFG_UNITS_OF_BCN_WAIT_TIME; case WNI_CFG_ENABLE_RTSCTS_HTVHT: return QWLAN_HAL_CFG_ENABLE_RTSCTS_HTVHT; + case WNI_CFG_ENABLE_MC_ADDR_LIST: + return QWLAN_HAL_CFG_ENABLE_MC_ADDR_LIST; default: { VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "There is no HAL CFG Id corresponding to WNI CFG Id: %d", wniCfgId); - return VOS_STATUS_E_INVAL; + return QWLAN_HAL_CFG_MAX_PARAMS; } } } @@ -5403,7 +5405,6 @@ VOS_STATUS WDA_UpdateCfg(tWDA_CbContext *pWDA, tSirMsgQ *cfgParam) { return VOS_STATUS_E_FAILURE; } - if(NULL != pWDA->wdaWdiCfgApiMsgParam) { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, @@ -5411,7 +5412,7 @@ VOS_STATUS WDA_UpdateCfg(tWDA_CbContext *pWDA, tSirMsgQ *cfgParam) VOS_ASSERT(0); return VOS_STATUS_E_FAILURE; } - + wdiCfgReqParam = (WDI_UpdateCfgReqParamsType *)vos_mem_malloc( sizeof(WDI_UpdateCfgReqParamsType)) ; if(NULL == wdiCfgReqParam) @@ -5431,7 +5432,7 @@ VOS_STATUS WDA_UpdateCfg(tWDA_CbContext *pWDA, tSirMsgQ *cfgParam) VOS_ASSERT(0); return VOS_STATUS_E_NOMEM; } - + /*convert the WNI CFG Id to HAL CFG Id*/ ((tHalCfg *)wdiCfgReqParam->pConfigBuffer)->type = WDA_ConvertWniCfgIdToHALCfgId(cfgParam->bodyval); @@ -5475,6 +5476,166 @@ VOS_STATUS WDA_UpdateCfg(tWDA_CbContext *pWDA, tSirMsgQ *cfgParam) return CONVERT_WDI2VOS_STATUS(status) ; } +/* + * FUNCTION: WDA_UpdateCfgIntParamCb + * + */ +void WDA_UpdateCfgIntParamCb(WDI_Status wdiStatus, void* pUserData) +{ + tWDA_CbContext *pWDA = (tWDA_CbContext *)pUserData ; + WDI_UpdateCfgReqParamsType *wdiCfgParam = + (WDI_UpdateCfgReqParamsType *)pWDA->wdaWdiCfgUpdateIntMsg ; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "<------ %s " ,__func__); + /* + * currently there is no response message is expected between PE and + * WDA, Failure return from WDI is a ASSERT condition + */ + if (WDI_STATUS_SUCCESS != wdiStatus) + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: CFG (%d) config failure", __func__, + ((tHalCfg *)(wdiCfgParam->pConfigBuffer))->type); + + if (wdiCfgParam && wdiCfgParam->pConfigBuffer) + { + vos_mem_free(wdiCfgParam->pConfigBuffer); + wdiCfgParam->pConfigBuffer = NULL; + } + + if (pWDA->wdaWdiCfgUpdateIntMsg) + { + vos_mem_free(pWDA->wdaWdiCfgUpdateIntMsg); + pWDA->wdaWdiCfgUpdateIntMsg = NULL; + } + + return ; +} + +/* + * FUNCTION: WDA_UpdateCfgIntParam + * + */ +VOS_STATUS WDA_UpdateCfgIntParam(tWDA_CbContext *pWDA, + tSirUpdateCfgIntParam *cfgParam) +{ + + WDI_Status status = WDI_STATUS_SUCCESS ; + tANI_U32 val =0; + tpAniSirGlobal pMac; + WDI_UpdateCfgReqParamsType *wdiCfgReqParam = NULL ; + tHalCfg *tlvStruct = NULL ; + tANI_U8 *tlvStructStart = NULL ; + v_PVOID_t *configParam; + tANI_U32 configParamSize; + tANI_U32 *configDataValue; + tANI_U32 cfgId; + tANI_U32 tlv_type = QWLAN_HAL_CFG_MAX_PARAMS; + + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + " ------> %s " ,__func__); + + if (cfgParam) + { + cfgId = cfgParam->cfgId; + } + else + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Invoked with NULL cfgParam")); + return VOS_STATUS_E_FAILURE; + } + + if (!pWDA) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Invoked with invalid WDA context")); + return VOS_STATUS_E_FAILURE; + } + + if (NULL != pWDA->wdaWdiCfgUpdateIntMsg) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("wdaWdiCfgApiMsgParam is not NULL")); + + return VOS_STATUS_E_FAILURE; + } + + pMac = (tpAniSirGlobal )VOS_GET_MAC_CTXT(pWDA->pVosContext) ; + if (NULL == pMac) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Invoked with invalid MAC context ")); + return VOS_STATUS_E_FAILURE; + } + + if (wlan_cfgGetInt(pMac, (tANI_U16)cfgId , &val) != eSIR_SUCCESS) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + FL("Fail to cfg get id %d"), cfgId); + return VOS_STATUS_E_FAILURE; + } + + /* Get TLV type */ + tlv_type = WDA_ConvertWniCfgIdToHALCfgId(cfgId); + if (tlv_type == QWLAN_HAL_CFG_MAX_PARAMS) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to Convert cfg to hal id %d", cfgId); + return VOS_STATUS_E_FAILURE; + } + + wdiCfgReqParam = (WDI_UpdateCfgReqParamsType *)vos_mem_malloc( + sizeof(WDI_UpdateCfgReqParamsType)) ; + if (NULL == wdiCfgReqParam) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + return VOS_STATUS_E_NOMEM; + } + + configParamSize = (sizeof(tHalCfg) + (sizeof(tANI_U32))) * 1; + configParam = vos_mem_malloc(configParamSize); + if (NULL == configParam) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + vos_mem_free(wdiCfgReqParam); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_set(configParam, configParamSize, 0); + wdiCfgReqParam->pConfigBuffer = configParam; + tlvStruct = (tHalCfg *)configParam; + tlvStructStart = (tANI_U8 *)configParam; + /* Set TLV type */ + tlvStruct->type = tlv_type; + tlvStruct->length = sizeof(tANI_U32); + configDataValue = (tANI_U32 *)(tlvStruct + 1); + *configDataValue = (tANI_U32)val; + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "cfg_id %d tlv_type %d tlv_value %d \n", + cfgId, tlvStruct->type, val); + tlvStruct = (tHalCfg *)(( (tANI_U8 *) tlvStruct + + sizeof(tHalCfg) + tlvStruct->length)) ; + wdiCfgReqParam->uConfigBufferLen = (tANI_U8 *)tlvStruct - tlvStructStart ; + wdiCfgReqParam->wdiReqStatusCB = NULL; + /* store Params pass it to WDI */ + pWDA->wdaWdiCfgUpdateIntMsg = (void *)wdiCfgReqParam ; + status = WDI_UpdateCfgReq(wdiCfgReqParam, + (WDI_UpdateCfgRspCb )WDA_UpdateCfgIntParamCb, pWDA) ; + if (IS_WDI_STATUS_FAILURE(status)) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failure in WDA_UpdateCfgIntParam WDI API, free memory "); + vos_mem_free(wdiCfgReqParam->pConfigBuffer); + wdiCfgReqParam->pConfigBuffer = NULL; + vos_mem_free(pWDA->wdaWdiCfgUpdateIntMsg); + pWDA->wdaWdiCfgUpdateIntMsg = NULL; + } + + return CONVERT_WDI2VOS_STATUS(status); +} + VOS_STATUS WDA_GetWepKeysFromCfg( tWDA_CbContext *pWDA, v_U8_t *pDefaultKeyId, v_U8_t *pNumKeys, @@ -15359,6 +15520,25 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) } break; } + case WDA_UPDATE_CFG_INT_PARAM: + { + if(pWDA->wdaState == WDA_READY_STATE) + { + WDA_UpdateCfgIntParam(pWDA, (tSirUpdateCfgIntParam *)pMsg->bodyptr); + vos_mem_free(pMsg->bodyptr); + } + else + { + if(NULL != pMsg->bodyptr) + { + vos_mem_free(pMsg->bodyptr); + } + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + " WDA_UPDATE_CFG_INT_PARAM req in wrong state %d", + pWDA->wdaState ); + } + break; + } case WDA_ENTER_IMPS_REQ: { if(pWDA->wdaState == WDA_READY_STATE) From 3ffc16a45f4e6af8a0499208f3837bbd0e53495e Mon Sep 17 00:00:00 2001 From: mukul sharma Date: Thu, 24 Nov 2016 22:03:31 +0530 Subject: [PATCH 076/281] prima: Support for all MC packet when MCBCFilter is set 0/2 If MCAddrList is enabled in ini and MCBC filter is set to Either Filter None (0) or Filter all BC (2)then, Fwr need to push all MC to host. This can be achived by disabling cfg MCAddrList in fwr. As in driver load, firmware have this value to 1 we need to set it to 0. Same needs to be reverted on resume. Change-Id: I5072e61efbad75c49e4fc01c9f8e444cca1f192b CRs-Fixed: 1094375 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 2 + .../prima/CORE/HDD/inc/wlan_hdd_power.h | 5 + .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 3 + .../CORE/HDD/src/wlan_hdd_early_suspend.c | 116 ++++++++++++++++++ .../prima/CORE/HDD/src/wlan_hdd_wext.c | 5 + 5 files changed, 131 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 03ce521eef05..8be2853b69b2 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1533,6 +1533,8 @@ struct hdd_context_s v_BOOL_t sus_res_mcastbcast_filter_valid; + v_BOOL_t mc_list_cfg_in_fwr; + /* debugfs entry */ struct dentry *debugfs_phy; diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h index 87756d480305..b932567ec7c7 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h @@ -108,6 +108,11 @@ int wlan_hdd_ipv4_changed(struct notifier_block *nb, int wlan_hdd_ipv6_changed(struct notifier_block *nb, unsigned long data, void *arg); +eHalStatus hdd_set_mc_list_cfg_item(hdd_context_t* pHddCtx, + bool value); +bool is_mc_list_cfg_disable_required(hdd_context_t* pHddCtx); +void hdd_mc_addr_list_cfg_config(hdd_context_t* pHddCtx, bool action); + /** * enum suspend_resume_state - Suspend resume state * @HDD_WLAN_EARLY_SUSPEND: Early suspend state. diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 6094d8686496..3389cec511f0 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -5287,6 +5287,9 @@ v_BOOL_t hdd_update_config_dat( hdd_context_t *pHddCtx ) hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CCM"); } + /* cache the value configured in fwr */ + pHddCtx->mc_list_cfg_in_fwr = pConfig->fEnableMCAddrList; + #ifdef WLAN_FEATURE_11AC /* Based on cfg.ini, update the Basic MCS set, RX/TX MCS map in the cfg.dat */ /* valid values are 0(MCS0-7), 1(MCS0-8), 2(MCS0-9) */ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index 1607774db2ce..af86113971f3 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -1325,6 +1325,116 @@ void hdd_conf_mcastbcast_filter(hdd_context_t* pHddCtx, v_BOOL_t setfilter) vos_mem_free(wlanRxpFilterParam); } +/* + * Enable/Disable McAddrList cfg item in fwr. + */ +eHalStatus hdd_set_mc_list_cfg_item(hdd_context_t* pHddCtx, + bool value) +{ + eHalStatus ret_val; + + if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_ENABLE_MC_ADDR_LIST, + value, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) + { + ret_val = eHAL_STATUS_FAILURE; + hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CCM"); + return ret_val; + } + + ret_val = sme_update_cfg_int_param(pHddCtx->hHal, + WNI_CFG_ENABLE_MC_ADDR_LIST); + if (!HAL_STATUS_SUCCESS(ret_val)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("Failed to toggle MC_ADDR_LIST_INI %d "), + ret_val); + return ret_val; + } + /* cache the value configured in fwr */ + pHddCtx->mc_list_cfg_in_fwr = value; + + return eHAL_STATUS_SUCCESS; +} + +bool is_mc_list_cfg_disable_required(hdd_context_t* pHddCtx) +{ + /* + * If MCAddrList is enabled in ini and MCBC filter is set to + * Either Filter None or Filter all BC then, Fwr need to push + * all MC to host. This can be achieved by disabling cfg MCAddrList + * in fwr. As in driver load, firmware have this value to 1 we + * need to set it to 0. Same needs to be reverted on resume. + */ + if (pHddCtx->cfg_ini->fEnableMCAddrList && + WDA_IS_MCAST_FLT_ENABLE_IN_FW && + ((VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid)&& + ((HDD_MCASTBCASTFILTER_FILTER_NONE == + pHddCtx->sus_res_mcastbcast_filter) || + (HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST == + pHddCtx->sus_res_mcastbcast_filter))) + ) + { + return true; + } + else + { + return false; + } +} + +/** + * hdd_mc_addr_list_cfg_config() - To set mc list cfg configuration in fwr + * @pHddCtx: hdd context handle + * @action: true to disable MCAddrList in fwr to get all MC pkt to host + * false to set ini value of MCAddrList in fwr if it was toggled + * Return: none + * + * Ensure Below API is invoked always post modification + * of sus_res_mcastbcast_filter. + */ +void hdd_mc_addr_list_cfg_config(hdd_context_t* pHddCtx, bool action) +{ + if (action) + { + /* check host need to disable mc list ini in fwr */ + if (is_mc_list_cfg_disable_required(pHddCtx)) + { + /* + * Yes Host should disable the mc list in fwr + * But Ensure host might already disable it + * This can happen when user issue set/clear MCBC + * ioctl with 2 to 0 or vice versa. + */ + if (pHddCtx->cfg_ini->fEnableMCAddrList == + pHddCtx->mc_list_cfg_in_fwr) + { + hdd_set_mc_list_cfg_item(pHddCtx, + !pHddCtx->cfg_ini->fEnableMCAddrList); + } + } + else + { + /* Host toggled mc list ini in fwr previosuly, set to ini value */ + if (pHddCtx->cfg_ini->fEnableMCAddrList != + pHddCtx->mc_list_cfg_in_fwr) + { + hdd_set_mc_list_cfg_item(pHddCtx, + pHddCtx->cfg_ini->fEnableMCAddrList); + } + } + } + else + { + /* Host toggled mc list ini in fwr previosuly, set to ini value */ + if (pHddCtx->cfg_ini->fEnableMCAddrList != + pHddCtx->mc_list_cfg_in_fwr) + { + hdd_set_mc_list_cfg_item(pHddCtx, + pHddCtx->cfg_ini->fEnableMCAddrList); + } + } +} + static void hdd_conf_suspend_ind(hdd_context_t* pHddCtx, hdd_adapter_t *pAdapter) { @@ -1379,6 +1489,10 @@ static void hdd_conf_suspend_ind(hdd_context_t* pHddCtx, wlanSuspendParam->configuredMcstBcstFilterSetting = pHddCtx->configuredMcastBcastFilter; + + /* mc add list cfg item configuration in fwr */ + hdd_mc_addr_list_cfg_config(pHddCtx, true); + } halStatus = sme_ConfigureSuspendInd(pHddCtx->hHal, wlanSuspendParam); @@ -1424,6 +1538,8 @@ static void hdd_conf_resume_ind(hdd_adapter_t *pAdapter) } pHddCtx->hdd_mcastbcast_filter_set = FALSE; + /* mc add list cfg item configuration in fwr */ + hdd_mc_addr_list_cfg_config(pHddCtx, false); if (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid) { pHddCtx->configuredMcastBcastFilter = diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 86a09a317eee..84655486fd1b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -8663,6 +8663,8 @@ static int __iw_set_dynamic_mcbc_filter(struct net_device *dev, pHddCtx->sus_res_mcastbcast_filter = pRequest->mcastBcastFilterSetting; } + /* mc add list cfg item configuration in fwr */ + hdd_mc_addr_list_cfg_config(pHddCtx, true); } } @@ -8754,6 +8756,9 @@ static int __iw_clear_dynamic_mcbc_filter(struct net_device *dev, pHddCtx->cfg_ini->mcastBcastFilterSetting; } + /* mc add list cfg item configuration in fwr */ + hdd_mc_addr_list_cfg_config(pHddCtx, true); + } EXIT(); return 0; From 614185bb7dc7e1a3da6c908f61386ce29ac9a458 Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Wed, 7 Dec 2016 16:21:07 +0530 Subject: [PATCH 077/281] wlan: Use heap memory for station_info instead of stack qcacld-2.0 to prima propagation. From kernel 3.19-rc4, size of struct station_info is around 600 bytes, so stack frame size of such routine use this struct will easily exceed 1024 bytes, the default value of stack frame size. So use heap memory for this struct instead. Change-Id: Ibe8a4f5189fcc9d5554f7a5d851c93be8fa8dbad CRs-Fixed: 1050323 --- .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 19 ++++++++++++++----- .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 19 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 933a2df781d1..cd5686f671c2 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -2730,7 +2730,7 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t case eCSR_ROAM_RESULT_IBSS_NEW_PEER: { hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - struct station_info staInfo; + struct station_info *staInfo; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "IBSS New Peer indication from SME with peerMac " MAC_ADDRESS_STR " BSSID: " MAC_ADDRESS_STR " and stationID= %d", @@ -2764,13 +2764,22 @@ static eHalStatus roamRoamConnectStatusUpdateHandler( hdd_adapter_t *pAdapter, t break; } pHddStaCtx->ibss_sta_generation++; - memset(&staInfo, 0, sizeof(staInfo)); - staInfo.filled = 0; - staInfo.generation = pHddStaCtx->ibss_sta_generation; + + staInfo = vos_mem_malloc(sizeof(*staInfo)); + if (staInfo == NULL) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "memory allocation for station_info failed"); + return eHAL_STATUS_FAILED_ALLOC; + } + + memset(staInfo, 0, sizeof(*staInfo)); + staInfo->filled = 0; + staInfo->generation = pHddStaCtx->ibss_sta_generation; cfg80211_new_sta(pAdapter->dev, (const u8 *)pRoamInfo->peerMac, - &staInfo, GFP_KERNEL); + staInfo, GFP_KERNEL); + vos_mem_free(staInfo); if ( eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == pHddStaCtx->ibss_enc_key.encType ||eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == pHddStaCtx->ibss_enc_key.encType diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index e67db4d09044..427a35058bcf 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -1065,21 +1065,28 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) { - struct station_info staInfo; + struct station_info *staInfo; v_U16_t iesLen = pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.iesLen; - memset(&staInfo, 0, sizeof(staInfo)); + staInfo = vos_mem_malloc(sizeof(*staInfo)); + if (staInfo == NULL) { + hddLog(LOGE, FL("alloc station_info failed")); + return VOS_STATUS_E_NOMEM; + } + + memset(staInfo, 0, sizeof(*staInfo)); if (iesLen <= MAX_ASSOC_IND_IE_LEN ) { - staInfo.assoc_req_ies = + staInfo->assoc_req_ies = (const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.ies[0]; - staInfo.assoc_req_ies_len = iesLen; + staInfo->assoc_req_ies_len = iesLen; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,31)) - staInfo.filled |= STATION_INFO_ASSOC_REQ_IES; + staInfo->filled |= STATION_INFO_ASSOC_REQ_IES; #endif cfg80211_new_sta(dev, (const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staMac.bytes[0], - &staInfo, GFP_KERNEL); + staInfo, GFP_KERNEL); + vos_mem_free(staInfo); } else { From 3df4bb5cdc3964b32faad9ba919202088a166217 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Fri, 16 Dec 2016 19:57:52 +0530 Subject: [PATCH 078/281] wlan: Validate no.of RIC data desctiptors before use Add change to validate no.of RIC data desctriptors before using it to access RICData array. Change-Id: I0ac4e9e1eb61690b3c13a74fa0edfc5af13d88c6 CRs-Fixed: 1102327 --- drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c index d408f16c84a8..6009013c992e 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/parserApi.c @@ -2714,7 +2714,7 @@ sirConvertAssocRespFrame2Struct(tpAniSirGlobal pMac, #endif #ifdef WLAN_FEATURE_VOWIFI_11R - if (ar.num_RICDataDesc) { + if (ar.num_RICDataDesc <= 2) { for (cnt=0; cnt < ar.num_RICDataDesc; cnt++) { if (ar.RICDataDesc[cnt].present) { vos_mem_copy( &pAssocRsp->RICData[cnt], &ar.RICDataDesc[cnt], From 69f45bc5e5a0c3d0740e21e8cdafa145a7b56a80 Mon Sep 17 00:00:00 2001 From: Subrat Dash Date: Wed, 14 Dec 2016 14:35:24 +0530 Subject: [PATCH 079/281] prima: Fix VHT-80 IBSS stops beaconing A STA entry is created for each peer joining the network to take care of the peer specific capabilities. The VDEV need not be reconfigured for IBSS peer with different channel width joining the network. Change-Id: Iec6ec5d2b510b84538f4e5300b3f1c5cc63b334d CRs-Fixed: 1046409 --- drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c index 8d3483b49ca8..8d3230947d16 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c @@ -469,7 +469,8 @@ static void __schBeaconProcessForSession( tpAniSirGlobal pMac, sendProbeReq = TRUE; } - if ( psessionEntry->htCapability && pBeacon->HTInfo.present ) + if ( psessionEntry->htCapability && pBeacon->HTInfo.present && + (!LIM_IS_IBSS_ROLE(psessionEntry))) { limUpdateStaRunTimeHTSwitchChnlParams( pMac, &pBeacon->HTInfo, bssIdx,psessionEntry); } From 2af44fad57c39e5e549285147ad25334f8abeb86 Mon Sep 17 00:00:00 2001 From: Arif Hussain Date: Tue, 6 Dec 2016 19:49:31 +0530 Subject: [PATCH 080/281] wlan: Use sme_dhcp_start/stop_ind api for dhcp state qcacld-3.0 to prima propagation Android framework indicates dhcp start and stop using power save (ps disable for dhcp start, ps enable for dhcp stop). Use this new indication method for any of the dhcp dependent operations. Also remove resetting dhcp_done flag in csr_roam_connect() function, as assumption of dhcp will trigger for every new connection is not correct, like in static IP address case there wont be dhcp indications, and this flag remains false. Change-Id: I3a995d859c39591b0a9fb4bc6e636e580c02dbd4 CRs-Fixed: 1088523 --- drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c | 1 - drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index 6b36c8a73fdd..aafe792b9d5e 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -6944,7 +6944,6 @@ eHalStatus csrRoamConnect(tpAniSirGlobal pMac, tANI_U32 sessionId, tCsrRoamProfi } /* Reset abortConnection for the fresh connection */ pSession->abortConnection = FALSE; - pSession->dhcp_done = false; csrRoamCancelRoaming(pMac, sessionId); csrScanRemoveFreshScanCommand(pMac, sessionId); csrScanCancelIdleScan(pMac); diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index 9a1d36fe243e..158b36adb584 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -6030,7 +6030,7 @@ eHalStatus sme_DHCPStartInd( tHalHandle hHal, sme_ReleaseGlobalLock( &pMac->sme ); return eHAL_STATUS_FAILURE; } - + pSession->dhcp_done = false; pMsg = (tAniDHCPInd*)vos_mem_malloc(sizeof(tAniDHCPInd)); if (NULL == pMsg) { @@ -6098,7 +6098,7 @@ eHalStatus sme_DHCPStopInd( tHalHandle hHal, sme_ReleaseGlobalLock( &pMac->sme ); return eHAL_STATUS_FAILURE; } - + pSession->dhcp_done = true; pMsg = (tAniDHCPInd*)vos_mem_malloc(sizeof(tAniDHCPInd)); if (NULL == pMsg) { From cdee817143647f79e61f96a0101f403cc2e20871 Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Thu, 1 Dec 2016 14:28:10 +0530 Subject: [PATCH 081/281] prima: Fix Set/Clear MCBC ioctl transition in early suspend Host uses set MCBC ioctl to change the MCBC value dynamically. But current host ioctl handling is not correct because firmware expects host must first disable offloads and later apply new filter value. Instead Host is applying new MCBC filter value without disabling offloads in early suspend mode. Another issue is host is updating suspend MCBC filter even when wlan is not in early suspend mode during IPv4 and Ipv6 change handling. As part of this fix, ensure host first disable and then enable offload. Host modify the suspend MCBC filter only when wlan is in early suspended mode. Change-Id: Ib759dd2210eb7e1acf028456c4ca98239f425604 CRs-Fixed: 1096069 --- .../prima/CORE/HDD/inc/wlan_hdd_power.h | 1 + .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 73 -------- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 171 +++++++++++++----- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 41 +++-- 4 files changed, 150 insertions(+), 136 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h index b932567ec7c7..70c700ab4261 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h @@ -140,5 +140,6 @@ void hdd_wlan_suspend_resume_event(uint8_t state) } #endif /* FEATURE_WLAN_DIAG_SUPPORT */ +void hdd_ReConfigSuspendDataClearedDuringRoaming(hdd_context_t* pHddCtx); #endif // if !defined __WLAN_QCT_DRIVER_H diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index cd5686f671c2..9b87c1692722 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -2441,79 +2441,6 @@ static eHalStatus roamIbssConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo return( eHAL_STATUS_SUCCESS ); } -/**============================================================================ - * - @brief hdd_ReConfigSuspendDataClearedDuringRoaming() - Reconfigure the - suspend related data which was cleared during roaming in FWR. - - ===========================================================================*/ -static void hdd_ReConfigSuspendDataClearedDuringRoaming(hdd_context_t *pHddCtx) -{ - VOS_STATUS vstatus = VOS_STATUS_E_FAILURE; - hdd_adapter_t *pAdapter; - hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; - ENTER(); - - spin_lock(&pHddCtx->filter_lock); - if (VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->configuredMcastBcastFilter; - pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; - hddLog(VOS_TRACE_LEVEL_INFO, FL("offload: callback to associated")); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("saving configuredMcastBcastFilter = %d"), - pHddCtx->configuredMcastBcastFilter); - hddLog(VOS_TRACE_LEVEL_INFO, - FL("offload: calling hdd_conf_mcastbcast_filter")); - } - spin_unlock(&pHddCtx->filter_lock); - - hdd_conf_mcastbcast_filter(pHddCtx, TRUE); - if(pHddCtx->hdd_mcastbcast_filter_set != TRUE) - hddLog(VOS_TRACE_LEVEL_ERROR, FL("Not able to set mcast/bcast filter ")); - - vstatus = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); - //No need to configure GTK Offload from here because it might possible - //cfg80211_set_rekey_data might not yet came, anyway GTK offload will - //be handled as part of cfg80211_set_rekey_data processing. - while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == vstatus ) - { - pAdapter = pAdapterNode->pAdapter; - if( pAdapter && - (( pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || - (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT))) - { - if (pHddCtx->cfg_ini->fhostArpOffload) - { - //Configure ARPOFFLOAD - vstatus = hdd_conf_arp_offload(pAdapter, TRUE); - if (!VOS_IS_STATUS_SUCCESS(vstatus)) - { - hddLog(VOS_TRACE_LEVEL_INFO, - FL("Failed to disable ARPOffload Feature %d"), vstatus); - } - } -#ifdef WLAN_NS_OFFLOAD - //Configure NSOFFLOAD - if (pHddCtx->cfg_ini->fhostNSOffload) - { - hdd_conf_ns_offload(pAdapter, TRUE); - } -#endif -#ifdef WLAN_FEATURE_PACKET_FILTERING - /* During suspend, configure MC Addr list filter to the firmware - * function takes care of checking necessary conditions before - * configuring. - */ - wlan_hdd_set_mc_addr_list(pAdapter, TRUE); -#endif - } - vstatus = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); - pAdapterNode = pNext; - } - EXIT(); -} /**============================================================================ * diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index af86113971f3..de9a3cf1f70b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -106,6 +106,23 @@ extern tVOS_CON_MODE hdd_get_conparam ( void ); static struct timer_list ssr_timer; static bool ssr_timer_started; +void inline check_and_set_suspend_resume_mcbc_filter(hdd_context_t *pHddCtx) +{ + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: sus_res_mcbc_filter_valid: %d sus_res_mcbc_filter: %d configuredMcBcFilter: %d"), + pHddCtx->sus_res_mcastbcast_filter_valid, + pHddCtx->sus_res_mcastbcast_filter, + pHddCtx->configuredMcastBcastFilter); + if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) + { + pHddCtx->sus_res_mcastbcast_filter = + pHddCtx->configuredMcastBcastFilter; + pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: saving sus_res_mcastbcast_filter = %d"), + pHddCtx->sus_res_mcastbcast_filter); + } +} #ifdef FEATURE_WLAN_DIAG_SUPPORT /** @@ -504,19 +521,11 @@ void __hdd_ipv6_notifier_work_queue(struct work_struct *work) return; } - if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->configuredMcastBcastFilter; - hddLog(LOG1, FL("saving configuredMcastBcastFilter = %d"), - pHddCtx->sus_res_mcastbcast_filter); - pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; - } - if ((eConnectionState_Associated == (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) && (pHddCtx->hdd_wlan_suspended)) { + check_and_set_suspend_resume_mcbc_filter(pHddCtx); // This invocation being part of the IPv6 registration callback, // set the newly generated ip address to f/w in suspend mode. #ifdef WLAN_NS_OFFLOAD @@ -709,6 +718,11 @@ void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, v_BOOL_t fenable) { hdd_conf_ns_offload(pAdapter, fenable); } + else + { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("ns offload ini is disabled")); + } #endif } } @@ -915,13 +929,13 @@ void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, int fenable) { offLoadRequest.enableOrDisable = SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE; - hddLog (VOS_TRACE_LEVEL_INFO, - FL("Set offLoadRequest with %d"), - offLoadRequest.enableOrDisable); } hdd_wlan_offload_event( SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE, SIR_OFFLOAD_ENABLE); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: NS filter programmed %d"), + offLoadRequest.enableOrDisable); vos_mem_copy(&offLoadRequest.params.hostIpv6Addr, &offLoadRequest.nsOffloadInfo.targetIPv6Addr[0], sizeof(tANI_U8)*SIR_MAC_IPV6_ADDR_LEN); @@ -1012,15 +1026,6 @@ void __hdd_ipv4_notifier_work_queue(struct work_struct *work) return; } - if ( VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->configuredMcastBcastFilter; - hddLog(LOG1, FL("saving configuredMcastBcastFilter = %d"), - pHddCtx->sus_res_mcastbcast_filter); - pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; - } - if ((eConnectionState_Associated == (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) && (pHddCtx->hdd_wlan_suspended)) @@ -1028,7 +1033,16 @@ void __hdd_ipv4_notifier_work_queue(struct work_struct *work) // This invocation being part of the IPv4 registration callback, // we are passing second parameter as 2 to avoid registration // of IPv4 notifier again. - hdd_conf_arp_offload(pAdapter, 2); + check_and_set_suspend_resume_mcbc_filter(pHddCtx); + if (pHddCtx->cfg_ini->fhostArpOffload) + { + hdd_conf_arp_offload(pAdapter, 2); + } + else + { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: arp offload ini is disabled in host")); + } } EXIT(); } @@ -1337,7 +1351,8 @@ eHalStatus hdd_set_mc_list_cfg_item(hdd_context_t* pHddCtx, value, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { ret_val = eHAL_STATUS_FAILURE; - hddLog(LOGE, "Could not pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CCM"); + hddLog(LOGE, + FL("offload: can't pass WNI_CFG_ENABLE_MC_ADDR_LIST to CCM")); return ret_val; } @@ -1352,12 +1367,17 @@ eHalStatus hdd_set_mc_list_cfg_item(hdd_context_t* pHddCtx, } /* cache the value configured in fwr */ pHddCtx->mc_list_cfg_in_fwr = value; - return eHAL_STATUS_SUCCESS; } bool is_mc_list_cfg_disable_required(hdd_context_t* pHddCtx) { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: fEnableMCList %d sus_res_mcbc_filter %d mc_list_in_fwr %d"), + pHddCtx->cfg_ini->fEnableMCAddrList, + pHddCtx->sus_res_mcastbcast_filter, + pHddCtx->mc_list_cfg_in_fwr); + /* * If MCAddrList is enabled in ini and MCBC filter is set to * Either Filter None or Filter all BC then, Fwr need to push @@ -1374,10 +1394,14 @@ bool is_mc_list_cfg_disable_required(hdd_context_t* pHddCtx) pHddCtx->sus_res_mcastbcast_filter))) ) { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: cfg ini need to disable in fwr")); return true; } else { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: cfg ini disable not needed ")); return false; } } @@ -1410,6 +1434,9 @@ void hdd_mc_addr_list_cfg_config(hdd_context_t* pHddCtx, bool action) { hdd_set_mc_list_cfg_item(pHddCtx, !pHddCtx->cfg_ini->fEnableMCAddrList); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + !pHddCtx->cfg_ini->fEnableMCAddrList); } } else @@ -1420,6 +1447,9 @@ void hdd_mc_addr_list_cfg_config(hdd_context_t* pHddCtx, bool action) { hdd_set_mc_list_cfg_item(pHddCtx, pHddCtx->cfg_ini->fEnableMCAddrList); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + pHddCtx->cfg_ini->fEnableMCAddrList); } } } @@ -1431,6 +1461,9 @@ void hdd_mc_addr_list_cfg_config(hdd_context_t* pHddCtx, bool action) { hdd_set_mc_list_cfg_item(pHddCtx, pHddCtx->cfg_ini->fEnableMCAddrList); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + pHddCtx->cfg_ini->fEnableMCAddrList); } } } @@ -1442,17 +1475,7 @@ static void hdd_conf_suspend_ind(hdd_context_t* pHddCtx, tpSirWlanSuspendParam wlanSuspendParam = vos_mem_malloc(sizeof(tSirWlanSuspendParam)); - if (VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->configuredMcastBcastFilter; - pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; - hddLog(VOS_TRACE_LEVEL_INFO, "offload: hdd_conf_suspend_ind"); - hddLog(VOS_TRACE_LEVEL_INFO, "configuredMCastBcastFilter saved = %d", - pHddCtx->configuredMcastBcastFilter); - - } - - + check_and_set_suspend_resume_mcbc_filter(pHddCtx); if(NULL == wlanSuspendParam) { hddLog(VOS_TRACE_LEVEL_FATAL, @@ -1667,6 +1690,69 @@ void hdd_suspend_wlan(void) return; } +/** + * @brief hdd_ReConfigSuspendDataClearedDuringRoaming() - Reconfigure the + * suspend related data which was cleared during roaming in FWR. + */ +void hdd_ReConfigSuspendDataClearedDuringRoaming(hdd_context_t *pHddCtx) + +{ + VOS_STATUS vstatus = VOS_STATUS_E_FAILURE; + hdd_adapter_t *pAdapter; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + + ENTER(); + + spin_lock(&pHddCtx->filter_lock); + check_and_set_suspend_resume_mcbc_filter(pHddCtx); + spin_unlock(&pHddCtx->filter_lock); + + hdd_conf_mcastbcast_filter(pHddCtx, TRUE); + if(pHddCtx->hdd_mcastbcast_filter_set != TRUE) + hddLog(VOS_TRACE_LEVEL_ERROR, FL("Not able to set mcast/bcast filter ")); + + vstatus = hdd_get_front_adapter ( pHddCtx, &pAdapterNode ); + //No need to configure GTK Offload from here because it might possible + //cfg80211_set_rekey_data might not yet came, anyway GTK offload will + //be handled as part of cfg80211_set_rekey_data processing. + while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == vstatus ) + { + pAdapter = pAdapterNode->pAdapter; + if( pAdapter && + (( pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || + (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT))) + { + if (pHddCtx->cfg_ini->fhostArpOffload) + { + //Configure ARPOFFLOAD + vstatus = hdd_conf_arp_offload(pAdapter, TRUE); + if (!VOS_IS_STATUS_SUCCESS(vstatus)) + { + hddLog(VOS_TRACE_LEVEL_INFO, + FL("Failed to disable ARPOffload Feature %d"), vstatus); + } + } +#ifdef WLAN_NS_OFFLOAD + //Configure NSOFFLOAD + if (pHddCtx->cfg_ini->fhostNSOffload) + { + hdd_conf_ns_offload(pAdapter, TRUE); + } +#endif +#ifdef WLAN_FEATURE_PACKET_FILTERING + /* During suspend, configure MC Addr list filter to the firmware + * function takes care of checking necessary conditions before + * configuring. + */ + wlan_hdd_set_mc_addr_list(pAdapter, TRUE); +#endif + } + vstatus = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext ); + pAdapterNode = pNext; + } + EXIT(); +} + static void hdd_PowerStateChangedCB ( v_PVOID_t callbackContext, @@ -1687,21 +1773,8 @@ static void hdd_PowerStateChangedCB spin_lock(&pHddCtx->filter_lock); if ((newState == BMPS) && pHddCtx->hdd_wlan_suspended) { + check_and_set_suspend_resume_mcbc_filter(pHddCtx); spin_unlock(&pHddCtx->filter_lock); - if (VOS_FALSE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->configuredMcastBcastFilter; - pHddCtx->sus_res_mcastbcast_filter_valid = VOS_TRUE; - - hddLog(VOS_TRACE_LEVEL_INFO, "offload: callback to associated"); - hddLog(VOS_TRACE_LEVEL_INFO, "saving configuredMcastBcastFilter = %d", - pHddCtx->configuredMcastBcastFilter); - hddLog(VOS_TRACE_LEVEL_INFO, - "offload: calling hdd_conf_mcastbcast_filter"); - - } - hdd_conf_mcastbcast_filter(pHddCtx, TRUE); if(pHddCtx->hdd_mcastbcast_filter_set != TRUE) hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Not able to set mcast/bcast filter ", __func__); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 84655486fd1b..07d2e6b9d264 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -8620,8 +8620,9 @@ static int __iw_set_dynamic_mcbc_filter(struct net_device *dev, "%s: Set MC BC Filter Config request: %d suspend %d", __func__, pRequest->mcastBcastFilterSetting, pHddCtx->hdd_wlan_suspended); - + spin_lock(&pHddCtx->filter_lock); pHddCtx->configuredMcastBcastFilter = pRequest->mcastBcastFilterSetting; + spin_unlock(&pHddCtx->filter_lock); if (pHddCtx->hdd_wlan_suspended) { @@ -8636,6 +8637,17 @@ static int __iw_set_dynamic_mcbc_filter(struct net_device *dev, wlanRxpFilterParam->configuredMcstBcstFilterSetting = pRequest->mcastBcastFilterSetting; wlanRxpFilterParam->setMcstBcstFilter = TRUE; + /* Fwr expect offload needs to clear before set */ + hdd_conf_hostoffload(pAdapter, FALSE); + spin_lock(&pHddCtx->filter_lock); + pHddCtx->configuredMcastBcastFilter = pRequest->mcastBcastFilterSetting; + spin_unlock(&pHddCtx->filter_lock); + if (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid) + { + hddLog(VOS_TRACE_LEVEL_INFO, "%s: pRequest->mcastBcastFilterSetting ", __func__); + pHddCtx->sus_res_mcastbcast_filter = + pRequest->mcastBcastFilterSetting; + } hdd_conf_hostoffload(pAdapter, TRUE); wlanRxpFilterParam->configuredMcstBcstFilterSetting = @@ -8658,11 +8670,6 @@ static int __iw_set_dynamic_mcbc_filter(struct net_device *dev, return -EINVAL; } - if (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pRequest->mcastBcastFilterSetting; - } /* mc add list cfg item configuration in fwr */ hdd_mc_addr_list_cfg_config(pHddCtx, true); } @@ -8717,8 +8724,10 @@ static int __iw_clear_dynamic_mcbc_filter(struct net_device *dev, { return ret; } + spin_lock(&pHddCtx->filter_lock); //Reset the filter to INI value as we have to clear the dynamic filter pHddCtx->configuredMcastBcastFilter = pHddCtx->cfg_ini->mcastBcastFilterSetting; + spin_unlock(&pHddCtx->filter_lock); //Configure FW with new setting if (pHddCtx->hdd_wlan_suspended) @@ -8734,11 +8743,22 @@ static int __iw_clear_dynamic_mcbc_filter(struct net_device *dev, wlanRxpFilterParam->configuredMcstBcstFilterSetting = pHddCtx->configuredMcastBcastFilter; wlanRxpFilterParam->setMcstBcstFilter = TRUE; + /* Fwr expect offload needs to clear before set */ + hdd_conf_hostoffload(pAdapter, FALSE); + spin_lock(&pHddCtx->filter_lock); + pHddCtx->configuredMcastBcastFilter = + pHddCtx->cfg_ini->mcastBcastFilterSetting; + spin_unlock(&pHddCtx->filter_lock); + + if (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid) + { + pHddCtx->sus_res_mcastbcast_filter = + pHddCtx->cfg_ini->mcastBcastFilterSetting; + } hdd_conf_hostoffload(pAdapter, TRUE); wlanRxpFilterParam->configuredMcstBcstFilterSetting = pHddCtx->configuredMcastBcastFilter; - if (eHAL_STATUS_SUCCESS != sme_ConfigureRxpFilter(WLAN_HDD_GET_HAL_CTX(pAdapter), wlanRxpFilterParam)) @@ -8750,15 +8770,8 @@ static int __iw_clear_dynamic_mcbc_filter(struct net_device *dev, return -EINVAL; } - if (VOS_TRUE == pHddCtx->sus_res_mcastbcast_filter_valid) - { - pHddCtx->sus_res_mcastbcast_filter = - pHddCtx->cfg_ini->mcastBcastFilterSetting; - } - /* mc add list cfg item configuration in fwr */ hdd_mc_addr_list_cfg_config(pHddCtx, true); - } EXIT(); return 0; From ec9f3c0138ae0844620b391d2432bd45d5e58d52 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 16 Dec 2016 13:42:06 -0500 Subject: [PATCH 082/281] sg_write()/bsg_write() is not fit to be called under KERNEL_DS Both damn things interpret userland pointers embedded into the payload; worse, they are actually traversing those. Leaving aside the bad API design, this is very much _not_ safe to call with KERNEL_DS. Bail out early if that happens. Change-Id: I5d9de7edf05dec142138a1d49b9025cb017340d0 Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- block/bsg.c | 3 +++ drivers/scsi/sg.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/block/bsg.c b/block/bsg.c index 420a5a9f1b23..76801e57f556 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -675,6 +675,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) dprintk("%s: write %Zd bytes\n", bd->name, count); + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + bsg_set_block(bd, file); bytes_written = 0; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8d92436820dc..59efcbb9e0b2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -568,6 +568,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) sg_io_hdr_t *hp; unsigned char cmnd[MAX_COMMAND_SIZE]; + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n", From b293bbc2ea29dc0ddf4612efb33498e6f4e8eb55 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Tue, 12 Jul 2016 16:01:21 -0700 Subject: [PATCH 083/281] mdss: move to a kthread for vsync_retire_work_handler vsync_retire_work_handler is in the critical display path and should never be delayed because of other non-FIFO work. bug 30115868 Change-Id: Ic97744a81198ff303f9c87e1cf7c2468b4356a25 --- drivers/video/msm/mdss/mdss_mdp.h | 5 +++++ drivers/video/msm/mdss/mdss_mdp_overlay.c | 23 +++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h index 7b637889af6a..2dab43eabfba 100644 --- a/drivers/video/msm/mdss/mdss_mdp.h +++ b/drivers/video/msm/mdss/mdss_mdp.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "mdss.h" #include "mdss_mdp_hwio.h" @@ -508,6 +509,10 @@ struct mdss_overlay_private { int retire_cnt; bool kickoff_released; u32 cursor_ndx[2]; + + struct kthread_worker worker; + struct kthread_work vsync_work; + struct task_struct *thread; }; struct mdss_mdp_commit_cb { diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index fc9b14c7ba9d..854611a2f68e 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -4123,13 +4123,13 @@ static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t) } mdp5_data = mfd_to_mdp5_data(mfd); - schedule_work(&mdp5_data->retire_work); + queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work); } -static void __vsync_retire_work_handler(struct work_struct *work) +static void __vsync_retire_work_handler(struct kthread_work *work) { struct mdss_overlay_private *mdp5_data = - container_of(work, typeof(*mdp5_data), retire_work); + container_of(work, typeof(*mdp5_data), vsync_work); if (!mdp5_data->ctl || !mdp5_data->ctl->mfd) return; @@ -4217,6 +4217,7 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); char name[24]; + struct sched_param param = { .sched_priority = 5 }; snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index); mdp5_data->vsync_timeline = sw_sync_timeline_create(name); @@ -4224,12 +4225,26 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) pr_err("cannot vsync create time line"); return -ENOMEM; } + + init_kthread_worker(&mdp5_data->worker); + init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler); + + mdp5_data->thread = kthread_run(kthread_worker_fn, + &mdp5_data->worker, "vsync_retire_work"); + + if (IS_ERR(mdp5_data->thread)) { + pr_err("unable to start vsync thread\n"); + mdp5_data->thread = NULL; + return -ENOMEM; + } + + sched_setscheduler(mdp5_data->thread, SCHED_FIFO, ¶m); + mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence; mdp5_data->vsync_retire_handler.vsync_handler = __vsync_retire_handle_vsync; mdp5_data->vsync_retire_handler.cmd_post_flush = false; - INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler); return 0; } From fc4220cd7fb76b005cfdc544daf69cdc79fbfd2b Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Mon, 25 Jul 2016 19:21:17 -0700 Subject: [PATCH 084/281] kgsl: convert some workqueues to use kthreads adreno_dispatch_work and _kgsl_event_worker are both low-latency low-runtime functions that are in the critical path of GPU rendering. Moving them out of workqueues and into a dedicated FIFO kthread avoids significant jitter. bug 30342017 Change-Id: I5feb4e829064d422b4b9af2acb449afd1f981899 --- drivers/gpu/msm/adreno_dispatch.c | 6 +++--- drivers/gpu/msm/adreno_dispatch.h | 2 +- drivers/gpu/msm/kgsl.c | 14 ++++++++++++++ drivers/gpu/msm/kgsl.h | 6 +++++- drivers/gpu/msm/kgsl_events.c | 8 ++++---- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 3cf69ae385b9..bc860bb48687 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1983,7 +1983,7 @@ static int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev, * * Process expired commands and send new ones. */ -static void adreno_dispatcher_work(struct work_struct *work) +static void adreno_dispatcher_work(struct kthread_work *work) { struct adreno_dispatcher *dispatcher = container_of(work, struct adreno_dispatcher, work); @@ -2058,7 +2058,7 @@ void adreno_dispatcher_schedule(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - queue_work(device->work_queue, &dispatcher->work); + queue_kthread_work(&kgsl_driver.worker, &dispatcher->work); } /** @@ -2353,7 +2353,7 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) if (adreno_is_a304(adreno_dev)) _fault_timer_interval = 400; - INIT_WORK(&dispatcher->work, adreno_dispatcher_work); + init_kthread_work(&dispatcher->work, adreno_dispatcher_work); init_completion(&dispatcher->idle_gate); complete_all(&dispatcher->idle_gate); diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h index c2721ad0c880..d7637146fe91 100644 --- a/drivers/gpu/msm/adreno_dispatch.h +++ b/drivers/gpu/msm/adreno_dispatch.h @@ -72,7 +72,7 @@ struct adreno_dispatcher { atomic_t fault; struct plist_head pending; spinlock_t plist_lock; - struct work_struct work; + struct kthread_work work; struct kobject kobj; struct completion idle_gate; }; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 5a1cf8f2e064..f84c6d8f5764 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4810,6 +4810,8 @@ static void kgsl_core_exit(void) static int __init kgsl_core_init(void) { int result = 0; + struct sched_param param = { .sched_priority = 2 }; + /* alloc major and minor device numbers */ result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX, "kgsl"); @@ -4871,6 +4873,18 @@ static int __init kgsl_core_init(void) kgsl_mmu_set_mmutype(ksgl_mmu_type); + init_kthread_worker(&kgsl_driver.worker); + + kgsl_driver.worker_thread = kthread_run(kthread_worker_fn, + &kgsl_driver.worker, "kgsl_worker_thread"); + + if (IS_ERR(kgsl_driver.worker_thread)) { + pr_err("unable to start kgsl thread\n"); + goto err; + } + + sched_setscheduler(kgsl_driver.worker_thread, SCHED_FIFO, ¶m); + kgsl_events_init(); /* create the memobjs kmem cache */ diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 010f8fcb0ac9..ae9975432473 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -24,6 +24,7 @@ #include #include #include +#include /* The number of memstore arrays limits the number of contexts allowed. * If more contexts are needed, update multiple for MEMSTORE_SIZE @@ -94,6 +95,9 @@ struct kgsl_driver { unsigned int mapped_max; } stats; unsigned int full_cache_threshold; + + struct kthread_worker worker; + struct task_struct *worker_thread; }; extern struct kgsl_driver kgsl_driver; @@ -220,7 +224,7 @@ struct kgsl_event { void *priv; struct list_head node; unsigned int created; - struct work_struct work; + struct kthread_work work; int result; struct kgsl_event_group *group; }; diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index 81fcbe61e0d4..f4bca88f4b41 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -32,7 +32,7 @@ static inline void signal_event(struct kgsl_device *device, { list_del(&event->node); event->result = result; - queue_work(device->events_wq, &event->work); + queue_kthread_work(&kgsl_driver.worker, &event->work); } /** @@ -42,7 +42,7 @@ static inline void signal_event(struct kgsl_device *device, * Each event callback has its own work struct and is run on a event specific * workqeuue. This is the worker that queues up the event callback function. */ -static void _kgsl_event_worker(struct work_struct *work) +static void _kgsl_event_worker(struct kthread_work *work) { struct kgsl_event *event = container_of(work, struct kgsl_event, work); int id = KGSL_CONTEXT_ID(event->context); @@ -261,7 +261,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, event->created = jiffies; event->group = group; - INIT_WORK(&event->work, _kgsl_event_worker); + init_kthread_work(&event->work, _kgsl_event_worker); trace_kgsl_register_event(KGSL_CONTEXT_ID(context), timestamp, func); @@ -276,7 +276,7 @@ int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, if (timestamp_cmp(retired, timestamp) >= 0) { event->result = KGSL_EVENT_RETIRED; - queue_work(device->events_wq, &event->work); + queue_kthread_work(&kgsl_driver.worker, &event->work); spin_unlock(&group->lock); return 0; } From 18e9d86732abe8643434c11221908998da2d3141 Mon Sep 17 00:00:00 2001 From: Rajesh Kemisetti Date: Tue, 31 May 2016 14:41:35 +0530 Subject: [PATCH 085/281] msm: kgsl: Check for integer overflow before allocating memory In _kgsl_sharedmem_page_alloc(), if the requested size is very large then there could be a possibility of integer overflow during memory allocation for scatterlist. To fix this, check for integer overflow condition before allocating the memory. CRs-Fixed: 1005344 Change-Id: I6e0015ab67d6b13fc94d94dafec41788f53820d3 Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/kgsl_sharedmem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 45d20ac3ae37..7a7864bf0593 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -627,6 +627,9 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, memdesc->pagetable = pagetable; memdesc->ops = &kgsl_page_alloc_ops; + /* Check for integer overflow */ + if (sglen_alloc && (sizeof(struct scatterlist) > INT_MAX / sglen_alloc)) + return -EINVAL; memdesc->sg = kgsl_malloc(sglen_alloc * sizeof(struct scatterlist)); if (memdesc->sg == NULL) { From 92776177238fb7b28c4aeefd6709fa0bac600485 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Wed, 27 Apr 2016 18:08:08 +0530 Subject: [PATCH 086/281] msm: kgsl: Check the address range before mapping to GPU Validate the GPU address range for memory mapping request for user allocated buffers before setting the bitmap. This is applicable to the memory mapping specifically when user have used USE_CPU_MAP flag. Change-Id: I7fd30789329939f89b5486d59bdee920616cc6df Signed-off-by: Sunil Khatri --- drivers/gpu/msm/kgsl_mmu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 7a87a3ee27c0..e68e86b5fc98 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -712,6 +712,10 @@ kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, if (kgsl_memdesc_has_guard_page(memdesc)) size += PAGE_SIZE; + if (size < memdesc->size) { + memdesc->size = 0; + return -EINVAL; + } /* * Allocate aligned virtual addresses for iommu. This allows * more efficient pagetable entries if the physical memory @@ -719,8 +723,19 @@ kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, */ if (kgsl_memdesc_use_cpu_map(memdesc)) { + uint64_t end = memdesc->gpuaddr + size; if (memdesc->gpuaddr == 0) return -EINVAL; + + /* + * Validate the GPU address range for memory mapping request + * for user allocated buffers before setting the bitmap. + */ + if ((end >= (KGSL_MMU_GLOBAL_MEM_BASE - SZ_1M)) || + (end < memdesc->gpuaddr)) { + memdesc->gpuaddr = 0; + return -EINVAL; + } bitmap_set(pagetable->mem_bitmap, (int) (memdesc->gpuaddr >> PAGE_SHIFT), (int) (size >> PAGE_SHIFT)); From 3b168f2b8434197bad6f63951bcc7dc2ef17917a Mon Sep 17 00:00:00 2001 From: Ashwanth Goli Date: Fri, 26 Aug 2016 15:03:49 +0530 Subject: [PATCH 087/281] rmnet_data: Changing format specifier to %pK Using %pK instead of %p to hide kernel pointers based on kptr_restrict. Change-Id: I065cff2a9e092d74d0e8c35da6551fab3805e83e Signed-off-by: Ashwanth Goli --- net/rmnet_data/rmnet_data_vnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c index b2a17867cd1c..c1026adb9c4e 100644 --- a/net/rmnet_data/rmnet_data_vnd.c +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -920,7 +920,7 @@ int rmnet_vnd_add_tc_flow(uint32_t id, uint32_t map_flow, uint32_t tc_flow) list_add(&(itm->list), &(dev_conf->flow_head)); write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); - LOGD("Created flow mapping [%s][0x%08X][0x%08X]@%p", + LOGD("Created flow mapping [%s][0x%08X][0x%08X]@%pK", dev->name, itm->map_flow_id, itm->tc_flow_id[0], itm); return RMNET_CONFIG_OK; From 8c3cb941836783167eb9f6460ed0ce51253f1674 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Tue, 13 Sep 2016 15:46:35 +0530 Subject: [PATCH 088/281] msm: kgsl: Validate the input parameter len against zero Validate the len against zero and return with valid error values. Change-Id: I8596c3a6558827d40a6764d0dfddaeb359c2794d Signed-off-by: Sunil Khatri --- drivers/gpu/msm/kgsl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f84c6d8f5764..5285d2603e98 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2902,7 +2902,8 @@ static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry, struct vm_area_struct *vma = NULL; int ret; - if (param->offset != 0 || param->hostptr == 0 + if (param->len == 0 || param->offset != 0 + || param->hostptr == 0 || !KGSL_IS_PAGE_ALIGNED(param->hostptr) || !KGSL_IS_PAGE_ALIGNED(param->len)) return -EINVAL; From 8ddf38ef6ac8a1c6c3a075fbbe3185729d91cd93 Mon Sep 17 00:00:00 2001 From: Srinivasarao P Date: Mon, 3 Oct 2016 12:09:52 +0530 Subject: [PATCH 089/281] ion: use %pk instead of %p which respects kptr_restrict sysctl Hide kernel pointers from unprivileged users by using %pk format-specifier instead of %p. This respects the kptr_restrict sysctl setting which is by default on. So by default %pk will print zeroes as address. echo 1 to kptr_restrict to print proper kernel address. Change-Id: Ia300e3e38b8662afac15edda28959564b05c9367 Signed-off-by: Satyajit Desai Signed-off-by: Srinivasarao P --- drivers/staging/android/ion/ion_cma_heap.c | 6 +++--- drivers/staging/android/ion/ion_cma_secure_heap.c | 10 +++++----- drivers/staging/android/ion/msm/msm_ion.c | 8 ++++---- drivers/staging/android/ion/msm/secure_buffer.c | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index f45e41a33364..b343d6576312 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -102,7 +102,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, /* keep this for memory release */ buffer->priv_virt = info; - dev_dbg(dev, "Allocate buffer %p\n", buffer); + dev_dbg(dev, "Allocate buffer %pK\n", buffer); return 0; free_table: @@ -121,7 +121,7 @@ static void ion_cma_free(struct ion_buffer *buffer) struct ion_cma_buffer_info *info = buffer->priv_virt; struct zone *zone = page_zone(pfn_to_page(PFN_DOWN(info->handle))); - dev_dbg(dev, "Release buffer %p\n", buffer); + dev_dbg(dev, "Release buffer %pK\n", buffer); /* release memory */ dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); mod_zone_page_state(zone, NR_ION_CMA_PAGES, @@ -139,7 +139,7 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, struct device *dev = heap->priv; struct ion_cma_buffer_info *info = buffer->priv_virt; - dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer, + dev_dbg(dev, "Return buffer %pK physical address 0x%pa\n", buffer, &info->handle); *addr = info->handle; diff --git a/drivers/staging/android/ion/ion_cma_secure_heap.c b/drivers/staging/android/ion/ion_cma_secure_heap.c index cc80ecb68dfe..7fa53b2f2564 100644 --- a/drivers/staging/android/ion/ion_cma_secure_heap.c +++ b/drivers/staging/android/ion/ion_cma_secure_heap.c @@ -3,7 +3,7 @@ * * Copyright (C) Linaro 2012 * Author: for ST-Ericsson. - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014,2016 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -491,7 +491,7 @@ static struct ion_secure_cma_buffer_info *__ion_secure_cma_allocate( /* keep this for memory release */ buffer->priv_virt = info; - dev_dbg(sheap->dev, "Allocate buffer %p\n", buffer); + dev_dbg(sheap->dev, "Allocate buffer %pK\n", buffer); return info; err: @@ -575,7 +575,7 @@ static void ion_secure_cma_free(struct ion_buffer *buffer) struct ion_secure_cma_buffer_info *info = buffer->priv_virt; int ret = 0; - dev_dbg(sheap->dev, "Release buffer %p\n", buffer); + dev_dbg(sheap->dev, "Release buffer %pK\n", buffer); if (msm_secure_v2_is_supported()) ret = msm_ion_unsecure_table(info->table); atomic_sub(buffer->size, &sheap->total_allocated); @@ -597,8 +597,8 @@ static int ion_secure_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, container_of(heap, struct ion_cma_secure_heap, heap); struct ion_secure_cma_buffer_info *info = buffer->priv_virt; - dev_dbg(sheap->dev, "Return buffer %p physical address 0x%pa\n", buffer, - &info->phys); + dev_dbg(sheap->dev, "Return buffer %pK physical address 0x%pa\n", + buffer, &info->phys); *addr = info->phys; *len = buffer->size; diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 9f8c1413e682..9ec2d983ae8d 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -714,7 +714,7 @@ long msm_ion_custom_ioctl(struct ion_client *client, } else { handle = ion_import_dma_buf(client, data.flush_data.fd); if (IS_ERR(handle)) { - pr_info("%s: Could not import handle: %p\n", + pr_info("%s: Could not import handle: %pK\n", __func__, handle); return -EINVAL; } @@ -727,8 +727,8 @@ long msm_ion_custom_ioctl(struct ion_client *client, + data.flush_data.length; if (start && check_vaddr_bounds(start, end)) { - pr_err("%s: virtual address %p is out of bounds\n", - __func__, data.flush_data.vaddr); + pr_err("%s: virtual address %pK is out of bounds\n", + __func__, data.flush_data.vaddr); ret = -EINVAL; } else { ret = ion_do_cache_op( diff --git a/drivers/staging/android/ion/msm/secure_buffer.c b/drivers/staging/android/ion/msm/secure_buffer.c index c9f2523eaa40..d09efdda1307 100644 --- a/drivers/staging/android/ion/msm/secure_buffer.c +++ b/drivers/staging/android/ion/msm/secure_buffer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 Google, Inc - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -99,7 +99,7 @@ static int secure_buffer_change_table(struct sg_table *table, int lock) u32 base; u64 tmp = sg_dma_address(sg); WARN((tmp >> 32) & 0xffffffff, - "%s: there are ones in the upper 32 bits of the sg at %p! They will be truncated! Address: 0x%llx\n", + "%s: there are ones in the upper 32 bits of the sg at %pK! They will be truncated! Address: 0x%llx\n", __func__, sg, tmp); if (unlikely(!size || (size % V2_CHUNK_SIZE))) { WARN(1, From 34ca16410cd8b535e928539b863a4a255d7445ca Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Thu, 17 Sep 2015 12:02:47 -0600 Subject: [PATCH 090/281] msm: kgsl: Verify the pointer isn't NULL before using it for kref Probably overkill, but ensure that the struct pointer we are going to dereference to send into kref calls is valid before we dereference. Change-Id: I308176df9f7476a2a9f1357612381a93160ad698 Signed-off-by: Carter Cooper --- drivers/gpu/msm/kgsl.c | 10 +++++----- drivers/gpu/msm/kgsl.h | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 5285d2603e98..f6b69bed0fca 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1370,16 +1370,15 @@ kgsl_sharedmem_region_empty(struct kgsl_process_private *private, static inline struct kgsl_mem_entry * __must_check kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id) { - int result = 0; + int result; struct kgsl_mem_entry *entry; spin_lock(&process->mem_lock); entry = idr_find(&process->mem_idr, id); - if (entry) - result = kgsl_mem_entry_get(entry); + result = kgsl_mem_entry_get(entry); spin_unlock(&process->mem_lock); - if (!result) + if (result == 0) return NULL; return entry; } @@ -3937,7 +3936,8 @@ kgsl_mmap_memstore(struct kgsl_device *device, struct vm_area_struct *vma) static void kgsl_gpumem_vm_open(struct vm_area_struct *vma) { struct kgsl_mem_entry *entry = vma->vm_private_data; - if (!kgsl_mem_entry_get(entry)) + + if (kgsl_mem_entry_get(entry) == 0) vma->vm_private_data = NULL; } diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index ae9975432473..2839dee3c287 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -401,13 +401,16 @@ static inline int timestamp_cmp(unsigned int a, unsigned int b) static inline int kgsl_mem_entry_get(struct kgsl_mem_entry *entry) { - return kref_get_unless_zero(&entry->refcount); + if (entry) + return kref_get_unless_zero(&entry->refcount); + return 0; } static inline void kgsl_mem_entry_put(struct kgsl_mem_entry *entry) { - kref_put(&entry->refcount, kgsl_mem_entry_destroy); + if (entry) + kref_put(&entry->refcount, kgsl_mem_entry_destroy); } /* From 5457dd1589ff6669c0bc975f21ecbede35b78c56 Mon Sep 17 00:00:00 2001 From: Sudeep Yedalapure Date: Wed, 2 Nov 2016 16:26:24 +0530 Subject: [PATCH 091/281] msm: kgsl: Fix overflow in sharedmem cache range operation function There could be possibility of integer overflow on adding size with maximum offset bytes and result in a value smaller than maximum memdesc size. CRs-Fixed: 1082914 Change-Id: Ie66b3a8ca2ca418a4a52f65987266b8d580c121f Signed-off-by: Sudeep Yedalapure --- drivers/gpu/msm/kgsl_sharedmem.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 7a7864bf0593..426ca1eb7fbc 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -539,10 +539,17 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, size_t offset, void *addr = (memdesc->hostptr) ? memdesc->hostptr : (void *) memdesc->useraddr; - /* Make sure that size is non-zero */ - if (!size) + if (size == 0 || size > UINT_MAX) return -EINVAL; + /* Make sure that the offset + size does not overflow */ + if ((offset + size < offset) || (offset + size < size)) + return -ERANGE; + + /* Make sure the offset + size do not overflow the address */ + if ((addr + offset + size) < addr) + return -ERANGE; + /* Check that offset+length does not exceed memdesc->size */ if ((offset + size) > memdesc->size) return -ERANGE; From fa4298180b810cf7f93fe7223500df36f832f29f Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 31 May 2016 11:24:22 -0600 Subject: [PATCH 092/281] msm: kgsl: Reserve a context ID slot but don't populate immediately When creating a context allocate an ID but don't populate the slot with the context pointer until we are done setup up the rest of the process. This avoids a race if somebody tries to free the same identifier before the create operation is complete. Change-Id: Ic0dedbadca5b4cc4ce567afad48a33078b549439 Signed-off-by: Jordan Crouse Signed-off-by: Sudeep Yedalapure --- drivers/gpu/msm/kgsl.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f6b69bed0fca..3ea163711b35 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -519,21 +519,18 @@ void kgsl_context_dump(struct kgsl_context *context) EXPORT_SYMBOL(kgsl_context_dump); /* Allocate a new context ID */ -int _kgsl_get_context_id(struct kgsl_device *device, - struct kgsl_context *context) +int _kgsl_get_context_id(struct kgsl_device *device) { int id; idr_preload(GFP_KERNEL); write_lock(&device->context_lock); - id = idr_alloc(&device->context_idr, context, 1, + /* Allocate the slot but don't put a pointer in it yet */ + id = idr_alloc(&device->context_idr, NULL, 1, KGSL_MEMSTORE_MAX, GFP_NOWAIT); write_unlock(&device->context_lock); idr_preload_end(); - if (id > 0) - context->id = id; - return id; } @@ -557,7 +554,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, char name[64]; int ret = 0, id; - id = _kgsl_get_context_id(device, context); + id = _kgsl_get_context_id(device); if (id == -ENOSPC) { /* * Before declaring that there are no contexts left try @@ -568,7 +565,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, mutex_unlock(&device->mutex); flush_workqueue(device->events_wq); mutex_lock(&device->mutex); - id = _kgsl_get_context_id(device, context); + id = _kgsl_get_context_id(device); } if (id < 0) { @@ -580,6 +577,8 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, return id; } + context->id = id; + kref_init(&context->refcount); /* * Get a refernce to the process private so its not destroyed, until @@ -2584,6 +2583,12 @@ long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, goto done; } trace_kgsl_context_create(dev_priv->device, context, param->flags); + + /* Commit the pointer to the context in context_idr */ + write_lock(&device->context_lock); + idr_replace(&device->context_idr, context, context->id); + write_unlock(&device->context_lock); + param->drawctxt_id = context->id; done: mutex_unlock(&device->mutex); From edf394ec144428a9f626461e46341dafcf0006d5 Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Thu, 22 Oct 2015 13:32:11 -0700 Subject: [PATCH 093/281] mm: cma: fix incorrect type conversion for size during dma allocation. This was found during userspace fuzzing test when a large size dma cma allocation is made by driver(like ion) through userspace. show_stack+0x10/0x1c dump_stack+0x74/0xc8 kasan_report_error+0x2b0/0x408 kasan_report+0x34/0x40 __asan_storeN+0x15c/0x168 memset+0x20/0x44 __dma_alloc_coherent+0x114/0x18c Change-Id: Ia0c4def2ec27ec56e9faf43ed1b8012381e3b253 Signed-off-by: Rohit Vaswani Acked-by: Greg Kroah-Hartman Cc: Marek Szyprowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-commit: 67a2e213e7e937c41c52ab5bc46bf3f4de469f6e Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [shashim@codeaurora.org: replace %p by %pK in print format] Signed-off-by: Shiraz Hashim --- drivers/base/dma-contiguous.c | 4 ++-- include/linux/dma-contiguous.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 8f6c6238fe7e..e9edf1b2ef7a 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -589,7 +589,7 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count) * global one. Requires architecture specific get_dev_cma_area() helper * function. */ -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int align) { unsigned long mask, pfn = 0, pageno, start = 0; @@ -604,7 +604,7 @@ unsigned long dma_alloc_from_contiguous(struct device *dev, int count, if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; - pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma, + pr_debug("%s(cma %pK, count %zu, align %d)\n", __func__, (void *)cma, count, align); if (!count) diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h index 9e6fee91bae4..d8d124e22859 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -117,7 +117,7 @@ static inline int dma_declare_contiguous_reserved(struct device *dev, return ret; } -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int order); bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, int count); @@ -136,7 +136,7 @@ int dma_declare_contiguous(struct device *dev, phys_addr_t size, } static inline -unsigned long dma_alloc_from_contiguous(struct device *dev, int count, +unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int order) { return 0; From 9eadc872a5a515c766f217a03a191728e8a7de30 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 5 Jan 2017 14:37:11 -0800 Subject: [PATCH 094/281] mnt: remount should propagate to slaves of slaves propagate_remount was not accounting for the slave mounts of other slave mounts, leading to some namespaces not recieving the remount information. Signed-off-by: Daniel Rosenberg Bug: 33731928 Change-Id: Idc9e8c2ed126a4143229fc23f10a959c2d0a3854 --- fs/pnode.c | 27 +++++++++++++++++++++------ fs/pnode.h | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/fs/pnode.c b/fs/pnode.c index 2ef946f51a11..46a71f920a69 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -360,16 +360,31 @@ int propagate_umount(struct list_head *list) return 0; } -int propagate_remount(struct mount *mnt) { - struct mount *m; +/* + * Iterates over all slaves, and slaves of slaves. + */ +static struct mount *next_descendent(struct mount *root, struct mount *cur) +{ + if (!IS_MNT_NEW(cur) && !list_empty(&cur->mnt_slave_list)) + return first_slave(cur); + do { + if (cur->mnt_slave.next != &cur->mnt_master->mnt_slave_list) + return next_slave(cur); + cur = cur->mnt_master; + } while (cur != root); + return NULL; +} + +void propagate_remount(struct mount *mnt) +{ + struct mount *m = mnt; struct super_block *sb = mnt->mnt.mnt_sb; - int ret = 0; if (sb->s_op->copy_mnt_data) { - for (m = first_slave(mnt); m->mnt_slave.next != &mnt->mnt_slave_list; m = next_slave(m)) { + m = next_descendent(mnt, m); + while (m) { sb->s_op->copy_mnt_data(m->mnt.data, mnt->mnt.data); + m = next_descendent(mnt, m); } } - - return ret; } diff --git a/fs/pnode.h b/fs/pnode.h index ae8d67a9e962..b0709096de7c 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -36,7 +36,7 @@ int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, struct list_head *); int propagate_umount(struct list_head *); int propagate_mount_busy(struct mount *, int); -int propagate_remount(struct mount *); +void propagate_remount(struct mount *); void mnt_release_group_id(struct mount *); int get_dominating_id(struct mount *mnt, const struct path *root); unsigned int mnt_get_count(struct mount *mnt); From 11175d35d07f12df282134b7d43d0ce14c84482d Mon Sep 17 00:00:00 2001 From: desaishivam26 Date: Thu, 12 Jan 2017 18:13:24 +0530 Subject: [PATCH 095/281] defconfig: Disable CORE_CTL_HELPER We don't use core_ctl in any of these devices Change-Id: I2ee1d8f9939d041348ea5e27a04c2050e403119c --- arch/arm/configs/harpia_defconfig | 2 +- arch/arm/configs/lux_defconfig | 2 +- arch/arm/configs/merlin_defconfig | 2 +- arch/arm/configs/osprey_defconfig | 2 +- arch/arm/configs/surnia_defconfig | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/configs/harpia_defconfig b/arch/arm/configs/harpia_defconfig index 72b7cf0f407e..4f0d1c656d41 100644 --- a/arch/arm/configs/harpia_defconfig +++ b/arch/arm/configs/harpia_defconfig @@ -3345,7 +3345,7 @@ CONFIG_MSM_XPU_ERR_FATAL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set CONFIG_QCOM_EARLY_RANDOM=y # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y CONFIG_MEM_SHARE_QMI_SERVICE=y diff --git a/arch/arm/configs/lux_defconfig b/arch/arm/configs/lux_defconfig index 5568e24ae81d..deef1e479474 100644 --- a/arch/arm/configs/lux_defconfig +++ b/arch/arm/configs/lux_defconfig @@ -3342,7 +3342,7 @@ CONFIG_MSM_XPU_ERR_FATAL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set CONFIG_QCOM_EARLY_RANDOM=y # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set # CONFIG_MSM_PERFORMANCE is not set CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_BOOTINFO=y diff --git a/arch/arm/configs/merlin_defconfig b/arch/arm/configs/merlin_defconfig index a455c9f3767a..7d22560508b7 100644 --- a/arch/arm/configs/merlin_defconfig +++ b/arch/arm/configs/merlin_defconfig @@ -3330,7 +3330,7 @@ CONFIG_MSM_XPU_ERR_FATAL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set CONFIG_QCOM_EARLY_RANDOM=y # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set # CONFIG_MSM_PERFORMANCE is not set CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_BOOTINFO=y diff --git a/arch/arm/configs/osprey_defconfig b/arch/arm/configs/osprey_defconfig index 9e4bc5138d51..16facee5e911 100644 --- a/arch/arm/configs/osprey_defconfig +++ b/arch/arm/configs/osprey_defconfig @@ -3344,7 +3344,7 @@ CONFIG_MSM_XPU_ERR_FATAL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set CONFIG_QCOM_EARLY_RANDOM=y # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y CONFIG_MEM_SHARE_QMI_SERVICE=y diff --git a/arch/arm/configs/surnia_defconfig b/arch/arm/configs/surnia_defconfig index b97be818bdf6..803d989b03d0 100644 --- a/arch/arm/configs/surnia_defconfig +++ b/arch/arm/configs/surnia_defconfig @@ -3317,7 +3317,7 @@ CONFIG_MSM_XPU_ERR_FATAL=y # CONFIG_MSM_SYSTEM_HEALTH_MONITOR is not set CONFIG_QCOM_EARLY_RANDOM=y # CONFIG_MSM_PACMAN is not set -CONFIG_MSM_CORE_CTL_HELPER=y +# CONFIG_MSM_CORE_CTL_HELPER is not set CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=y CONFIG_MEM_SHARE_QMI_SERVICE=y From dcfe7037c56a9739b89db36c8d5a50293b5bd4f3 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 18 Nov 2016 22:13:00 +0100 Subject: [PATCH 096/281] UPSTREAM: l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind() (cherry picked from commit 32c231164b762dddefa13af5a0101032c70b50ef) Lock socket before checking the SOCK_ZAPPED flag in l2tp_ip6_bind(). Without lock, a concurrent call could modify the socket flags between the sock_flag(sk, SOCK_ZAPPED) test and the lock_sock() call. This way, a socket could be inserted twice in l2tp_ip6_bind_table. Releasing it would then leave a stale pointer there, generating use-after-free errors when walking through the list or modifying adjacent entries. BUG: KASAN: use-after-free in l2tp_ip6_close+0x22e/0x290 at addr ffff8800081b0ed8 Write of size 8 by task syz-executor/10987 CPU: 0 PID: 10987 Comm: syz-executor Not tainted 4.8.0+ #39 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 ffff880031d97838 ffffffff829f835b ffff88001b5a1640 ffff8800081b0ec0 ffff8800081b15a0 ffff8800081b6d20 ffff880031d97860 ffffffff8174d3cc ffff880031d978f0 ffff8800081b0e80 ffff88001b5a1640 ffff880031d978e0 Call Trace: [] dump_stack+0xb3/0x118 lib/dump_stack.c:15 [] kasan_object_err+0x1c/0x70 mm/kasan/report.c:156 [< inline >] print_address_description mm/kasan/report.c:194 [] kasan_report_error+0x1f6/0x4d0 mm/kasan/report.c:283 [< inline >] kasan_report mm/kasan/report.c:303 [] __asan_report_store8_noabort+0x3e/0x40 mm/kasan/report.c:329 [< inline >] __write_once_size ./include/linux/compiler.h:249 [< inline >] __hlist_del ./include/linux/list.h:622 [< inline >] hlist_del_init ./include/linux/list.h:637 [] l2tp_ip6_close+0x22e/0x290 net/l2tp/l2tp_ip6.c:239 [] inet_release+0xed/0x1c0 net/ipv4/af_inet.c:415 [] inet6_release+0x50/0x70 net/ipv6/af_inet6.c:422 [] sock_release+0x8d/0x1d0 net/socket.c:570 [] sock_close+0x16/0x20 net/socket.c:1017 [] __fput+0x28c/0x780 fs/file_table.c:208 [] ____fput+0x15/0x20 fs/file_table.c:244 [] task_work_run+0xf9/0x170 [] do_exit+0x85e/0x2a00 [] do_group_exit+0x108/0x330 [] get_signal+0x617/0x17a0 kernel/signal.c:2307 [] do_signal+0x7f/0x18f0 [] exit_to_usermode_loop+0xbf/0x150 arch/x86/entry/common.c:156 [< inline >] prepare_exit_to_usermode arch/x86/entry/common.c:190 [] syscall_return_slowpath+0x1a0/0x1e0 arch/x86/entry/common.c:259 [] entry_SYSCALL_64_fastpath+0xc4/0xc6 Object at ffff8800081b0ec0, in cache L2TP/IPv6 size: 1448 Allocated: PID = 10987 [ 1116.897025] [] save_stack_trace+0x16/0x20 [ 1116.897025] [] save_stack+0x46/0xd0 [ 1116.897025] [] kasan_kmalloc+0xad/0xe0 [ 1116.897025] [] kasan_slab_alloc+0x12/0x20 [ 1116.897025] [< inline >] slab_post_alloc_hook mm/slab.h:417 [ 1116.897025] [< inline >] slab_alloc_node mm/slub.c:2708 [ 1116.897025] [< inline >] slab_alloc mm/slub.c:2716 [ 1116.897025] [] kmem_cache_alloc+0xc8/0x2b0 mm/slub.c:2721 [ 1116.897025] [] sk_prot_alloc+0x69/0x2b0 net/core/sock.c:1326 [ 1116.897025] [] sk_alloc+0x38/0xae0 net/core/sock.c:1388 [ 1116.897025] [] inet6_create+0x2d7/0x1000 net/ipv6/af_inet6.c:182 [ 1116.897025] [] __sock_create+0x37b/0x640 net/socket.c:1153 [ 1116.897025] [< inline >] sock_create net/socket.c:1193 [ 1116.897025] [< inline >] SYSC_socket net/socket.c:1223 [ 1116.897025] [] SyS_socket+0xef/0x1b0 net/socket.c:1203 [ 1116.897025] [] entry_SYSCALL_64_fastpath+0x23/0xc6 Freed: PID = 10987 [ 1116.897025] [] save_stack_trace+0x16/0x20 [ 1116.897025] [] save_stack+0x46/0xd0 [ 1116.897025] [] kasan_slab_free+0x71/0xb0 [ 1116.897025] [< inline >] slab_free_hook mm/slub.c:1352 [ 1116.897025] [< inline >] slab_free_freelist_hook mm/slub.c:1374 [ 1116.897025] [< inline >] slab_free mm/slub.c:2951 [ 1116.897025] [] kmem_cache_free+0xc8/0x330 mm/slub.c:2973 [ 1116.897025] [< inline >] sk_prot_free net/core/sock.c:1369 [ 1116.897025] [] __sk_destruct+0x32b/0x4f0 net/core/sock.c:1444 [ 1116.897025] [] sk_destruct+0x44/0x80 net/core/sock.c:1452 [ 1116.897025] [] __sk_free+0x53/0x220 net/core/sock.c:1460 [ 1116.897025] [] sk_free+0x23/0x30 net/core/sock.c:1471 [ 1116.897025] [] sk_common_release+0x28c/0x3e0 ./include/net/sock.h:1589 [ 1116.897025] [] l2tp_ip6_close+0x1fe/0x290 net/l2tp/l2tp_ip6.c:243 [ 1116.897025] [] inet_release+0xed/0x1c0 net/ipv4/af_inet.c:415 [ 1116.897025] [] inet6_release+0x50/0x70 net/ipv6/af_inet6.c:422 [ 1116.897025] [] sock_release+0x8d/0x1d0 net/socket.c:570 [ 1116.897025] [] sock_close+0x16/0x20 net/socket.c:1017 [ 1116.897025] [] __fput+0x28c/0x780 fs/file_table.c:208 [ 1116.897025] [] ____fput+0x15/0x20 fs/file_table.c:244 [ 1116.897025] [] task_work_run+0xf9/0x170 [ 1116.897025] [] do_exit+0x85e/0x2a00 [ 1116.897025] [] do_group_exit+0x108/0x330 [ 1116.897025] [] get_signal+0x617/0x17a0 kernel/signal.c:2307 [ 1116.897025] [] do_signal+0x7f/0x18f0 [ 1116.897025] [] exit_to_usermode_loop+0xbf/0x150 arch/x86/entry/common.c:156 [ 1116.897025] [< inline >] prepare_exit_to_usermode arch/x86/entry/common.c:190 [ 1116.897025] [] syscall_return_slowpath+0x1a0/0x1e0 arch/x86/entry/common.c:259 [ 1116.897025] [] entry_SYSCALL_64_fastpath+0xc4/0xc6 Memory state around the buggy address: ffff8800081b0d80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff8800081b0e00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >ffff8800081b0e80: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb ^ ffff8800081b0f00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8800081b0f80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== The same issue exists with l2tp_ip_bind() and l2tp_ip_bind_table. Bug: 33753815 Change-Id: I3313e481d3cdc4bc2c5f898f5ef933dbaf85374b Fixes: c51ce49735c1 ("l2tp: fix oops in L2TP IP sockets for connect() AF_UNSPEC case") Reported-by: Baozeng Ding Reported-by: Andrey Konovalov Tested-by: Baozeng Ding Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller --- net/l2tp/l2tp_ip.c | 5 +++-- net/l2tp/l2tp_ip6.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 07f8b97f9ae9..81f317f841b4 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -251,8 +251,6 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) int ret; int chk_addr_ret; - if (!sock_flag(sk, SOCK_ZAPPED)) - return -EINVAL; if (addr_len < sizeof(struct sockaddr_l2tpip)) return -EINVAL; if (addr->l2tp_family != AF_INET) @@ -267,6 +265,9 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) read_unlock_bh(&l2tp_ip_lock); lock_sock(sk); + if (!sock_flag(sk, SOCK_ZAPPED)) + goto out; + if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip)) goto out; diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index eadfb3031ed2..7c1a288f0b20 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -266,8 +266,6 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) int addr_type; int err; - if (!sock_flag(sk, SOCK_ZAPPED)) - return -EINVAL; if (addr->l2tp_family != AF_INET6) return -EINVAL; if (addr_len < sizeof(*addr)) @@ -293,6 +291,9 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) lock_sock(sk); err = -EINVAL; + if (!sock_flag(sk, SOCK_ZAPPED)) + goto out_unlock; + if (sk->sk_state != TCP_CLOSE) goto out_unlock; From fcc46393d35325949f06e54646d5ee5b889d4bfe Mon Sep 17 00:00:00 2001 From: Puja Gupta Date: Mon, 16 Jan 2017 15:56:27 -0800 Subject: [PATCH 097/281] soc: qcom: pil: Fix kernel pointer leak Replace WARN with pr_warn so that stack trace is not printed with the message. CRs-Fixed: 1111653 Change-Id: Id1c7bbe8a528199261455ba7901e9df81913aef8 Signed-off-by: Puja Gupta --- drivers/soc/qcom/subsystem_restart.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 355aa147af20..66e0fe479b1b 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -883,8 +883,9 @@ int subsystem_restart_dev(struct subsys_device *dev) pr_info("Restart sequence requested for %s, restart_level = %s.\n", name, restart_levels[dev->restart_level]); - if (WARN(disable_restart_work == DISABLE_SSR, - "subsys-restart: Ignoring restart request for %s.\n", name)) { + if (disable_restart_work == DISABLE_SSR) { + pr_warn("subsys-restart: Ignoring restart request for %s.\n", + name); return 0; } From 6476eb16ac5eb7374ce629ed3a87c50b9d9e4e38 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Wed, 9 Nov 2016 11:00:56 +0800 Subject: [PATCH 098/281] ASoC: msm: q6dspv2: fix potentional information leak The heap buffer pointed to out_buffer and in_buffer are allocated but uninitlalized. It may cause information leak. Change to kzalloc instead of kmalloc when allocating kernel buffers to avoid information leak. CRs-Fixed: 1087020 Change-Id: I6f9b7a630158355a7f920dcf9cfffe537b1c6a85 Signed-off-by: Meng Wang --- sound/soc/msm/qdsp6v2/q6asm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index bc4a0cb86906..31bd1d7f5657 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -309,12 +309,12 @@ static void config_debug_fs_write(struct audio_buffer *ab) } static void config_debug_fs_init(void) { - out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL); + out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL); if (out_buffer == NULL) { pr_err("%s: kmalloc() for out_buffer failed\n", __func__); goto outbuf_fail; } - in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL); + in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL); if (in_buffer == NULL) { pr_err("%s: kmalloc() for in_buffer failed\n", __func__); goto inbuf_fail; From 3361b84a2d924c706e98162c7096c3f0f7c63497 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Wed, 11 Jan 2017 10:34:46 +0800 Subject: [PATCH 099/281] ASoC: qdsp6v2: fix potential bug of infinite loop When variable bufsz equals to 0, there would be infinite loop at q6asm_audio_client_buf_alloc. Fix the potential bug by checking bufsz beforehand. CRs-Fixed: 1072280 Change-Id: I13850031e621dff92b9ad759375964b8cc5cce67 Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/q6afe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 0400e1dca08a..49406298df73 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2513,8 +2513,9 @@ int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir, struct afe_audio_buffer *buf; size_t len; - if (!(ac) || ((dir != IN) && (dir != OUT))) { - pr_err("%s: ac %pK dir %d\n", __func__, ac, dir); + if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) { + pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz, + dir); return -EINVAL; } From b8b4e659b200f878f26a88e2a8d6c3556bbd3506 Mon Sep 17 00:00:00 2001 From: VijayaKumar T M Date: Mon, 16 Jan 2017 11:42:34 +0530 Subject: [PATCH 100/281] msm: cpp: Fix issue in updating frame info pointer in compact ioctl The userspace pointer is directly accessed/de-referenced in kernel space. This causes device crash during camera stability runs. Copy the v4l2ioctl and cpp frame info userspace pointer to kernel space and access/update the individual data. Change-Id: Ic7829edc8464b91ccd8315e3b96f8c283ac15a32 Signed-off-by: Krishna Srinivas Kundurthi Signed-off-by: VijayaKumar T M --- .../media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index eeafe6d66900..ed401c50cb46 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -305,7 +305,7 @@ static uint32_t msm_cpp_read(void __iomem *cpp_base) uint32_t tmp, retry = 0; do { tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); - } while (((tmp & 0x2) == 0x0) && (retry++ < 10)) ; + } while (((tmp & 0x2) == 0x0) && (retry++ < 10)); if (retry < 10) { tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA); CPP_DBG("Read data: 0%x\n", tmp); @@ -1802,8 +1802,14 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, struct msm_camera_v4l2_ioctl_t *ioctl_ptr) { struct msm_cpp_frame_info_t *frame = NULL; + struct msm_cpp_frame_info_t k_frame_info; int32_t rc = 0; + if (copy_from_user(&k_frame_info, + (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(k_frame_info))) + return -EFAULT; + frame = msm_cpp_get_frame(ioctl_ptr); if (!frame) { pr_err("%s: Error allocating frame\n", __func__); @@ -1814,7 +1820,7 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, ioctl_ptr->trans_code = rc; - if (copy_to_user((void __user *)frame->status, &rc, + if (copy_to_user((void __user *)k_frame_info.status, &rc, sizeof(int32_t))) pr_err("error cannot copy error\n"); From 60c721604bf771b0231eb4b6097b9d608a66d4d1 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Sat, 17 Oct 2015 22:57:06 -0400 Subject: [PATCH 101/281] ext4: fix potential use after free in __ext4_journal_stop There is a use-after-free possibility in __ext4_journal_stop() in the case that we free the handle in the first jbd2_journal_stop() because we're referencing handle->h_err afterwards. This was introduced in 9705acd63b125dee8b15c705216d7186daea4625 and it is wrong. Fix it by storing the handle->h_err value beforehand and avoid referencing potentially freed handle. Fixes: 9705acd63b125dee8b15c705216d7186daea4625 Signed-off-by: Lukas Czerner Reviewed-by: Andreas Dilger Cc: stable@vger.kernel.org (cherry picked from commit 5f83c16464dffcf535b261fddcdc8734625f28d6) Change-Id: I8b3bd278f4cae62877e32256da1a5f8cbaaff1be --- fs/ext4/ext4_jbd2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 1be3996b5942..3517d5af2574 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -75,8 +75,14 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) ext4_put_nojournal(handle); return 0; } - sb = handle->h_transaction->t_journal->j_private; + err = handle->h_err; + if (!handle->h_transaction) { + rc = jbd2_journal_stop(handle); + return err ? err : rc; + } + + sb = handle->h_transaction->t_journal->j_private; rc = jbd2_journal_stop(handle); if (!err) From b065051279123ada88b484f9505c24dce6cf7cd4 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Wed, 25 Jan 2017 16:35:51 -0500 Subject: [PATCH 102/281] lowmemorykiller: account for unevictable pages Adapted from caf/aosp-new/android-msm-angler-3.10-nougat ----------------- lowmemorykiller was not taking into account unevictable pages when deciding what level to kill. If significant amounts of memory were pinned, this caused lowmemorykiller to effectively stop at a much higher level than it should. bug 31255977 Change-Id: I763ecbfef8c56d65bb8f6147ae810692bd81b6e2 --- drivers/staging/android/lowmemorykiller.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index db5c8faae886..16305a960bd7 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -142,6 +142,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, if (pressure >= 95) { other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -155,6 +156,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -440,6 +442,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) global_page_state(NR_FILE_PAGES)) other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); else other_file = 0; From 3bbd99aecb4b727e24031e7ff6d86b865abb0a7b Mon Sep 17 00:00:00 2001 From: Sachin Bhayare Date: Fri, 18 Nov 2016 12:10:26 +0530 Subject: [PATCH 103/281] msm: mdss: Fix potential deferencing of null pointer While servicing display post processing ioctl for calib data the driver checks if the calibration addr is valid. During this check it deferences the base address for all pipes without checking if the pipe pointer is NULL. This fix adds this check. CRs-Fixed: 1082568 Change-Id: Id8164e3e9a6e5178d14dfce60eccbdb3f7a1b253 Signed-off-by: Naseer Ahmed Signed-off-by: Sachin Bhayare --- drivers/video/msm/mdss/mdss_mdp_pp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c index d53cfaa0bdf1..1ed13e3f8fe5 100644 --- a/drivers/video/msm/mdss/mdss_mdp_pp.c +++ b/drivers/video/msm/mdss/mdss_mdp_pp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -5495,9 +5495,6 @@ static int is_valid_calib_addr(void *addr, u32 operation) int ret = 0; char __iomem *ptr = addr; char __iomem *mixer_base = mdss_res->mixer_intf->base; - char __iomem *rgb_base = mdss_res->rgb_pipes->base; - char __iomem *dma_base = mdss_res->dma_pipes->base; - char __iomem *vig_base = mdss_res->vig_pipes->base; char __iomem *ctl_base = mdss_res->ctl_off->base; char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base; @@ -5529,17 +5526,20 @@ static int is_valid_calib_addr(void *addr, u32 operation) if (ret) goto valid_addr; } - if (ptr >= vig_base) { + if (mdss_res->vig_pipes && + ptr >= mdss_res->vig_pipes->base) { ret = is_valid_calib_vig_addr(ptr); if (ret) goto valid_addr; } - if (ptr >= rgb_base) { + if (mdss_res->rgb_pipes && + ptr >= mdss_res->rgb_pipes->base) { ret = is_valid_calib_rgb_addr(ptr); if (ret) goto valid_addr; } - if (ptr >= dma_base) { + if (mdss_res->dma_pipes && + ptr >= mdss_res->dma_pipes->base) { ret = is_valid_calib_dma_addr(ptr); if (ret) goto valid_addr; From c9a57a9be157bbc433add34d5d7edbbe50229869 Mon Sep 17 00:00:00 2001 From: VijayaKumar T M Date: Thu, 24 Nov 2016 14:35:30 +0530 Subject: [PATCH 104/281] msm: sensor: Validationg function pointers before using them Since IOCTLS can come in any order, validating the actuator function table and methods before accessing them. CRs-Fixed: 1084177 Change-Id: Ic6fce52fdf4d1420c2b707ec9bc9cba045066a13 Signed-off-by: Sureshnaidu Laveti Signed-off-by: VijayaKumar T M --- .../camera_v2/sensor/actuator/msm_actuator.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index 79b0ee0bf373..e50955c14e90 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1323,7 +1323,7 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, { struct msm_actuator_cfg_data *cdata = (struct msm_actuator_cfg_data *)argp; - int32_t rc = 0; + int32_t rc = -EINVAL; mutex_lock(a_ctrl->actuator_mutex); CDBG("Enter\n"); CDBG("%s type %d\n", __func__, cdata->cfgtype); @@ -1336,6 +1336,7 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, case CFG_GET_ACTUATOR_INFO: cdata->is_af_supported = 1; cdata->cfg.cam_name = a_ctrl->cam_name; + rc = 0; break; case CFG_SET_ACTUATOR_INFO: @@ -1345,15 +1346,19 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, break; case CFG_SET_DEFAULT_FOCUS: - rc = a_ctrl->func_tbl->actuator_set_default_focus(a_ctrl, - &cdata->cfg.move); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_set_default_focus) + rc = a_ctrl->func_tbl->actuator_set_default_focus( + a_ctrl, &cdata->cfg.move); if (rc < 0) pr_err("move focus failed %d\n", rc); break; case CFG_MOVE_FOCUS: - rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, - &cdata->cfg.move); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_move_focus) + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, + &cdata->cfg.move); if (rc < 0) pr_err("move focus failed %d\n", rc); break; @@ -1364,8 +1369,10 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, break; case CFG_SET_POSITION: - rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, - &cdata->cfg.setpos); + if (a_ctrl->func_tbl && + a_ctrl->func_tbl->actuator_set_position) + rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, + &cdata->cfg.setpos); if (rc < 0) pr_err("actuator_set_position failed %d\n", rc); break; From 02d42b8982ba7c8a87473cc31eb02e30ed6a7c12 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Thu, 20 Oct 2016 17:34:20 -0700 Subject: [PATCH 105/281] qseecom: check buffer size when loading firmware images Make change in __qseecom_load_fw() and qseecom_load_commonlib_image() to check buffer size before copying img to buffer. CRs-fixed: 1080290 Change-Id: I0f48666ac948a9571e249598ae7cc19df9036b1d Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index e4264c3270f4..aee2f46d3278 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2318,7 +2318,7 @@ static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry) return true; } -static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size) +static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size) { int ret = -1; int i = 0, rc = 0; @@ -2344,14 +2344,21 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size) ehdr = (struct elf32_hdr *)fw_entry->data; num_images = ehdr->e_phnum; release_firmware(fw_entry); + fw_entry = NULL; for (i = 0; i < num_images; i++, phdr++) { memset(fw_name, 0, sizeof(fw_name)); snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i); ret = request_firmware(&fw_entry, fw_name, qseecom.pdev); if (ret) goto err; + if (*fw_size > U32_MAX - fw_entry->size) { + pr_err("QSEE %s app file size overflow\n", appname); + ret = -EINVAL; + goto err; + } *fw_size += fw_entry->size; release_firmware(fw_entry); + fw_entry = NULL; } return ret; err: @@ -2361,8 +2368,9 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size) return ret; } -static int __qseecom_get_fw_data(char *appname, u8 *img_data, - struct qseecom_load_app_ireq *load_req) +static int __qseecom_get_fw_data(const char *appname, u8 *img_data, + uint32_t fw_size, + struct qseecom_load_app_ireq *load_req) { int ret = -1; int i = 0, rc = 0; @@ -2379,12 +2387,19 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data, goto err; } load_req->img_len = fw_entry->size; + if (load_req->img_len > fw_size) { + pr_err("app %s size %zu is larger than buf size %u\n", + appname, fw_entry->size, fw_size); + ret = -EINVAL; + goto err; + } memcpy(img_data_ptr, fw_entry->data, fw_entry->size); img_data_ptr = img_data_ptr + fw_entry->size; load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/ ehdr = (struct elf32_hdr *)fw_entry->data; num_images = ehdr->e_phnum; release_firmware(fw_entry); + fw_entry = NULL; for (i = 0; i < num_images; i++) { snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i); ret = request_firmware(&fw_entry, fw_name, qseecom.pdev); @@ -2392,10 +2407,17 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data, pr_err("Failed to locate blob %s\n", fw_name); goto err; } + if ((fw_entry->size > U32_MAX - load_req->img_len) || + (fw_entry->size + load_req->img_len > fw_size)) { + pr_err("Invalid file size for %s\n", fw_name); + ret = -EINVAL; + goto err; + } memcpy(img_data_ptr, fw_entry->data, fw_entry->size); img_data_ptr = img_data_ptr + fw_entry->size; load_req->img_len += fw_entry->size; release_firmware(fw_entry); + fw_entry = NULL; } return ret; err: @@ -2472,8 +2494,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) if (ret) return ret; - - ret = __qseecom_get_fw_data(appname, img_data, &load_req); + ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req); if (ret) { ret = -EIO; goto exit_free_img_data; @@ -2566,7 +2587,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data) if (ret) return -EIO; - ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req); + ret = __qseecom_get_fw_data("cmnlib", img_data, fw_size, &load_req); if (ret) { ret = -EIO; goto exit_free_img_data; From 4a0c810cdcf80f4120d8674d26162b99398298f1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 19 Sep 2016 17:39:09 +0200 Subject: [PATCH 106/281] BACKPORT: posix_acl: Clear SGID bit when setting file permissions (cherry pick from commit 073931017b49d9458aa351605b43a7e34598caef) When file permissions are modified via chmod(2) and the user is not in the owning group or capable of CAP_FSETID, the setgid bit is cleared in inode_change_ok(). Setting a POSIX ACL via setxattr(2) sets the file permissions as well as the new ACL, but doesn't clear the setgid bit in a similar way; this allows to bypass the check in chmod(2). Fix that. NB: conflicts resolution included extending the change to all visible users of the near deprecated function posix_acl_equiv_mode replaced with posix_acl_update_mode. We did not resolve the ACL leak in this CL, require additional upstream fixes. References: CVE-2016-7097 Reviewed-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: Jan Kara Signed-off-by: Andreas Gruenbacher Bug: 32458736 Change-Id: I19591ad452cc825ac282b3cfd2daaa72aa9a1ac1 --- fs/9p/acl.c | 40 +++++++++++++++++---------------------- fs/btrfs/acl.c | 6 ++---- fs/ext2/acl.c | 12 ++++-------- fs/ext3/acl.c | 12 ++++-------- fs/ext4/acl.c | 12 ++++-------- fs/f2fs/acl.c | 6 ++---- fs/generic_acl.c | 8 ++------ fs/gfs2/acl.c | 11 +++-------- fs/jffs2/acl.c | 9 ++++----- fs/jfs/xattr.c | 6 +++--- fs/ocfs2/acl.c | 18 ++++++------------ fs/posix_acl.c | 31 ++++++++++++++++++++++++++++++ fs/reiserfs/xattr_acl.c | 8 ++------ fs/xfs/xfs_acl.c | 13 +++---------- include/linux/posix_acl.h | 1 + 15 files changed, 88 insertions(+), 105 deletions(-) diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 7af425f53bee..9686c1f17653 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -320,32 +320,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - umode_t mode = inode->i_mode; - retval = posix_acl_equiv_mode(acl, &mode); - if (retval < 0) + struct iattr iattr; + + retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl); + if (retval) goto err_out; - else { - struct iattr iattr; - if (retval == 0) { - /* - * ACL can be represented - * by the mode bits. So don't - * update ACL. - */ - acl = NULL; - value = NULL; - size = 0; - } - /* Updte the mode bits */ - iattr.ia_mode = ((mode & S_IALLUGO) | - (inode->i_mode & ~S_IALLUGO)); - iattr.ia_valid = ATTR_MODE; - /* FIXME should we update ctime ? - * What is the following setxattr update the - * mode ? + if (!acl) { + /* + * ACL can be represented + * by the mode bits. So don't + * update ACL. */ - v9fs_vfs_setattr_dotl(dentry, &iattr); + value = NULL; + size = 0; } + iattr.ia_valid = ATTR_MODE; + /* FIXME should we update ctime ? + * What is the following setxattr update the + * mode ? + */ + v9fs_vfs_setattr_dotl(dentry, &iattr); } break; case ACL_TYPE_DEFAULT: diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 0890c83643e9..d6d53e5e7945 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -118,11 +118,9 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - ret = posix_acl_equiv_mode(acl, &inode->i_mode); - if (ret < 0) + ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (ret) return ret; - if (ret == 0) - acl = NULL; } ret = 0; break; diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 110b6b371a4e..48c3c2d7d261 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -206,15 +206,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); } break; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index dbb5ad59a7fc..bb2f60a62d82 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -205,15 +205,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = CURRENT_TIME_SEC; + ext3_mark_inode_dirty(handle, inode); } break; diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 39a54a0e9fe4..c844f1bfb451 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -211,15 +211,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - if (error == 0) - acl = NULL; - } + inode->i_ctime = ext4_current_time(inode); + ext4_mark_inode_dirty(handle, inode); } break; diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 5b952c05903f..9ae61eca7887 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -228,12 +228,10 @@ static int f2fs_set_acl(struct inode *inode, int type, case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; set_acl_inode(fi, inode->i_mode); - if (error == 0) - acl = NULL; } break; diff --git a/fs/generic_acl.c b/fs/generic_acl.c index b3f3676796d3..21408084c3b3 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -87,14 +87,10 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, goto failed; switch (type) { case ACL_TYPE_ACCESS: - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) goto failed; inode->i_ctime = CURRENT_TIME; - if (error == 0) { - posix_acl_release(acl); - acl = NULL; - } break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) { diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index f69ac0af5496..e7b330ef4dfd 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -268,15 +268,10 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name, if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; - error = posix_acl_equiv_mode(acl, &mode); + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); - if (error <= 0) { - posix_acl_release(acl); - acl = NULL; - - if (error < 0) - return error; - } + if (error) + goto out_release; error = gfs2_set_mode(inode, mode); if (error) diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 223283c30111..9335b8d3cf52 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -243,9 +243,10 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { - umode_t mode = inode->i_mode; - rc = posix_acl_equiv_mode(acl, &mode); - if (rc < 0) + umode_t mode; + + rc = posix_acl_update_mode(inode, &mode, &acl); + if (rc) return rc; if (inode->i_mode != mode) { struct iattr attr; @@ -257,8 +258,6 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (rc < 0) return rc; } - if (rc == 0) - acl = NULL; } break; case ACL_TYPE_DEFAULT: diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 42d67f9757bf..c79b1d7a53e2 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -693,11 +693,11 @@ static int can_set_system_xattr(struct inode *inode, const char *name, return rc; } if (acl) { - rc = posix_acl_equiv_mode(acl, &inode->i_mode); + rc = posix_acl_update_mode(inode, &inode->i_mode, &acl); posix_acl_release(acl); - if (rc < 0) { + if (rc) { printk(KERN_ERR - "posix_acl_equiv_mode returned %d\n", + "posix_acl_update_mode returned %d\n", rc); return rc; } diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 8a404576fb26..2fe643160cf7 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -275,19 +275,13 @@ static int ocfs2_set_acl(handle_t *handle, name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl) { umode_t mode = inode->i_mode; - ret = posix_acl_equiv_mode(acl, &mode); - if (ret < 0) + ret = posix_acl_update_mode(inode, &mode, &acl); + if (ret) + return ret; + ret = ocfs2_acl_set_mode(inode, di_bh, + handle, mode); + if (ret) return ret; - else { - if (ret == 0) - acl = NULL; - - ret = ocfs2_acl_set_mode(inode, di_bh, - handle, mode); - if (ret) - return ret; - - } } break; case ACL_TYPE_DEFAULT: diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 3542f1f814e2..35cc1f40b82d 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -341,6 +341,37 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) return not_equiv; } +/** + * posix_acl_update_mode - update mode in set_acl + * + * Update the file mode when setting an ACL: compute the new file permission + * bits based on the ACL. In addition, if the ACL is equivalent to the new + * file mode, set *acl to NULL to indicate that no ACL should be set. + * + * As with chmod, clear the setgit bit if the caller is not in the owning group + * or capable of CAP_FSETID (see inode_change_ok). + * + * Called from set_acl inode operations. + */ +int posix_acl_update_mode(struct inode *inode, umode_t *mode_p, + struct posix_acl **acl) +{ + umode_t mode = inode->i_mode; + int error; + + error = posix_acl_equiv_mode(*acl, &mode); + if (error < 0) + return error; + if (error == 0) + *acl = NULL; + if (!in_group_p(inode->i_gid) && + !capable_wrt_inode_uidgid(inode, CAP_FSETID)) + mode &= ~S_ISGID; + *mode_p = mode; + return 0; +} +EXPORT_SYMBOL(posix_acl_update_mode); + /* * Modify the ACL for the chmod syscall. */ diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 6c8767fdfc6a..2d73589f37d6 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -286,13 +286,9 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) + error = posix_acl_update_mode(inode, &inode->i_mode, &acl); + if (error) return error; - else { - if (error == 0) - acl = NULL; - } } break; case ACL_TYPE_DEFAULT: diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 306d883d89bc..4f8e4770229c 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -389,16 +389,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name, if (type == ACL_TYPE_ACCESS) { umode_t mode = inode->i_mode; - error = posix_acl_equiv_mode(acl, &mode); - - if (error <= 0) { - posix_acl_release(acl); - acl = NULL; - - if (error < 0) - return error; - } - + error = posix_acl_update_mode(inode, &mode, &acl); + if (error) + goto out_release; error = xfs_set_mode(inode, mode); if (error) goto out_release; diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 7931efe71175..2ae0bba45f12 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -90,6 +90,7 @@ extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *); extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); +extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **); extern struct posix_acl *get_posix_acl(struct inode *, int); extern int set_posix_acl(struct inode *, int, struct posix_acl *); From a7008be4bc61c2580ff087bcc354a4bad12e284d Mon Sep 17 00:00:00 2001 From: Alex Naidis Date: Sat, 21 Jan 2017 16:01:25 +0100 Subject: [PATCH 107/281] ion: Fix permissions on source file The source file ion.c should not be executable. This patch resets the permissions to "644". Change-Id: I66241e3f9967ae3e1fd7519e02e10fc4b2640e1e Signed-off-by: Alex Naidis --- drivers/staging/android/ion/ion.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 drivers/staging/android/ion/ion.c diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c old mode 100755 new mode 100644 From 4aac8528315423eaa4f65a77f4163eefa8a46251 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 4 Oct 2016 09:52:27 +0530 Subject: [PATCH 108/281] UPSTREAM: kernel.h: define u8, s8, u32, etc. limits (cherry pick from commit 89a0714106aac7309c7dfa0f004b39e1e89d2942) Create constants that define the maximum and minimum values representable by the kernel types u8, s8, u16, s16, and so on. Change-Id: I5b3f021c30454e6a6f188c74910d5758ccccccc9 Signed-off-by: Alex Elder Cc: Sage Weil Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Bug: 27299111 Bug: 27297988 Git-commit: 89a0714106aac7309c7dfa0f004b39e1e89d2942 Git-repo: https://android.googlesource.com/kernel/common [schikk@codeaurora.org fixed compilation errors] CRs-Fixed: 1064411 Signed-off-by: Swetha Chikkaboraiah Merged additional same titled patched to prevent redefinition of U8_MAX in lin/qmi_encdec.c Change-Id: I5b3f021c30454e6a6f188c74910d5758ccccccc9 Signed-off-by: Vishnu Vardhan Reddy Naini --- include/linux/kernel.h | 13 +++++++++++++ lib/qmi_encdec.c | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6802ef7149f3..6d0f8600c727 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -29,6 +29,19 @@ #define ULLONG_MAX (~0ULL) #define SIZE_MAX (~(size_t)0) +#define U8_MAX ((u8)~0U) +#define S8_MAX ((s8)(U8_MAX>>1)) +#define S8_MIN ((s8)(-S8_MAX - 1)) +#define U16_MAX ((u16)~0U) +#define S16_MAX ((s16)(U16_MAX>>1)) +#define S16_MIN ((s16)(-S16_MAX - 1)) +#define U32_MAX ((u32)~0U) +#define S32_MAX ((s32)(U32_MAX>>1)) +#define S32_MIN ((s32)(-S32_MAX - 1)) +#define U64_MAX ((u64)~0ULL) +#define S64_MAX ((s64)(U64_MAX>>1)) +#define S64_MIN ((s64)(-S64_MAX - 1)) + #define STACK_MAGIC 0xdeadbeef #define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c index a205a5b719bb..d930aae18e35 100644 --- a/lib/qmi_encdec.c +++ b/lib/qmi_encdec.c @@ -24,7 +24,6 @@ #define TLV_LEN_SIZE sizeof(uint16_t) #define TLV_TYPE_SIZE sizeof(uint8_t) -#define U8_MAX 255 #ifdef CONFIG_QMI_ENCDEC_DEBUG From 006379fc39d09f378da1403e76d2be8d28028092 Mon Sep 17 00:00:00 2001 From: Mallikarjuna Reddy Amireddy Date: Tue, 22 Nov 2016 17:24:46 +0530 Subject: [PATCH 109/281] qseecom: remove entry from qseecom_registered_app_list In an error handling case, the QSEECOM_IOCTL_LOAD_APP_REQ ioctl freed the entry for new TA, but didn't removed it from qseecom_registered_app_list. Make change to remove it. Change-Id: Id681fbf3c923027d3db875d506cbe3f971919a8d Signed-off-by: Zhen Kong Signed-off-by: Mallikarjuna Reddy Amireddy --- drivers/misc/qseecom.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index aee2f46d3278..339cef6ab1f0 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1259,6 +1259,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) struct qseecom_command_scm_resp resp; struct qseecom_check_app_ireq req; struct qseecom_load_app_ireq load_req; + bool first_time = false; /* Copy the relevant information needed for loading the image */ if (copy_from_user(&load_img_req, @@ -1305,6 +1306,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) &qseecom.registered_app_list_lock, flags); ret = 0; } else { + first_time = true; pr_warn("App (%s) does'nt exist, loading apps for first time\n", (char *)(load_img_req.img_name)); /* Get the handle of the shared fd */ @@ -1405,8 +1407,15 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) load_img_req.app_id = app_id; if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) { pr_err("copy_to_user failed\n"); - kzfree(entry); ret = -EFAULT; + if (first_time == true) { + spin_lock_irqsave( + &qseecom.registered_app_list_lock, flags); + list_del(&entry->list); + spin_unlock_irqrestore( + &qseecom.registered_app_list_lock, flags); + kzfree(entry); + } } loadapp_err: From ada43c853003aca842fff5f62f6ea66e9cd6517e Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Wed, 2 Nov 2016 16:49:41 +0530 Subject: [PATCH 110/281] qcom: scm: remove printing input arguments scm_call2 is printing the input arguments if TZ ret value is < 0 leading to information leak. Remove printing input arguments. Change-Id: I21dd6d83fa979aed2c79ebb2c9c8de63a247dded CRs-Fixed: 1076407 Signed-off-by: Swetha Chikkaboraiah --- drivers/soc/qcom/scm.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 938d3bfe6016..c5a6cc8602d1 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -640,10 +640,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) desc->ret[0] = desc->ret[1] = desc->ret[2] = 0; - pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5); - if (scm_version == SCM_ARMV8_64) ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0], desc->args[1], @@ -663,10 +659,8 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); if (ret < 0) - pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5, ret, desc->ret[0], - desc->ret[1], desc->ret[2]); + pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", + x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]); if (arglen > N_REGISTER_ARGS) kfree(desc->extra_arg_buf); From 1af5b7391ea8d340a4a58e502910a4bff0a25b06 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Tue, 4 Oct 2016 12:24:28 -0700 Subject: [PATCH 111/281] drivers: soc: add size checks and update log messages Add size checks to validate minimum size is met. Update log messages to include only relevant information to ensure logs are accurate and useful. Change-Id: Idf76a7d964ec6989a0474d49895e54103f17938b CRs-fixed: 1073129 Signed-off-by: Siena Richard --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 41 ++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index bbc2550e8629..977d2c6dc190 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -216,8 +216,8 @@ static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request, } else if (!strcmp(apr_request->svc_name, VOICE_SVC_MVM_STR)) { apr_handle = prtd->apr_q6_mvm; } else { - pr_err("%s: Invalid service %s\n", __func__, - apr_request->svc_name); + pr_err("%s: Invalid service %.*s\n", __func__, + MAX_APR_SERVICE_NAME_LEN, apr_request->svc_name); ret = -EINVAL; goto done; @@ -331,8 +331,8 @@ static int process_reg_cmd(struct voice_svc_register *apr_reg_svc, svc = VOICE_SVC_CVS_STR; handle = &prtd->apr_q6_cvs; } else { - pr_err("%s: Invalid Service: %s\n", __func__, - apr_reg_svc->svc_name); + pr_err("%s: Invalid Service: %.*s\n", __func__, + MAX_APR_SERVICE_NAME_LEN, apr_reg_svc->svc_name); ret = -EINVAL; goto done; } @@ -358,7 +358,17 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, pr_debug("%s\n", __func__); - data = kmalloc(count, GFP_KERNEL); + /* + * Check if enough memory is allocated to parse the message type. + * Will check there is enough to hold the payload later. + */ + if (count >= sizeof(struct voice_svc_write_msg)) { + data = kmalloc(count, GFP_KERNEL); + } else { + pr_debug("%s: invalid data size\n", __func__); + ret = -EINVAL; + goto done; + } if (data == NULL) { pr_err("%s: data kmalloc failed.\n", __func__); @@ -376,7 +386,7 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, } cmd = data->msg_type; - prtd = (struct voice_svc_prvt *)file->private_data; + prtd = (struct voice_svc_prvt *) file->private_data; if (prtd == NULL) { pr_err("%s: prtd is NULL\n", __func__); @@ -386,9 +396,13 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, switch (cmd) { case MSG_REGISTER: - if (count >= - (sizeof(struct voice_svc_register) + - sizeof(*data))) { + /* + * Check that count reflects the expected size to ensure + * sufficient memory was allocated. Since voice_svc_register + * has a static size, this should be exact. + */ + if (count == (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_register))) { ret = process_reg_cmd( (struct voice_svc_register *)data->payload, prtd); if (!ret) @@ -400,8 +414,13 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, } break; case MSG_REQUEST: - if (count >= (sizeof(struct voice_svc_cmd_request) + - sizeof(*data))) { + /* + * Check that count reflects the expected size to ensure + * sufficient memory was allocated. Since voice_svc_cmd_request + * has a variable size, check the minimum value count must be. + */ + if (count >= (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_cmd_request))) { ret = voice_svc_send_req( (struct voice_svc_cmd_request *)data->payload, prtd); if (!ret) From 38646ee4b90a5cb9cb87f37a50f06ac3acc29f1e Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 18 Nov 2016 10:44:16 -0800 Subject: [PATCH 112/281] BACKPORT: aio: mark AIO pseudo-fs noexec This ensures that do_mmap() won't implicitly make AIO memory mappings executable if the READ_IMPLIES_EXEC personality flag is set. Such behavior is problematic because the security_mmap_file LSM hook doesn't catch this case, potentially permitting an attacker to bypass a W^X policy enforced by SELinux. I have tested the patch on my machine. To test the behavior, compile and run this: #define _GNU_SOURCE #include #include #include #include #include #include #include int main(void) { personality(READ_IMPLIES_EXEC); aio_context_t ctx = 0; if (syscall(__NR_io_setup, 1, &ctx)) err(1, "io_setup"); char cmd[1000]; sprintf(cmd, "cat /proc/%d/maps | grep -F '/[aio]'", (int)getpid()); system(cmd); return 0; } In the output, "rw-s" is good, "rwxs" is bad. Signed-off-by: Jann Horn Signed-off-by: Linus Torvalds (cherry picked from commit 22f6b4d34fcf039c63a94e7670e0da24f8575a5a) Bug: 31711619 Change-Id: I9f2872703bef240d6b82320c744529459bb076dc --- fs/aio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/aio.c b/fs/aio.c index 9798d4edfd8f..0f2c38f29c4a 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -153,6 +154,9 @@ static int aio_setup_ring(struct kioctx *ctx) unsigned long size, populate; int nr_pages; + if (current->personality & READ_IMPLIES_EXEC) + return -EPERM; + /* Compensate for the ring buffer's head/tail overlap entry */ nr_events += 2; /* 1 is required, 2 for good luck */ From 97ff22675c6538716eabc4fd75bd75b7e8d86218 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Wed, 21 Sep 2016 18:34:01 +0530 Subject: [PATCH 113/281] net: ipc_router: fix NULL pointer de-reference issue Fail cases of accept() system call on AF_MSM_IPC socket family causes NULL pointer de-reference of sock structure variable in release operation. Validate the sock structure pointer before using it in release operation. CRs-Fixed: 1068888 Change-Id: I5637e52be59ea9504ea6ae317394bef0c28c7865 Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_socket.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c index 36622993866f..8a2e16eea5bf 100644 --- a/net/ipc_router/ipc_router_socket.c +++ b/net/ipc_router/ipc_router_socket.c @@ -628,10 +628,18 @@ static unsigned int msm_ipc_router_poll(struct file *file, static int msm_ipc_router_close(struct socket *sock) { struct sock *sk = sock->sk; - struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk); + struct msm_ipc_port *port_ptr; int ret; + if (!sk) + return -EINVAL; + lock_sock(sk); + port_ptr = msm_ipc_sk_port(sk); + if (!port_ptr) { + release_sock(sk); + return -EINVAL; + } ret = msm_ipc_router_close_port(port_ptr); msm_ipc_unload_default_node(msm_ipc_sk(sk)->default_node_vote_info); release_sock(sk); From 08036e27eaa40e8b509eacbcb14a610caa841dd3 Mon Sep 17 00:00:00 2001 From: Adrian Salido Date: Thu, 1 Dec 2016 18:07:42 -0800 Subject: [PATCH 114/281] fs/proc/array.c: make safe access to group_leader As mentioned in commit 52ee2dfdd4f51cf422ea6a96a0846dc94244aa37 ("pids: refactor vnr/nr_ns helpers to make them safe"). *_nr_ns helpers used to be buggy. The commit addresses most of the helpers but is missing task_tgid_xxx() Without this protection there is a possible use after free reported by kasan instrumented kernel: ================================================================== BUG: KASAN: use-after-free in task_tgid_nr_ns+0x2c/0x44 at addr *** Read of size 8 by task cat/2472 CPU: 1 PID: 2472 Comm: cat Tainted: **** Hardware name: Google Tegra210 Smaug Rev 1,3+ (DT) Call trace: [] dump_backtrace+0x0/0x17c [] show_stack+0x18/0x24 [] dump_stack+0x94/0x100 [] kasan_report+0x308/0x554 [] __asan_load8+0x20/0x7c [] task_tgid_nr_ns+0x28/0x44 [] proc_pid_status+0x444/0x1080 [] proc_single_show+0x8c/0xdc [] seq_read+0x2e8/0x6f0 [] vfs_read+0xd8/0x1e0 [] SyS_read+0x68/0xd4 Accessing group_leader while holding rcu_lock and using the now safe helpers introduced in the commit mentioned, this race condition is addressed. Signed-off-by: Adrian Salido Change-Id: I4315217922dda375a30a3581c0c1740dda7b531b Bug: 31495866 --- fs/proc/array.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index e90b33123945..f5fa4e703d43 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -168,16 +168,16 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, int g; struct fdtable *fdt = NULL; const struct cred *cred; - pid_t ppid, tpid; + pid_t ppid = 0, tpid = 0; + struct task_struct *leader = NULL; rcu_read_lock(); - ppid = pid_alive(p) ? - task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; - tpid = 0; if (pid_alive(p)) { struct task_struct *tracer = ptrace_parent(p); if (tracer) tpid = task_pid_nr_ns(tracer, ns); + ppid = task_tgid_nr_ns(rcu_dereference(p->real_parent), ns); + leader = p->group_leader; } cred = get_task_cred(p); seq_printf(m, @@ -189,7 +189,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - task_tgid_nr_ns(p, ns), + leader ? task_pid_nr_ns(leader, ns) : 0, pid_nr_ns(pid, ns), ppid, tpid, from_kuid_munged(user_ns, cred->uid), From 9c4cfefa70ed7881dab5b7d8d21a9d65a50beee5 Mon Sep 17 00:00:00 2001 From: Ranjith Kagathi Ananda Date: Wed, 4 Jan 2017 22:43:39 +0530 Subject: [PATCH 115/281] msm: ispif: Remove handling of SD_SHUTDOWN Remove handling of SD_SHUTDOWN to avoid multiple release. Bug: 31243641 Change-Id: I09db8adb766d2e7889443f779a716aaa2f6c09d1 Signed-off-by: Harsh Shah Signed-off-by: Ranjith Kagathi Ananda --- drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index ea8f12ce37ec..0b87bece2db7 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -1351,10 +1351,6 @@ static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, case VIDIOC_MSM_ISPIF_CFG: return msm_ispif_cmd(sd, arg); case MSM_SD_SHUTDOWN: { - struct ispif_device *ispif = - (struct ispif_device *)v4l2_get_subdevdata(sd); - if (ispif && ispif->base) - msm_ispif_release(ispif); return 0; } default: From e396f55e037806eab05b7cdd5f49a326c0daa7a4 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Thu, 15 Aug 2013 15:31:06 -0700 Subject: [PATCH 116/281] netlink: Eliminate kmalloc in netlink dump operation. Following patch stores struct netlink_callback in netlink_sock to avoid allocating and freeing it on every netlink dump msg. Only one dump operation is allowed for a given socket at a time therefore we can safely convert cb pointer to cb struct inside netlink_sock. Change-Id: I376b6feef396010e3ebd98673a30518b62af9425 Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 97 +++++++++++++++++----------------------- net/netlink/af_netlink.h | 3 +- 2 files changed, 44 insertions(+), 56 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c38b79fe1f90..e71320326787 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -497,7 +497,7 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, * for dumps is performed here. A dump is allowed to continue * if at least half the ring is unused. */ - while (nlk->cb != NULL && netlink_dump_space(nlk)) { + while (nlk->cb_running && netlink_dump_space(nlk)) { err = netlink_dump(sk); if (err < 0) { sk->sk_err = err; @@ -704,18 +704,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb) #define netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group, siocb) 0 #endif /* CONFIG_NETLINK_MMAP */ -static void netlink_destroy_callback(struct netlink_callback *cb) -{ - kfree_skb(cb->skb); - kfree(cb); -} - -static void netlink_consume_callback(struct netlink_callback *cb) -{ - consume_skb(cb->skb); - kfree(cb); -} - static void netlink_skb_destructor(struct sk_buff *skb) { #ifdef CONFIG_NETLINK_MMAP @@ -767,12 +755,12 @@ static void netlink_sock_destruct(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); - if (nlk->cb) { - if (nlk->cb->done) - nlk->cb->done(nlk->cb); + if (nlk->cb_running) { + if (nlk->cb.done) + nlk->cb.done(&nlk->cb); - module_put(nlk->cb->module); - netlink_destroy_callback(nlk->cb); + module_put(nlk->cb.module); + kfree_skb(nlk->cb.skb); } skb_queue_purge(&sk->sk_receive_queue); @@ -2269,7 +2257,8 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, skb_free_datagram(sk, skb); - if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { + if (nlk->cb_running && + atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk); if (ret) { sk->sk_err = ret; @@ -2483,13 +2472,12 @@ static int netlink_dump(struct sock *sk) int alloc_size; mutex_lock(nlk->cb_mutex); - - cb = nlk->cb; - if (cb == NULL) { + if (!nlk->cb_running) { err = -EINVAL; goto errout_skb; } + cb = &nlk->cb; alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); if (!netlink_rx_is_mmaped(sk) && @@ -2527,11 +2515,11 @@ static int netlink_dump(struct sock *sk) if (cb->done) cb->done(cb); - nlk->cb = NULL; - mutex_unlock(nlk->cb_mutex); + nlk->cb_running = false; + mutex_unlock(nlk->cb_mutex); module_put(cb->module); - netlink_consume_callback(cb); + consume_skb(cb->skb); return 0; errout_skb: @@ -2549,59 +2537,51 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, struct netlink_sock *nlk; int ret; - cb = kzalloc(sizeof(*cb), GFP_KERNEL); - if (cb == NULL) - return -ENOBUFS; - /* Memory mapped dump requests need to be copied to avoid looping * on the pending state in netlink_mmap_sendmsg() while the CB hold * a reference to the skb. */ if (netlink_skb_is_mmaped(skb)) { skb = skb_copy(skb, GFP_KERNEL); - if (skb == NULL) { - kfree(cb); + if (skb == NULL) return -ENOBUFS; - } } else atomic_inc(&skb->users); - cb->dump = control->dump; - cb->done = control->done; - cb->nlh = nlh; - cb->data = control->data; - cb->module = control->module; - cb->min_dump_alloc = control->min_dump_alloc; - cb->skb = skb; - sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid); if (sk == NULL) { - netlink_destroy_callback(cb); - return -ECONNREFUSED; + ret = -ECONNREFUSED; + goto error_free; } - nlk = nlk_sk(sk); + nlk = nlk_sk(sk); mutex_lock(nlk->cb_mutex); /* A dump is in progress... */ - if (nlk->cb) { - mutex_unlock(nlk->cb_mutex); - netlink_destroy_callback(cb); + if (nlk->cb_running) { ret = -EBUSY; - goto out; + goto error_unlock; } /* add reference of module which cb->dump belongs to */ - if (!try_module_get(cb->module)) { - mutex_unlock(nlk->cb_mutex); - netlink_destroy_callback(cb); + if (!try_module_get(control->module)) { ret = -EPROTONOSUPPORT; - goto out; + goto error_unlock; } - nlk->cb = cb; + cb = &nlk->cb; + memset(cb, 0, sizeof(*cb)); + cb->dump = control->dump; + cb->done = control->done; + cb->nlh = nlh; + cb->data = control->data; + cb->module = control->module; + cb->min_dump_alloc = control->min_dump_alloc; + cb->skb = skb; + + nlk->cb_running = true; + mutex_unlock(nlk->cb_mutex); ret = netlink_dump(sk); -out: sock_put(sk); if (ret) @@ -2611,6 +2591,13 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, * signal not to send ACK even if it was requested. */ return -EINTR; + +error_unlock: + sock_put(sk); + mutex_unlock(nlk->cb_mutex); +error_free: + kfree_skb(skb); + return ret; } EXPORT_SYMBOL(__netlink_dump_start); @@ -2830,14 +2817,14 @@ static int netlink_seq_show(struct seq_file *seq, void *v) struct sock *s = v; struct netlink_sock *nlk = nlk_sk(s); - seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %pK %-8d %-8d %-8lu\n", + seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %d %-8d %-8d %-8lu\n", s, s->sk_protocol, nlk->portid, nlk->groups ? (u32)nlk->groups[0] : 0, sk_rmem_alloc_get(s), sk_wmem_alloc_get(s), - nlk->cb, + nlk->cb_running, atomic_read(&s->sk_refcnt), atomic_read(&s->sk_drops), sock_i_ino(s) diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index ed8522265f4e..74c16f079869 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -32,7 +32,8 @@ struct netlink_sock { unsigned long *groups; unsigned long state; wait_queue_head_t wait; - struct netlink_callback *cb; + bool cb_running; + struct netlink_callback cb; struct mutex *cb_mutex; struct mutex cb_def_mutex; void (*netlink_rcv)(struct sk_buff *skb); From b6e24936247d419bb3330b32374392a9c04f3aa6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 16 May 2016 17:28:16 +0800 Subject: [PATCH 117/281] netlink: Fix dump skb leak/double free When we free cb->skb after a dump, we do it after releasing the lock. This means that a new dump could have started in the time being and we'll end up freeing their skb instead of ours. This patch saves the skb and module before we unlock so we free the right memory. Change-Id: Icdf8adc86b334c32d2f820b5b203989b294fb19f Fixes: 16b304f3404f ("netlink: Eliminate kmalloc in netlink dump operation.") Reported-by: Baozeng Ding Signed-off-by: Herbert Xu Acked-by: Cong Wang Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e71320326787..c0369c362e6d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2468,6 +2468,7 @@ static int netlink_dump(struct sock *sk) struct netlink_callback *cb; struct sk_buff *skb = NULL; struct nlmsghdr *nlh; + struct module *module; int len, err = -ENOBUFS; int alloc_size; @@ -2517,9 +2518,11 @@ static int netlink_dump(struct sock *sk) cb->done(cb); nlk->cb_running = false; + module = cb->module; + skb = cb->skb; mutex_unlock(nlk->cb_mutex); - module_put(cb->module); - consume_skb(cb->skb); + module_put(module); + consume_skb(skb); return 0; errout_skb: From 880b1f1b860b5c5334e6d87ba8da8fa648106565 Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Thu, 1 Dec 2016 15:08:37 -0500 Subject: [PATCH 118/281] ext4: validate s_first_meta_bg at mount time Ralf Spenneberg reported that he hit a kernel crash when mounting a modified ext4 image. And it turns out that kernel crashed when calculating fs overhead (ext4_calculate_overhead()), this is because the image has very large s_first_meta_bg (debug code shows it's 842150400), and ext4 overruns the memory in count_overhead() when setting bitmap buffer, which is PAGE_SIZE. ext4_calculate_overhead(): buf = get_zeroed_page(GFP_NOFS); <=== PAGE_SIZE buffer blks = count_overhead(sb, i, buf); count_overhead(): for (j = ext4_bg_num_gdb(sb, grp); j > 0; j--) { <=== j = 842150400 ext4_set_bit(EXT4_B2C(sbi, s++), buf); <=== buffer overrun count++; } This can be reproduced easily for me by this script: #!/bin/bash rm -f fs.img mkdir -p /mnt/ext4 fallocate -l 16M fs.img mke2fs -t ext4 -O bigalloc,meta_bg,^resize_inode -F fs.img debugfs -w -R "ssv first_meta_bg 842150400" fs.img mount -o loop fs.img /mnt/ext4 Fix it by validating s_first_meta_bg first at mount time, and refusing to mount if its value exceeds the largest possible meta_bg number. Change-Id: Idaae9e51a43378f641a985b60823585289fa455b Reported-by: Ralf Spenneberg Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger --- fs/ext4/super.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 95020fc8a6e0..ba80d93d315f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3724,6 +3724,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG)) { + if (le32_to_cpu(es->s_first_meta_bg) >= db_count) { + ext4_msg(sb, KERN_WARNING, + "first meta block group too large: %u " + "(group descriptor block count %u)", + le32_to_cpu(es->s_first_meta_bg), db_count); + goto failed_mount; + } + } sbi->s_group_desc = ext4_kvmalloc(db_count * sizeof(struct buffer_head *), GFP_KERNEL); From b57927c5a8dcf37d953f61fa7f948038da72e3a6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 8 Feb 2017 11:26:59 -0800 Subject: [PATCH 119/281] time: Remove CONFIG_TIMER_STATS Currently CONFIG_TIMER_STATS exposes process information across namespaces: kernel/time/timer_list.c print_timer(): SEQ_printf(m, ", %s/%d", tmp, timer->start_pid); /proc/timer_list: #11: <0000000000000000>, hrtimer_wakeup, S:01, do_nanosleep, cron/2570 Given that the tracer can give the same information, this patch entirely removes CONFIG_TIMER_STATS. Change-Id: Ice26d74094d3ad563808342c1604ad444234844b Suggested-by: Thomas Gleixner Signed-off-by: Kees Cook Acked-by: John Stultz Cc: Nicolas Pitre Cc: linux-doc@vger.kernel.org Cc: Lai Jiangshan Cc: Shuah Khan Cc: Xing Gao Cc: Jonathan Corbet Cc: Jessica Frazelle Cc: kernel-hardening@lists.openwall.com Cc: Nicolas Iooss Cc: "Paul E. McKenney" Cc: Petr Mladek Cc: Richard Cochran Cc: Tejun Heo Cc: Michal Marek Cc: Josh Poimboeuf Cc: Dmitry Vyukov Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Olof Johansson Cc: Andrew Morton Cc: linux-api@vger.kernel.org Cc: Arjan van de Ven Link: http://lkml.kernel.org/r/20170208192659.GA32582@beast Signed-off-by: Thomas Gleixner --- Documentation/timers/timer_stats.txt | 73 ----- include/linux/hrtimer.h | 11 - include/linux/timer.h | 48 --- kernel/hrtimer.c | 38 --- kernel/time/Makefile | 1 - kernel/time/timer_list.c | 10 - kernel/time/timer_stats.c | 425 --------------------------- kernel/timer.c | 44 +-- kernel/workqueue.c | 2 - lib/Kconfig.debug | 14 - 10 files changed, 2 insertions(+), 664 deletions(-) delete mode 100644 Documentation/timers/timer_stats.txt delete mode 100644 kernel/time/timer_stats.c diff --git a/Documentation/timers/timer_stats.txt b/Documentation/timers/timer_stats.txt deleted file mode 100644 index 8abd40b22b7f..000000000000 --- a/Documentation/timers/timer_stats.txt +++ /dev/null @@ -1,73 +0,0 @@ -timer_stats - timer usage statistics ------------------------------------- - -timer_stats is a debugging facility to make the timer (ab)usage in a Linux -system visible to kernel and userspace developers. If enabled in the config -but not used it has almost zero runtime overhead, and a relatively small -data structure overhead. Even if collection is enabled runtime all the -locking is per-CPU and lookup is hashed. - -timer_stats should be used by kernel and userspace developers to verify that -their code does not make unduly use of timers. This helps to avoid unnecessary -wakeups, which should be avoided to optimize power consumption. - -It can be enabled by CONFIG_TIMER_STATS in the "Kernel hacking" configuration -section. - -timer_stats collects information about the timer events which are fired in a -Linux system over a sample period: - -- the pid of the task(process) which initialized the timer -- the name of the process which initialized the timer -- the function where the timer was initialized -- the callback function which is associated to the timer -- the number of events (callbacks) - -timer_stats adds an entry to /proc: /proc/timer_stats - -This entry is used to control the statistics functionality and to read out the -sampled information. - -The timer_stats functionality is inactive on bootup. - -To activate a sample period issue: -# echo 1 >/proc/timer_stats - -To stop a sample period issue: -# echo 0 >/proc/timer_stats - -The statistics can be retrieved by: -# cat /proc/timer_stats - -The readout of /proc/timer_stats automatically disables sampling. The sampled -information is kept until a new sample period is started. This allows multiple -readouts. - -Sample output of /proc/timer_stats: - -Timerstats sample period: 3.888770 s - 12, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) - 15, 1 swapper hcd_submit_urb (rh_timer_func) - 4, 959 kedac schedule_timeout (process_timeout) - 1, 0 swapper page_writeback_init (wb_timer_fn) - 28, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) - 22, 2948 IRQ 4 tty_flip_buffer_push (delayed_work_timer_fn) - 3, 3100 bash schedule_timeout (process_timeout) - 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - 1, 1 swapper neigh_table_init_no_netlink (neigh_periodic_timer) - 1, 2292 ip __netdev_watchdog_up (dev_watchdog) - 1, 23 events/1 do_cache_clean (delayed_work_timer_fn) -90 total events, 30.0 events/sec - -The first column is the number of events, the second column the pid, the third -column is the name of the process. The forth column shows the function which -initialized the timer and in parenthesis the callback function which was -executed on expiry. - - Thomas, Ingo - -Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable -timer will appear as follows - 10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 0302bbe3daba..765d9e73c2ba 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -96,12 +96,6 @@ enum hrtimer_restart { * @function: timer expiry callback function * @base: pointer to the timer base (per cpu and per clock) * @state: state information (See bit values above) - * @start_site: timer statistics field to store the site where the timer - * was started - * @start_comm: timer statistics field to store the name of the process which - * started the timer - * @start_pid: timer statistics field to store the pid of the task which - * started the timer * * The hrtimer structure must be initialized by hrtimer_init() */ @@ -111,11 +105,6 @@ struct hrtimer { enum hrtimer_restart (*function)(struct hrtimer *); struct hrtimer_clock_base *base; unsigned long state; -#ifdef CONFIG_TIMER_STATS - int start_pid; - void *start_site; - char start_comm[16]; -#endif }; /** diff --git a/include/linux/timer.h b/include/linux/timer.h index 8c5a197e1587..7c8adfa57ae5 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -23,11 +23,6 @@ struct timer_list { int slack; -#ifdef CONFIG_TIMER_STATS - int start_pid; - void *start_site; - char start_comm[16]; -#endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif @@ -194,49 +189,6 @@ extern void set_timer_slack(struct timer_list *time, int slack_hz); */ extern unsigned long get_next_timer_interrupt(unsigned long now); -/* - * Timer-statistics info: - */ -#ifdef CONFIG_TIMER_STATS - -extern int timer_stats_active; - -#define TIMER_STATS_FLAG_DEFERRABLE 0x1 - -extern void init_timer_stats(void); - -extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, - void *timerf, char *comm, - unsigned int timer_flag); - -extern void __timer_stats_timer_set_start_info(struct timer_list *timer, - void *addr); - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ - if (likely(!timer_stats_active)) - return; - __timer_stats_timer_set_start_info(timer, __builtin_return_address(0)); -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ - timer->start_site = NULL; -} -#else -static inline void init_timer_stats(void) -{ -} - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ -} -#endif - extern void add_timer(struct timer_list *timer); extern int try_to_del_timer_sync(struct timer_list *timer); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 47067de1d7d0..c9c3a6ca54fa 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -827,34 +827,6 @@ void hrtimers_resume(void) clock_was_set_delayed(); } -static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - if (timer->start_site) - return; - timer->start_site = __builtin_return_address(0); - memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); - timer->start_pid = current->pid; -#endif -} - -static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; -#endif -} - -static inline void timer_stats_account_hrtimer(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - if (likely(!timer_stats_active)) - return; - timer_stats_update_stats(timer, timer->start_pid, timer->start_site, - timer->function, timer->start_comm, 0); -#endif -} - /* * Counterpart to lock_hrtimer_base above: */ @@ -988,7 +960,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) * rare case and less expensive than a smp call. */ debug_deactivate(timer); - timer_stats_hrtimer_clear_start_info(timer); reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases); /* * We must preserve the CALLBACK state flag here, @@ -1034,8 +1005,6 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, /* Switch the timer base, if necessary: */ new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); - timer_stats_hrtimer_set_start_info(timer); - leftmost = enqueue_hrtimer(timer, new_base); /* @@ -1211,12 +1180,6 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, base = hrtimer_clockid_to_base(clock_id); timer->base = &cpu_base->clock_base[base]; timerqueue_init(&timer->node); - -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; - timer->start_pid = -1; - memset(timer->start_comm, 0, TASK_COMM_LEN); -#endif } /** @@ -1264,7 +1227,6 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) debug_deactivate(timer); __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); - timer_stats_account_hrtimer(timer); fn = timer->function; /* diff --git a/kernel/time/Makefile b/kernel/time/Makefile index aa91af582aa1..fd87e5194155 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -7,4 +7,3 @@ obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o tick-broadcast-h obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o -obj-$(CONFIG_TIMER_STATS) += timer_stats.o diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index 61ed862cdd37..f6a104349aea 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -57,21 +57,11 @@ static void print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, int idx, u64 now) { -#ifdef CONFIG_TIMER_STATS - char tmp[TASK_COMM_LEN + 1]; -#endif SEQ_printf(m, " #%d: ", idx); print_name_offset(m, taddr); SEQ_printf(m, ", "); print_name_offset(m, timer->function); SEQ_printf(m, ", S:%02lx", timer->state); -#ifdef CONFIG_TIMER_STATS - SEQ_printf(m, ", "); - print_name_offset(m, timer->start_site); - memcpy(tmp, timer->start_comm, TASK_COMM_LEN); - tmp[TASK_COMM_LEN] = 0; - SEQ_printf(m, ", %s/%d", tmp, timer->start_pid); -#endif SEQ_printf(m, "\n"); SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n", (unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)), diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c deleted file mode 100644 index 0b537f27b559..000000000000 --- a/kernel/time/timer_stats.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * kernel/time/timer_stats.c - * - * Collect timer usage statistics. - * - * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006 Timesys Corp., Thomas Gleixner - * - * timer_stats is based on timer_top, a similar functionality which was part of - * Con Kolivas dyntick patch set. It was developed by Daniel Petrini at the - * Instituto Nokia de Tecnologia - INdT - Manaus. timer_top's design was based - * on dynamic allocation of the statistics entries and linear search based - * lookup combined with a global lock, rather than the static array, hash - * and per-CPU locking which is used by timer_stats. It was written for the - * pre hrtimer kernel code and therefore did not take hrtimers into account. - * Nevertheless it provided the base for the timer_stats implementation and - * was a helpful source of inspiration. Kudos to Daniel and the Nokia folks - * for this effort. - * - * timer_top.c is - * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus - * Written by Daniel Petrini - * timer_top.c was released under the GNU General Public License version 2 - * - * We export the addresses and counting of timer functions being called, - * the pid and cmdline from the owner process if applicable. - * - * Start/stop data collection: - * # echo [1|0] >/proc/timer_stats - * - * Display the information collected so far: - * # cat /proc/timer_stats - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include - -/* - * This is our basic unit of interest: a timer expiry event identified - * by the timer, its start/expire functions and the PID of the task that - * started the timer. We count the number of times an event happens: - */ -struct entry { - /* - * Hash list: - */ - struct entry *next; - - /* - * Hash keys: - */ - void *timer; - void *start_func; - void *expire_func; - pid_t pid; - - /* - * Number of timeout events: - */ - unsigned long count; - unsigned int timer_flag; - - /* - * We save the command-line string to preserve - * this information past task exit: - */ - char comm[TASK_COMM_LEN + 1]; - -} ____cacheline_aligned_in_smp; - -/* - * Spinlock protecting the tables - not taken during lookup: - */ -static DEFINE_RAW_SPINLOCK(table_lock); - -/* - * Per-CPU lookup locks for fast hash lookup: - */ -static DEFINE_PER_CPU(raw_spinlock_t, tstats_lookup_lock); - -/* - * Mutex to serialize state changes with show-stats activities: - */ -static DEFINE_MUTEX(show_mutex); - -/* - * Collection status, active/inactive: - */ -int __read_mostly timer_stats_active; - -/* - * Beginning/end timestamps of measurement: - */ -static ktime_t time_start, time_stop; - -/* - * tstat entry structs only get allocated while collection is - * active and never freed during that time - this simplifies - * things quite a bit. - * - * They get freed when a new collection period is started. - */ -#define MAX_ENTRIES_BITS 10 -#define MAX_ENTRIES (1UL << MAX_ENTRIES_BITS) - -static unsigned long nr_entries; -static struct entry entries[MAX_ENTRIES]; - -static atomic_t overflow_count; - -/* - * The entries are in a hash-table, for fast lookup: - */ -#define TSTAT_HASH_BITS (MAX_ENTRIES_BITS - 1) -#define TSTAT_HASH_SIZE (1UL << TSTAT_HASH_BITS) -#define TSTAT_HASH_MASK (TSTAT_HASH_SIZE - 1) - -#define __tstat_hashfn(entry) \ - (((unsigned long)(entry)->timer ^ \ - (unsigned long)(entry)->start_func ^ \ - (unsigned long)(entry)->expire_func ^ \ - (unsigned long)(entry)->pid ) & TSTAT_HASH_MASK) - -#define tstat_hashentry(entry) (tstat_hash_table + __tstat_hashfn(entry)) - -static struct entry *tstat_hash_table[TSTAT_HASH_SIZE] __read_mostly; - -static void reset_entries(void) -{ - nr_entries = 0; - memset(entries, 0, sizeof(entries)); - memset(tstat_hash_table, 0, sizeof(tstat_hash_table)); - atomic_set(&overflow_count, 0); -} - -static struct entry *alloc_entry(void) -{ - if (nr_entries >= MAX_ENTRIES) - return NULL; - - return entries + nr_entries++; -} - -static int match_entries(struct entry *entry1, struct entry *entry2) -{ - return entry1->timer == entry2->timer && - entry1->start_func == entry2->start_func && - entry1->expire_func == entry2->expire_func && - entry1->pid == entry2->pid; -} - -/* - * Look up whether an entry matching this item is present - * in the hash already. Must be called with irqs off and the - * lookup lock held: - */ -static struct entry *tstat_lookup(struct entry *entry, char *comm) -{ - struct entry **head, *curr, *prev; - - head = tstat_hashentry(entry); - curr = *head; - - /* - * The fastpath is when the entry is already hashed, - * we do this with the lookup lock held, but with the - * table lock not held: - */ - while (curr) { - if (match_entries(curr, entry)) - return curr; - - curr = curr->next; - } - /* - * Slowpath: allocate, set up and link a new hash entry: - */ - prev = NULL; - curr = *head; - - raw_spin_lock(&table_lock); - /* - * Make sure we have not raced with another CPU: - */ - while (curr) { - if (match_entries(curr, entry)) - goto out_unlock; - - prev = curr; - curr = curr->next; - } - - curr = alloc_entry(); - if (curr) { - *curr = *entry; - curr->count = 0; - curr->next = NULL; - memcpy(curr->comm, comm, TASK_COMM_LEN); - - smp_mb(); /* Ensure that curr is initialized before insert */ - - if (prev) - prev->next = curr; - else - *head = curr; - } - out_unlock: - raw_spin_unlock(&table_lock); - - return curr; -} - -/** - * timer_stats_update_stats - Update the statistics for a timer. - * @timer: pointer to either a timer_list or a hrtimer - * @pid: the pid of the task which set up the timer - * @startf: pointer to the function which did the timer setup - * @timerf: pointer to the timer callback function of the timer - * @comm: name of the process which set up the timer - * - * When the timer is already registered, then the event counter is - * incremented. Otherwise the timer is registered in a free slot. - */ -void timer_stats_update_stats(void *timer, pid_t pid, void *startf, - void *timerf, char *comm, - unsigned int timer_flag) -{ - /* - * It doesn't matter which lock we take: - */ - raw_spinlock_t *lock; - struct entry *entry, input; - unsigned long flags; - - if (likely(!timer_stats_active)) - return; - - lock = &per_cpu(tstats_lookup_lock, raw_smp_processor_id()); - - input.timer = timer; - input.start_func = startf; - input.expire_func = timerf; - input.pid = pid; - input.timer_flag = timer_flag; - - raw_spin_lock_irqsave(lock, flags); - if (!timer_stats_active) - goto out_unlock; - - entry = tstat_lookup(&input, comm); - if (likely(entry)) - entry->count++; - else - atomic_inc(&overflow_count); - - out_unlock: - raw_spin_unlock_irqrestore(lock, flags); -} - -static void print_name_offset(struct seq_file *m, unsigned long addr) -{ - char symname[KSYM_NAME_LEN]; - - if (lookup_symbol_name(addr, symname) < 0) - seq_printf(m, "<%p>", (void *)addr); - else - seq_printf(m, "%s", symname); -} - -static int tstats_show(struct seq_file *m, void *v) -{ - struct timespec period; - struct entry *entry; - unsigned long ms; - long events = 0; - ktime_t time; - int i; - - mutex_lock(&show_mutex); - /* - * If still active then calculate up to now: - */ - if (timer_stats_active) - time_stop = ktime_get(); - - time = ktime_sub(time_stop, time_start); - - period = ktime_to_timespec(time); - ms = period.tv_nsec / 1000000; - - seq_puts(m, "Timer Stats Version: v0.2\n"); - seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); - if (atomic_read(&overflow_count)) - seq_printf(m, "Overflow: %d entries\n", - atomic_read(&overflow_count)); - - for (i = 0; i < nr_entries; i++) { - entry = entries + i; - if (entry->timer_flag & TIMER_STATS_FLAG_DEFERRABLE) { - seq_printf(m, "%4luD, %5d %-16s ", - entry->count, entry->pid, entry->comm); - } else { - seq_printf(m, " %4lu, %5d %-16s ", - entry->count, entry->pid, entry->comm); - } - - print_name_offset(m, (unsigned long)entry->start_func); - seq_puts(m, " ("); - print_name_offset(m, (unsigned long)entry->expire_func); - seq_puts(m, ")\n"); - - events += entry->count; - } - - ms += period.tv_sec * 1000; - if (!ms) - ms = 1; - - if (events && period.tv_sec) - seq_printf(m, "%ld total events, %ld.%03ld events/sec\n", - events, events * 1000 / ms, - (events * 1000000 / ms) % 1000); - else - seq_printf(m, "%ld total events\n", events); - - mutex_unlock(&show_mutex); - - return 0; -} - -/* - * After a state change, make sure all concurrent lookup/update - * activities have stopped: - */ -static void sync_access(void) -{ - unsigned long flags; - int cpu; - - for_each_online_cpu(cpu) { - raw_spinlock_t *lock = &per_cpu(tstats_lookup_lock, cpu); - - raw_spin_lock_irqsave(lock, flags); - /* nothing */ - raw_spin_unlock_irqrestore(lock, flags); - } -} - -static ssize_t tstats_write(struct file *file, const char __user *buf, - size_t count, loff_t *offs) -{ - char ctl[2]; - - if (count != 2 || *offs) - return -EINVAL; - - if (copy_from_user(ctl, buf, count)) - return -EFAULT; - - mutex_lock(&show_mutex); - switch (ctl[0]) { - case '0': - if (timer_stats_active) { - timer_stats_active = 0; - time_stop = ktime_get(); - sync_access(); - } - break; - case '1': - if (!timer_stats_active) { - reset_entries(); - time_start = ktime_get(); - smp_mb(); - timer_stats_active = 1; - } - break; - default: - count = -EINVAL; - } - mutex_unlock(&show_mutex); - - return count; -} - -static int tstats_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, tstats_show, NULL); -} - -static const struct file_operations tstats_fops = { - .open = tstats_open, - .read = seq_read, - .write = tstats_write, - .llseek = seq_lseek, - .release = single_release, -}; - -void __init init_timer_stats(void) -{ - int cpu; - - for_each_possible_cpu(cpu) - raw_spin_lock_init(&per_cpu(tstats_lookup_lock, cpu)); -} - -static int __init init_tstats_procfs(void) -{ - struct proc_dir_entry *pe; - - pe = proc_create("timer_stats", 0644, NULL, &tstats_fops); - if (!pe) - return -ENOMEM; - return 0; -} -__initcall(init_tstats_procfs); diff --git a/kernel/timer.c b/kernel/timer.c index 5733076d6472..8bff0a9e61b3 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -397,34 +397,6 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) } } -#ifdef CONFIG_TIMER_STATS -void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr) -{ - if (timer->start_site) - return; - - timer->start_site = addr; - memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); - timer->start_pid = current->pid; -} - -static void timer_stats_account_timer(struct timer_list *timer) -{ - unsigned int flag = 0; - - if (likely(!timer->start_site)) - return; - if (unlikely(tbase_get_deferrable(timer->base))) - flag |= TIMER_STATS_FLAG_DEFERRABLE; - - timer_stats_update_stats(timer, timer->start_pid, timer->start_site, - timer->function, timer->start_comm, flag); -} - -#else -static void timer_stats_account_timer(struct timer_list *timer) {} -#endif - #ifdef CONFIG_DEBUG_OBJECTS_TIMERS static struct debug_obj_descr timer_debug_descr; @@ -637,11 +609,6 @@ static void do_init_timer(struct timer_list *timer, unsigned int flags, timer->entry.next = NULL; timer->base = (void *)((unsigned long)base | flags); timer->slack = -1; -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; - timer->start_pid = -1; - memset(timer->start_comm, 0, TASK_COMM_LEN); -#endif lockdep_init_map(&timer->lockdep_map, name, key, 0); } @@ -739,7 +706,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned long flags; int ret = 0 , cpu; - timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); base = lock_timer_base(timer, &flags); @@ -943,7 +909,6 @@ void add_timer_on(struct timer_list *timer, int cpu) struct tvec_base *base = per_cpu(tvec_bases, cpu); unsigned long flags; - timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); spin_lock_irqsave(&base->lock, flags); timer_set_base(timer, base); @@ -981,7 +946,6 @@ int del_timer(struct timer_list *timer) debug_assert_init(timer); - timer_stats_timer_clear_start_info(timer); if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); ret = detach_if_pending(timer, base, true); @@ -1009,10 +973,9 @@ int try_to_del_timer_sync(struct timer_list *timer) base = lock_timer_base(timer, &flags); - if (base->running_timer != timer) { - timer_stats_timer_clear_start_info(timer); + if (base->running_timer != timer) ret = detach_if_pending(timer, base, true); - } + spin_unlock_irqrestore(&base->lock, flags); return ret; @@ -1193,8 +1156,6 @@ static inline void __run_timers(struct tvec_base *base, bool try) data = timer->data; irqsafe = tbase_get_irqsafe(timer->base); - timer_stats_account_timer(timer); - base->running_timer = timer; detach_expired_timer(timer, base); @@ -1695,7 +1656,6 @@ void __init init_timers(void) err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); - init_timer_stats(); BUG_ON(err != NOTIFY_OK); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c607473ee746..d92b80bc56fa 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1448,8 +1448,6 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, return; } - timer_stats_timer_set_start_info(&dwork->timer); - dwork->wq = wq; dwork->cpu = cpu; timer->expires = jiffies + delay; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d12c364b84da..30f31784fa9d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -378,20 +378,6 @@ config SCHEDSTATS application, you can say N to avoid the very slight overhead this adds. -config TIMER_STATS - bool "Collect kernel timers statistics" - depends on DEBUG_KERNEL && PROC_FS - help - If you say Y here, additional code will be inserted into the - timer routines to collect statistics about kernel timers being - reprogrammed. The statistics can be read from /proc/timer_stats. - The statistics collection is started by writing 1 to /proc/timer_stats, - writing 0 stops it. This feature is useful to collect information - about timer usage patterns in kernel and userspace. This feature - is lightweight if enabled in the kernel config but not activated - (it defaults to deactivated on bootup and will only be activated - if some application like powertop activates it explicitly). - config DEBUG_OBJECTS bool "Debug object operations" depends on DEBUG_KERNEL From 9b11d530103ed1cbf98222142a87379f7979f387 Mon Sep 17 00:00:00 2001 From: Alberto97 Date: Mon, 20 Feb 2017 21:23:19 +0100 Subject: [PATCH 120/281] defconfig: Remove CONFIG_TIMER_STATS Change-Id: If63af800a462605aa70e3685e54c752249f53d2f --- arch/arm/configs/harpia_defconfig | 1 - arch/arm/configs/lux_defconfig | 1 - arch/arm/configs/merlin_defconfig | 1 - arch/arm/configs/osprey_defconfig | 1 - arch/arm/configs/surnia_defconfig | 1 - 5 files changed, 5 deletions(-) diff --git a/arch/arm/configs/harpia_defconfig b/arch/arm/configs/harpia_defconfig index 4f0d1c656d41..4a9c0a6b5bd0 100644 --- a/arch/arm/configs/harpia_defconfig +++ b/arch/arm/configs/harpia_defconfig @@ -3569,7 +3569,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SYSRQ_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set diff --git a/arch/arm/configs/lux_defconfig b/arch/arm/configs/lux_defconfig index deef1e479474..3b87c1f9a8bf 100644 --- a/arch/arm/configs/lux_defconfig +++ b/arch/arm/configs/lux_defconfig @@ -3565,7 +3565,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SYSRQ_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set diff --git a/arch/arm/configs/merlin_defconfig b/arch/arm/configs/merlin_defconfig index 7d22560508b7..e2eede9ff820 100644 --- a/arch/arm/configs/merlin_defconfig +++ b/arch/arm/configs/merlin_defconfig @@ -3553,7 +3553,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SYSRQ_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set diff --git a/arch/arm/configs/osprey_defconfig b/arch/arm/configs/osprey_defconfig index 16facee5e911..1bd1e7682cb3 100644 --- a/arch/arm/configs/osprey_defconfig +++ b/arch/arm/configs/osprey_defconfig @@ -3553,7 +3553,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SYSRQ_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set diff --git a/arch/arm/configs/surnia_defconfig b/arch/arm/configs/surnia_defconfig index 803d989b03d0..61e0fe699f36 100644 --- a/arch/arm/configs/surnia_defconfig +++ b/arch/arm/configs/surnia_defconfig @@ -3526,7 +3526,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_SYSRQ_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set From 4fa5ae304cce0be851fc38eb2e126ceb5d294b0e Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Wed, 28 Oct 2015 16:54:25 +0530 Subject: [PATCH 121/281] wlan:Restore DXE power state when InitScanRSp fail Even when failure response is received to WDI from HAL for Init Sacn request, WDI sets DXE in BMPS power state to full. As a result power state mismatch happens between DXE and Firmware. Change-Id: I2ff66743194d68f8e3c864e1514185d6a76d19a4 CRs-Fixed: 927394 --- drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 535237aeed06..2b6d407242d9 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -16764,6 +16764,12 @@ WDI_ProcessInitScanRsp "Error returned WDI_ProcessInitScanRspi:%d BMPS%d", wdiStatus, pWDICtx->bInBmps); } + else + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Error returned WDI_ProcessInitScanRspi:%d BMPS%d", + wdiStatus, pWDICtx->bInBmps); + } /*Notify UMAC*/ wdiInitScanRspCb( wdiStatus, pWDICtx->pRspCBUserData); From b77abd0b79deb7b217210aa26f12af1f36740ec2 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Tue, 29 Nov 2016 11:38:16 +0530 Subject: [PATCH 122/281] wlan: Log IP address of the first Rx packet after wakeup Log the IP header source and destination address for the first Rx packet received after host wakeup. Change-Id: Id2daa58d9f4dc019729cb8fc85419d2a0deb84fe CRs-Fixed: 1087632 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h | 10 ++- .../CORE/HDD/src/wlan_hdd_softap_tx_rx.c | 7 ++ .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 7 ++ .../staging/prima/CORE/HDD/src/wlan_hdd_wmm.c | 83 ++++++++++++++++++- .../CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c | 29 +------ 5 files changed, 108 insertions(+), 28 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h index 76c2837b45f0..ca4db65c53f7 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -407,4 +407,12 @@ hdd_wlan_wmm_status_e hdd_wmm_checkts( hdd_adapter_t* pAdapter, ===========================================================================*/ VOS_STATUS hdd_wmm_adapter_clear( hdd_adapter_t *pAdapter ); +/**============================================================================ + @brief hdd_log_ip_addr() - Function to log IP header src and dst address + @param pAdapter : [in] pointer to os packet + + @return : None + ===========================================================================*/ +void hdd_log_ip_addr(struct sk_buff *skb); + #endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 58d1c9a4be89..b6cf6360d7dc 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -1744,6 +1744,13 @@ VOS_STATUS hdd_softap_rx_packet_cbk( v_VOID_t *vosContext, } } + if (pHddCtx->rx_wow_dump) { + if (!(VOS_PKT_PROTO_TYPE_ARP & proto_type) && + !(VOS_PKT_PROTO_TYPE_EAPOL & proto_type)) + hdd_log_ip_addr(skb); + pHddCtx->rx_wow_dump = false; + } + if (WLAN_RX_BCMC_STA_ID == pRxMetaInfo->ucDesSTAId) { //MC/BC packets. Duplicate a copy of packet diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index 06d5b60f6a4e..3cae5479a191 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -2680,6 +2680,13 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, } } + if (pHddCtx->rx_wow_dump) { + if (!(VOS_PKT_PROTO_TYPE_ARP & proto_type) && + !(VOS_PKT_PROTO_TYPE_EAPOL & proto_type)) + hdd_log_ip_addr(skb); + pHddCtx->rx_wow_dump = false; + } + if (pHddCtx->cfg_ini->gEnableRoamDelayStats) { vos_record_roam_event(e_HDD_RX_PKT_CBK_TIME, (void *)skb, 0); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c index dcea728e7435..e854ad271701 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -93,6 +93,12 @@ #define HDD_WMM_UP_TO_AC_MAP_SIZE 8 +#define IPv6_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5],\ + (a)[6], (a)[7], (a)[8], (a)[9], (a)[10], (a)[11], (a)[12], (a)[13],\ + (a)[14], (a)[15] +#define IPv6_ADDR_STR "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\ + "%02x%02x:%02x%02x" + const v_U8_t hddWmmUpToAcMap[] = { WLANTL_AC_BE, WLANTL_AC_BK, @@ -1878,6 +1884,81 @@ v_BOOL_t hdd_skb_is_eapol_or_wai_packet(struct sk_buff *skb) return VOS_FALSE; } +/**============================================================================ + @brief hdd_log_ip_addr() - Function to log IP header src and dst address + @param skb : [in] pointer to OS packet (sk_buff) + @return : none + ===========================================================================*/ +void hdd_log_ip_addr(struct sk_buff *skb) +{ + union generic_ethhdr *pHdr; + struct iphdr *pIpHdr; + unsigned char * pPkt; + char *buf; + + pPkt = skb->data; + pHdr = (union generic_ethhdr *)pPkt; + + if (pHdr->eth_II.h_proto == htons(ETH_P_IP)) + { + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_II)]; + + buf = (char *)&pIpHdr->saddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: src addr %d:%d:%d:%d", __func__, + buf[0], buf[1], buf[2], buf[3]); + + buf = (char *)&pIpHdr->daddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: dst addr %d:%d:%d:%d", __func__, + buf[0], buf[1], buf[2], buf[3]); + } + else if (pHdr->eth_II.h_proto == htons(ETH_P_IPV6)) + { + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)]; + + buf = (char *)&pIpHdr->saddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: src addr "IPv6_ADDR_STR, __func__, IPv6_ADDR_ARRAY(buf)); + + buf = (char *)&pIpHdr->daddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: dst addr "IPv6_ADDR_STR, __func__, IPv6_ADDR_ARRAY(buf)); + } + else if ((ntohs(pHdr->eth_II.h_proto) < WLAN_MIN_PROTO) && + (pHdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) && + (pHdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) && + (pHdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL)) + { + if (pHdr->eth_8023.h_proto == htons(ETH_P_IP)) + { + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)]; + + buf = (char *)&pIpHdr->saddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: src addr %d:%d:%d:%d", __func__, + buf[0], buf[1], buf[2], buf[3]); + + buf = (char *)&pIpHdr->daddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: dst addr %d:%d:%d:%d", __func__, + buf[0], buf[1], buf[2], buf[3]); + } + else if (pHdr->eth_8023.h_proto == htons(ETH_P_IPV6)) + { + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)]; + + buf = (char *)&pIpHdr->saddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: src addr "IPv6_ADDR_STR, __func__, IPv6_ADDR_ARRAY(buf)); + + buf = (char *)&pIpHdr->daddr; + VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: dst addr "IPv6_ADDR_STR, __func__, IPv6_ADDR_ARRAY(buf)); + } + } +} + /**============================================================================ @brief hdd_wmm_classify_pkt() - Function which will classify an OS packet into a WMM AC based on either 802.1Q or DSCP diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c index 1480e54ad920..018b8be4f5ef 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c @@ -602,10 +602,6 @@ static void WDTS_RxPacketDump(vos_pkt_t *pFrame, WDI_DS_RxMetaInfoType *pRxMetadata) { tpSirMacMgmtHdr pHdr; - struct sk_buff *skb = NULL; - uint8_t proto_type; - uint8_t flag = 0x0F; - wpt_status status; if (NULL == pRxMetadata) { VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, @@ -632,35 +628,18 @@ static void WDTS_RxPacketDump(vos_pkt_t *pFrame, "%s: Management subtype:%d SA:"MAC_ADDRESS_STR" DA:" MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); + vos_set_rx_wow_dump(false); } else if (WDI_MAC_CTRL_FRAME == pRxMetadata->type) { VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, "%s: Control subtype:%d SA:"MAC_ADDRESS_STR" DA:" MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); + vos_set_rx_wow_dump(false); } else if (WDI_MAC_DATA_FRAME == pRxMetadata->type) { VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, "%s: Data subtype:%d SA:"MAC_ADDRESS_STR" DA:" MAC_ADDRESS_STR, __func__, pRxMetadata->subtype, MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da)); - - status = vos_pkt_get_os_packet(pFrame, (v_VOID_t **)&skb, 0); - if (eWLAN_PAL_STATUS_SUCCESS != status) { - VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, - "%s: Failure extracting skb from vos pkt", __func__); - return; - } - - proto_type = vos_pkt_get_proto_type(skb, flag); - if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type) - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: RX frame is EAPOL", __func__); - else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type) - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: RX frame is DHCP", __func__); - else if (VOS_PKT_PROTO_TYPE_ARP & proto_type) - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: RX frame is ARP", __func__); - } else VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR, "%s: Unknown frame SA:"MAC_ADDRESS_STR, @@ -977,10 +956,8 @@ wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType c } /* Dump first Rx packet after host wakeup */ - if (vos_get_rx_wow_dump()) { + if (vos_get_rx_wow_dump()) WDTS_RxPacketDump((vos_pkt_t*)pFrame, pRxMetadata); - vos_set_rx_wow_dump(false); - } /* Invoke Rx complete callback */ pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); From 867acfd36932dbd923892bbde83b1084df1160cc Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Wed, 7 Dec 2016 15:21:44 +0530 Subject: [PATCH 123/281] wlan: Remove PTK/GTK debug logs Currently host prints PTK and GTK key information in default logs. Fix to remove the debug logs which prints sensitive key information. Change-Id: I358b09b77d23eeb5da7d826859ae119a8ea4af8a CRs-Fixed: 1097857 --- .../staging/prima/CORE/MAC/src/pe/lim/limFT.c | 23 ------------------- .../prima/CORE/SME/src/csr/csrApiRoam.c | 9 -------- .../prima/CORE/SME/src/sme_common/sme_FTApi.c | 21 ----------------- 3 files changed, 53 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c index 6a51b3387772..7a60cac737e5 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limFT.c @@ -1507,29 +1507,6 @@ tANI_BOOLEAN limProcessFTUpdateKey(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf ) limLog(pMac, LOG1, FL("BSSID = "MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pKeyInfo->bssId)); - if(pAddBssParams->extSetStaKeyParam.key[0].keyLength == 16) - { - limLog(pMac, LOG1, - FL("BSS key = %02X-%02X-%02X-%02X-%02X-%02X-%02X- " - "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X"), - pAddBssParams->extSetStaKeyParam.key[0].key[0], - pAddBssParams->extSetStaKeyParam.key[0].key[1], - pAddBssParams->extSetStaKeyParam.key[0].key[2], - pAddBssParams->extSetStaKeyParam.key[0].key[3], - pAddBssParams->extSetStaKeyParam.key[0].key[4], - pAddBssParams->extSetStaKeyParam.key[0].key[5], - pAddBssParams->extSetStaKeyParam.key[0].key[6], - pAddBssParams->extSetStaKeyParam.key[0].key[7], - pAddBssParams->extSetStaKeyParam.key[0].key[8], - pAddBssParams->extSetStaKeyParam.key[0].key[9], - pAddBssParams->extSetStaKeyParam.key[0].key[10], - pAddBssParams->extSetStaKeyParam.key[0].key[11], - pAddBssParams->extSetStaKeyParam.key[0].key[12], - pAddBssParams->extSetStaKeyParam.key[0].key[13], - pAddBssParams->extSetStaKeyParam.key[0].key[14], - pAddBssParams->extSetStaKeyParam.key[0].key[15]); - } - return TRUE; } diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index aafe792b9d5e..24e93f852195 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -14601,16 +14601,7 @@ eHalStatus csrSendMBSetContextReqMsg( tpAniSirGlobal pMac, tANI_U32 sessionId, // set pSirKey->keyLength = keyLength; p = pal_set_U16( p, pal_cpu_to_be16(keyLength) ); if ( keyLength && pKey ) - { vos_mem_copy(p, pKey, keyLength); - if(keyLength == 16) - { - smsLog(pMac, LOG1, " SME Set keyIdx (%d) encType(%d) key = %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", - keyId, edType, pKey[0], pKey[1], pKey[2], pKey[3], pKey[4], - pKey[5], pKey[6], pKey[7], pKey[8], - pKey[9], pKey[10], pKey[11], pKey[12], pKey[13], pKey[14], pKey[15]); - } - } status = palSendMBMessage(pMac->hHdd, pMsg); } while( 0 ); return( status ); diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c index cde968833a27..4d988afb85f9 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_FTApi.c @@ -216,12 +216,7 @@ eHalStatus sme_FTSendUpdateKeyInd(tHalHandle hHal, tCsrRoamSetKey * pFTKeyInfo) tAniEdType edType; tpAniSirGlobal pMac = PMAC_STRUCT( hHal ); #if defined WLAN_FEATURE_VOWIFI_11R_DEBUG - int i = 0; - smsLog(pMac, LOG1, FL("keyLength %d"), pFTKeyInfo->keyLength); - - for (i=0; ikeyLength; i++) - smsLog(pMac, LOG1, FL("%02x"), pFTKeyInfo->Key[i]); #endif msgLen = sizeof(tSirFTUpdateKeyInfo); @@ -262,23 +257,7 @@ eHalStatus sme_FTSendUpdateKeyInd(tHalHandle hHal, tCsrRoamSetKey * pFTKeyInfo) keymaterial->key[ 0 ].keyLength = pFTKeyInfo->keyLength; if ( pFTKeyInfo->keyLength && pFTKeyInfo->Key ) - { vos_mem_copy(&keymaterial->key[ 0 ].key, pFTKeyInfo->Key, pFTKeyInfo->keyLength); - if(pFTKeyInfo->keyLength == 16) - { - smsLog(pMac, LOG1, "SME Set Update Ind keyIdx (%d) encType(%d) key = " - "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", - pMsg->keyMaterial.key[0].keyId, (tAniEdType)pMsg->keyMaterial.edType, - pMsg->keyMaterial.key[0].key[0], pMsg->keyMaterial.key[0].key[1], - pMsg->keyMaterial.key[0].key[2], pMsg->keyMaterial.key[0].key[3], - pMsg->keyMaterial.key[0].key[4], pMsg->keyMaterial.key[0].key[5], - pMsg->keyMaterial.key[0].key[6], pMsg->keyMaterial.key[0].key[7], - pMsg->keyMaterial.key[0].key[8], pMsg->keyMaterial.key[0].key[9], - pMsg->keyMaterial.key[0].key[10], pMsg->keyMaterial.key[0].key[11], - pMsg->keyMaterial.key[0].key[12], pMsg->keyMaterial.key[0].key[13], - pMsg->keyMaterial.key[0].key[14], pMsg->keyMaterial.key[0].key[15]); - } - } vos_mem_copy( &pMsg->bssId[ 0 ], &pFTKeyInfo->peerMac[ 0 ], From 1198fbb8b0a04285bf2a9d3304c5b713904c8cec Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Tue, 13 Dec 2016 19:38:00 +0530 Subject: [PATCH 124/281] wlan: Add support for SAP restart in case of lte coex event In case of lte coex event, currently driver stops the SAP and waits for framework to restart it again. Add changes for SAP to restart internally in case of lte coex event. Change-Id: I097008bb2fec490b27471d06619522c45c719a1d CRs-Fixed: 1101834 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 5 + .../prima/CORE/HDD/inc/wlan_hdd_cfg80211.h | 15 ++ .../prima/CORE/HDD/inc/wlan_hdd_hostapd.h | 20 +++ .../prima/CORE/HDD/inc/wlan_hdd_main.h | 15 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 10 ++ .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 154 +++++++++++------- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 1 + .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 57 ++++++- .../prima/CORE/HDD/src/wlan_hdd_main.c | 134 +++++++++++++++ drivers/staging/prima/CORE/SAP/inc/sapApi.h | 6 +- drivers/staging/prima/CORE/SAP/src/sapFsm.c | 3 +- 11 files changed, 352 insertions(+), 68 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 0e8764293e57..92faaaa85619 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2863,6 +2863,10 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ #define CFG_SAP_PROBE_RESP_OFFLOAD_MAX (1) #define CFG_SAP_PROBE_RESP_OFFLOAD_DEFAULT (1) +#define CFG_CH_AVOID_SAP_RESTART_NAME "sap_ch_avoid_restart" +#define CFG_CH_AVOID_SAP_RESTART_MIN (0) +#define CFG_CH_AVOID_SAP_RESTART_MAX (1) +#define CFG_CH_AVOID_SAP_RESTART_DEFAULT (1) /*--------------------------------------------------------------------------- Type declarations @@ -3423,6 +3427,7 @@ typedef struct uint32_t edca_be_aifs; v_BOOL_t sendMgmtPktViaWQ5; v_BOOL_t sap_probe_resp_offload; + v_BOOL_t sap_restrt_ch_avoid; } hdd_config_t; /*--------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h index f236369aa5c3..ab932ddb8784 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -1436,4 +1436,19 @@ struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_list( struct cfg80211_bss *wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, tSirBssDescription *bss_desc); +#ifdef CFG80211_DEL_STA_V2 +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)) || defined(WITH_BACKPORTS) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, const u8 *mac); +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac); +#endif +#endif + +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *pHostapdAdapter); #endif diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h index 0e1692327688..3b1eb5d0d963 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h @@ -87,6 +87,26 @@ int hdd_softap_unpackIE( tHalHandle halHandle, u_int16_t gen_ie_len, u_int8_t *gen_ie ); +/** + * hdd_change_ch_avoidance_status() - update is_ch_avoid_in_progress flag + * + * @hdd_ctx: pointer to hdd context + * @value: value to set + * + * This function will change the value of is_ch_avoid_in_progress + * + * Return: none + */ +static inline void +hdd_change_ch_avoidance_status(hdd_context_t *hdd_ctx, + bool value) +{ + vos_spin_lock_acquire(&hdd_ctx->sap_update_info_lock); + hdd_ctx->is_ch_avoid_in_progress = value; + vos_spin_lock_release(&hdd_ctx->sap_update_info_lock); +} + + VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCallback); VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ); void hdd_set_ap_ops( struct net_device *pWlanHostapdDev ); diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 8be2853b69b2..396111f4a686 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -540,8 +540,14 @@ typedef struct hdd_wapi_info_s hdd_wapi_info_t; #endif /* FEATURE_WLAN_WAPI */ typedef struct beacon_data_s { - u8 *head, *tail; - int head_len, tail_len; + u8 *head; + u8 *tail; + u8 *proberesp_ies; + u8 *assocresp_ies; + int head_len; + int tail_len; + int proberesp_ies_len; + int assocresp_ies_len; int dtim_period; } beacon_data_t; @@ -1451,6 +1457,11 @@ struct hdd_context_s /* Lock to avoid race condtion during start/stop bss*/ struct mutex sap_lock; + struct work_struct sap_start_work; + bool is_sap_restart_required; + bool is_ch_avoid_in_progress; + vos_spin_lock_t sap_update_info_lock; + /* Lock to avoid race condtion between ROC timeout and cancel callbacks*/ struct mutex roc_lock; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 3389cec511f0..f68c005064fc 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -3734,6 +3734,13 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_SAP_PROBE_RESP_OFFLOAD_DEFAULT, CFG_SAP_PROBE_RESP_OFFLOAD_MIN, CFG_SAP_PROBE_RESP_OFFLOAD_MAX), + + REG_VARIABLE(CFG_CH_AVOID_SAP_RESTART_NAME, WLAN_PARAM_Integer, + hdd_config_t, sap_restrt_ch_avoid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CH_AVOID_SAP_RESTART_DEFAULT, + CFG_CH_AVOID_SAP_RESTART_MIN, + CFG_CH_AVOID_SAP_RESTART_MAX), }; /* @@ -4291,6 +4298,9 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) "Name = [gPERRoamUpThresholdRate] Value = [%u] ", pHddCtx->cfg_ini->rateUpThreshold); #endif + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [sap_ch_avoid_restart] Value = [%u] ", + pHddCtx->cfg_ini->sap_restrt_ch_avoid); } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 7522bb713e17..0fb2c54a3b7e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -8363,7 +8363,8 @@ int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, int size; beacon_data_t *beacon = NULL; beacon_data_t *old = NULL; - int head_len,tail_len; + int head_len, tail_len, proberesp_ies_len, assocresp_ies_len; + const u8 *head, *tail, *proberesp_ies, *assocresp_ies; ENTER(); if (params->head && !params->head_len) @@ -8400,20 +8401,50 @@ int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, } #endif - if(params->head) + if (params->head) + { head_len = params->head_len; - else + head = params->head; + } else + { head_len = old->head_len; + head = old->head; + } - if(params->tail || !old) + if (params->tail || !old) + { tail_len = params->tail_len; - else + tail = params->tail; + } else + { tail_len = old->tail_len; + tail = old->tail; + } - size = sizeof(beacon_data_t) + head_len + tail_len; + if (params->proberesp_ies || !old) + { + proberesp_ies_len = params->proberesp_ies_len; + proberesp_ies = params->proberesp_ies; + } else + { + proberesp_ies_len = old->proberesp_ies_len; + proberesp_ies = old->proberesp_ies; + } - beacon = kzalloc(size, GFP_KERNEL); + if (params->assocresp_ies || !old) + { + assocresp_ies_len = params->assocresp_ies_len; + assocresp_ies = params->assocresp_ies; + } else + { + assocresp_ies_len = old->assocresp_ies_len; + assocresp_ies = old->assocresp_ies; + } + size = sizeof(beacon_data_t) + head_len + tail_len + + proberesp_ies_len + assocresp_ies_len; + + beacon = kzalloc(size, GFP_KERNEL); if( beacon == NULL ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, @@ -8422,12 +8453,12 @@ int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, } #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) - if(params->dtim_period || !old ) + if (params->dtim_period) beacon->dtim_period = params->dtim_period; else beacon->dtim_period = old->dtim_period; #else - if(dtim_period || !old ) + if (dtim_period) beacon->dtim_period = dtim_period; else beacon->dtim_period = old->dtim_period; @@ -8435,31 +8466,24 @@ int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, beacon->head = ((u8 *) beacon) + sizeof(beacon_data_t); beacon->tail = beacon->head + head_len; + beacon->proberesp_ies = beacon->tail + tail_len; + beacon->assocresp_ies = beacon->proberesp_ies + proberesp_ies_len; + beacon->head_len = head_len; beacon->tail_len = tail_len; + beacon->proberesp_ies_len = proberesp_ies_len; + beacon->assocresp_ies_len= assocresp_ies_len; - if(params->head) { - memcpy (beacon->head,params->head,beacon->head_len); - } - else { - if(old) - memcpy (beacon->head,old->head,beacon->head_len); - } - - if(params->tail) { - memcpy (beacon->tail,params->tail,beacon->tail_len); - } - else { - if(old) - memcpy (beacon->tail,old->tail,beacon->tail_len); - } + memcpy(beacon->head, head, head_len); + memcpy(beacon->tail, tail, tail_len); + memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); + memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); *ppBeacon = beacon; kfree(old); return 0; - } v_U8_t* wlan_hdd_cfg80211_get_ie_ptr( @@ -8674,18 +8698,13 @@ static void wlan_hdd_add_hostapd_conf_vsie(hdd_adapter_t* pHostapdAdapter, return; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) -static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, - struct beacon_parameters *params) -#else -static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, - struct cfg80211_beacon_data *params) -#endif +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *pHostapdAdapter) { v_U8_t *genie; v_U8_t total_ielen = 0; v_U8_t addIE[1] = {0}; int ret = 0; + beacon_data_t *pBeacon = NULL; genie = vos_mem_malloc(MAX_GENIE_LEN); @@ -8694,6 +8713,7 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, return -ENOMEM; } + pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; if (0 != wlan_hdd_add_ie(pHostapdAdapter, genie, &total_ielen, WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE)) { @@ -8751,9 +8771,9 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, } // Added for ProResp IE - if ( (params->proberesp_ies != NULL) && (params->proberesp_ies_len != 0) ) + if ((pBeacon->proberesp_ies != NULL) && (pBeacon->proberesp_ies_len != 0)) { - u16 rem_probe_resp_ie_len = params->proberesp_ies_len; + u16 rem_probe_resp_ie_len = pBeacon->proberesp_ies_len; u8 probe_rsp_ie_len[3] = {0}; u8 counter = 0; /* Check Probe Resp Length if it is greater then 255 then Store @@ -8781,7 +8801,8 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, { if (ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal, WNI_CFG_PROBE_RSP_ADDNIE_DATA1, - (tANI_U8*)¶ms->proberesp_ies[rem_probe_resp_ie_len], + (tANI_U8*)&pBeacon-> + proberesp_ies[rem_probe_resp_ie_len], probe_rsp_ie_len[0], NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { @@ -8797,7 +8818,8 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, { if (ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal, WNI_CFG_PROBE_RSP_ADDNIE_DATA2, - (tANI_U8*)¶ms->proberesp_ies[rem_probe_resp_ie_len], + (tANI_U8*)&pBeacon-> + proberesp_ies[rem_probe_resp_ie_len], probe_rsp_ie_len[1], NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { @@ -8813,7 +8835,8 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, { if (ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal, WNI_CFG_PROBE_RSP_ADDNIE_DATA3, - (tANI_U8*)¶ms->proberesp_ies[rem_probe_resp_ie_len], + (tANI_U8*)&pBeacon-> + proberesp_ies[rem_probe_resp_ie_len], probe_rsp_ie_len[2], NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { @@ -8870,11 +8893,11 @@ static int wlan_hdd_cfg80211_update_apies(hdd_adapter_t* pHostapdAdapter, } // Added for AssocResp IE - if ( (params->assocresp_ies != NULL) && (params->assocresp_ies_len != 0) ) + if ((pBeacon->assocresp_ies != NULL) && (pBeacon->assocresp_ies_len != 0)) { if (ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal, - WNI_CFG_ASSOC_RSP_ADDNIE_DATA, (tANI_U8*)params->assocresp_ies, - params->assocresp_ies_len, NULL, + WNI_CFG_ASSOC_RSP_ADDNIE_DATA, (tANI_U8*)pBeacon->assocresp_ies, + pBeacon->assocresp_ies_len, NULL, eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE) { hddLog(LOGE, @@ -9195,7 +9218,6 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, int status = VOS_STATUS_SUCCESS; tpWLAN_SAPEventCB pSapEventCallback; hdd_hostapd_state_t *pHostapdState; - v_U8_t wpaRsnIEdata[(SIR_MAC_MAX_IE_LENGTH * 2)+4]; //Max ie length 255 * 2(WPA+RSN) + 2 bytes (vendor specific ID) * 2 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext; tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); struct qc_mac_acl_entry *acl_entry = NULL; @@ -9207,6 +9229,8 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, v_BOOL_t MFPRequired = VOS_FALSE; v_BOOL_t sapEnable11AC = (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->sapEnable11AC; + u_int16_t prev_rsn_length = 0; + ENTER(); iniConfig = pHddCtx->cfg_ini; @@ -9346,14 +9370,18 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, eCSR_ENCRYPT_TYPE_NONE; pConfig->RSNWPAReqIELength = 0; - pConfig->pRSNWPAReqIE = NULL; + memset(&pConfig->RSNWPAReqIE[0], 0, sizeof(pConfig->RSNWPAReqIE)); pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, WLAN_EID_RSN); if(pIe && pIe[1]) { pConfig->RSNWPAReqIELength = pIe[1] + 2; - memcpy(&wpaRsnIEdata[0], pIe, pConfig->RSNWPAReqIELength); - pConfig->pRSNWPAReqIE = &wpaRsnIEdata[0]; + if (pConfig->RSNWPAReqIELength <= sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hddLog(LOGE, "RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); /* The actual processing may eventually be more extensive than * this. Right now, just consume any PMKIDs that are sent in * by the app. @@ -9365,8 +9393,8 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, &RSNAuthType, &MFPCapable, &MFPRequired, - pConfig->pRSNWPAReqIE[1]+2, - pConfig->pRSNWPAReqIE ); + pConfig->RSNWPAReqIE[1]+2, + pConfig->RSNWPAReqIE); if( VOS_STATUS_SUCCESS == status ) { @@ -9388,17 +9416,29 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, if(pIe && pIe[1] && (pIe[0] == DOT11F_EID_WPA)) { - if (pConfig->pRSNWPAReqIE) + if (pConfig->RSNWPAReqIE[0]) { /*Mixed mode WPA/WPA2*/ - memcpy((&wpaRsnIEdata[0] + pConfig->RSNWPAReqIELength), pIe, pIe[1] + 2); + prev_rsn_length = pConfig->RSNWPAReqIELength; pConfig->RSNWPAReqIELength += pIe[1] + 2; + if (pConfig->RSNWPAReqIELength <= + (sizeof(pConfig->RSNWPAReqIE) - prev_rsn_length)) + memcpy(&pConfig->RSNWPAReqIE[0] + prev_rsn_length, pIe, + pIe[1] + 2); + else + hddLog(LOGE, "RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + } else { pConfig->RSNWPAReqIELength = pIe[1] + 2; - memcpy(&wpaRsnIEdata[0], pIe, pConfig->RSNWPAReqIELength); - pConfig->pRSNWPAReqIE = &wpaRsnIEdata[0]; + if (pConfig->RSNWPAReqIELength <= sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hddLog(LOGE, "RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); status = hdd_softap_unpackIE( vos_get_context( VOS_MODULE_ID_SME, pVosContext), &RSNEncryptType, @@ -9406,8 +9446,8 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, &RSNAuthType, &MFPCapable, &MFPRequired, - pConfig->pRSNWPAReqIE[1]+2, - pConfig->pRSNWPAReqIE ); + pConfig->RSNWPAReqIE[1]+2, + pConfig->RSNWPAReqIE); if( VOS_STATUS_SUCCESS == status ) { @@ -9425,7 +9465,7 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, } } - if (pConfig->RSNWPAReqIELength > sizeof wpaRsnIEdata) { + if (pConfig->RSNWPAReqIELength > sizeof(pConfig->RSNWPAReqIE)) { hddLog( VOS_TRACE_LEVEL_ERROR, "**RSNWPAReqIELength is too large***"); return -EINVAL; } @@ -9552,7 +9592,7 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, pConfig->ht_capab = (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->apProtection; - if ( 0 != wlan_hdd_cfg80211_update_apies(pHostapdAdapter, params) ) + if ( 0 != wlan_hdd_cfg80211_update_apies(pHostapdAdapter)) { hddLog(LOGE, FL("SAP Not able to set AP IEs")); return -EINVAL; @@ -16521,15 +16561,15 @@ static int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, } #ifdef CFG80211_DEL_STA_V2 -static int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *param) #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)) -static int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac) #else -static int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) #endif #endif diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index de9a3cf1f70b..7ef39cdfae1a 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2165,6 +2165,7 @@ VOS_STATUS hdd_wlan_shutdown(void) } vos_flush_delayed_work(&pHddCtx->spoof_mac_addr_work); + vos_flush_work(&pHddCtx->sap_start_work); hdd_reset_all_adapters(pHddCtx); /* set default value of Tcp delack and stop timer */ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index 427a35058bcf..b3499b92e3b7 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -922,7 +922,6 @@ VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCa VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: WLANSAP_SetKeySta failed idx %d", __func__, i); } - pHddApCtx->wepKey[i].keyLength = 0; } } //Fill the params for sending IWEVCUSTOM Event with SOFTAP.enabled @@ -1493,6 +1492,54 @@ void hdd_hostapd_update_unsafe_channel_list(hdd_context_t *pHddCtx, return; } +/** + * hdd_unsafe_channel_restart_sap - restart sap if sap is on unsafe channel + * @adapter: hdd ap adapter + * + * hdd_unsafe_channel_restart_sap check all unsafe channel list + * and if ACS is enabled, driver will ask userspace to restart the + * sap. User space on LTE coex indication restart driver. + * + * Return - none + */ +static void hdd_unsafe_channel_restart_sap(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx) +{ + + if (!(adapter && (WLAN_HDD_SOFTAP == adapter->device_mode))) { + return; + } + + hddLog(LOG1, FL("Current operation channel %d"), + adapter->sessionCtx.ap.operatingChannel); + if (false == hdd_ctx->is_ch_avoid_in_progress) { + hdd_change_ch_avoidance_status(hdd_ctx, true); + + vos_flush_work( + &hdd_ctx->sap_start_work); + + /* + * current operating channel + * is un-safe channel, restart SAP + */ + hddLog(LOG1, + FL("Restarting SAP due to unsafe channel")); + + adapter->sessionCtx.ap.sapConfig.channel = + AUTO_CHANNEL_SELECT; + + netif_tx_disable(adapter->dev); + + if (hdd_ctx->cfg_ini->sap_restrt_ch_avoid) + schedule_work( + &hdd_ctx->sap_start_work); + + return; + } + return; +} + + /**--------------------------------------------------------------------------- \brief hdd_hostapd_ch_avoid_cb() - @@ -1509,7 +1556,7 @@ void hdd_hostapd_update_unsafe_channel_list(hdd_context_t *pHddCtx, --------------------------------------------------------------------------*/ void hdd_hostapd_ch_avoid_cb ( - void *pAdapter, + void *context, void *indParam ) { @@ -1535,14 +1582,14 @@ void hdd_hostapd_ch_avoid_cb #endif /* Basic sanity */ - if ((NULL == pAdapter) || (NULL == indParam)) + if ((NULL == context) || (NULL == indParam)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s : Invalid arguments", __func__); return; } - hddCtxt = (hdd_context_t *)pAdapter; + hddCtxt = (hdd_context_t *)context; chAvoidInd = (tSirChAvoidIndType *)indParam; pVosContext = hddCtxt->pvosContext; @@ -1667,7 +1714,7 @@ void hdd_hostapd_ch_avoid_cb { /* current operating channel is un-safe channel * restart driver */ - hdd_hostapd_stop(pHostapdAdapter->dev); + hdd_unsafe_channel_restart_sap(pHostapdAdapter, hddCtxt); /* On LE, this event is handled by wlan-services to * restart SAP. On android, this event would be * ignored. diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 80d85593befa..9593d6e4206c 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -9218,6 +9218,137 @@ VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, return VOS_STATUS_SUCCESS; } +/** + * wlan_hdd_restart_sap() - to restart SAP in driver internally + * @ap_adapter: - Pointer to SAP hdd_adapter_t structure + * + * wlan_hdd_restart_sap first delete SAP and do cleanup. + * After that WLANSAP_StartBss start re-start process of SAP. + * + * Return: None + */ +static void wlan_hdd_restart_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *pHddApCtx; + hdd_hostapd_state_t *pHostapdState; + VOS_STATUS vos_status; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(ap_adapter); +#ifdef CFG80211_DEL_STA_V2 + struct station_del_parameters delStaParams; +#endif + tsap_Config_t *pConfig; + + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + pConfig = &pHddApCtx->sapConfig; + + mutex_lock(&pHddCtx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { +#ifdef CFG80211_DEL_STA_V2 + delStaParams.mac = NULL; + delStaParams.subtype = SIR_MAC_MGMT_DEAUTH >> 4; + delStaParams.reason_code = eCsrForcedDeauthSta; + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, ap_adapter->dev, + &delStaParams); +#else + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, ap_adapter->dev, + NULL); +#endif + hdd_cleanup_actionframe(pHddCtx, ap_adapter); + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + vos_event_reset(&pHostapdState->vosEvent); + + if (VOS_STATUS_SUCCESS == WLANSAP_StopBss(pHddCtx->pvosContext)) { + vos_status = vos_wait_single_event(&pHostapdState->vosEvent, + 10000); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("SAP Stop Failed")); + goto end; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + wlan_hdd_decr_active_session(pHddCtx, ap_adapter->device_mode); + hddLog(LOG1, FL("SAP Stop Success")); + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + hddLog(LOGE, FL("SAP Not able to set AP IEs")); + goto end; + } + + if (WLANSAP_StartBss(pHddCtx->pvosContext, hdd_hostapd_SAPEventCB, + pConfig, (v_PVOID_t)ap_adapter->dev) != VOS_STATUS_SUCCESS) { + hddLog(LOGE, FL("SAP Start Bss fail")); + goto end; + } + + hddLog(LOG1, FL("Waiting for SAP to start")); + vos_status = vos_wait_single_event(&pHostapdState->vosEvent, 10000); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("SAP Start failed")); + goto end; + } + hddLog(LOG1, FL("SAP Start Success")); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + wlan_hdd_incr_active_session(pHddCtx, ap_adapter->device_mode); + pHostapdState->bCommit = TRUE; + } +end: + mutex_unlock(&pHddCtx->sap_lock); + return; +} + +/** + * __hdd_sap_restart_handle() - to handle restarting of SAP + * @work: name of the work + * + * Purpose of this function is to trigger sap start. this function + * will be called from workqueue. + * + * Return: void. + */ +static void __hdd_sap_restart_handle(struct work_struct *work) +{ + hdd_adapter_t *sap_adapter; + hdd_context_t *hdd_ctx = container_of(work, + hdd_context_t, + sap_start_work); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + vos_ssr_unprotect(__func__); + return; + } + sap_adapter = hdd_get_adapter(hdd_ctx, + WLAN_HDD_SOFTAP); + if (sap_adapter == NULL) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("sap_adapter is NULL")); + vos_ssr_unprotect(__func__); + return; + } + + if (hdd_ctx->is_ch_avoid_in_progress) { + sap_adapter->sessionCtx.ap.sapConfig.channel = AUTO_CHANNEL_SELECT; + wlan_hdd_restart_sap(sap_adapter); + hdd_change_ch_avoidance_status(hdd_ctx, false); + } +} + +/** + * hdd_sap_restart_handle() - to handle restarting of SAP + * @work: name of the work + * + * Purpose of this function is to trigger sap start. this function + * will be called from workqueue. + * + * Return: void. + */ +static void hdd_sap_restart_handle(struct work_struct *work) +{ + vos_ssr_protect(__func__); + __hdd_sap_restart_handle(work); + vos_ssr_unprotect(__func__); +} + + VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx ) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; @@ -10565,6 +10696,7 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) hdd_close_all_adapters( pHddCtx ); vos_flush_delayed_work(&pHddCtx->spoof_mac_addr_work); + vos_flush_work(&pHddCtx->sap_start_work); free_hdd_ctx: /* free the power on lock from platform driver */ @@ -11549,11 +11681,13 @@ int hdd_wlan_startup(struct device *dev ) #endif /* WLAN_FEATURE_EXTSCAN */ spin_lock_init(&pHddCtx->schedScan_lock); + vos_spin_lock_init(&pHddCtx->sap_update_info_lock); hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS ); vos_init_delayed_work(&pHddCtx->spoof_mac_addr_work, hdd_processSpoofMacAddrRequest); + vos_init_work(&pHddCtx->sap_start_work, hdd_sap_restart_handle); #ifdef FEATURE_WLAN_TDLS /* tdls_lock is initialized before an hdd_open_adapter ( which is diff --git a/drivers/staging/prima/CORE/SAP/inc/sapApi.h b/drivers/staging/prima/CORE/SAP/inc/sapApi.h index 0da7bbc2045a..dcb248289583 100644 --- a/drivers/staging/prima/CORE/SAP/inc/sapApi.h +++ b/drivers/staging/prima/CORE/SAP/inc/sapApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -427,8 +427,8 @@ typedef struct sap_Config { v_U8_t dtim_period; /* dtim interval */ v_U8_t num_accept_mac; v_U8_t num_deny_mac; - v_U8_t *pRSNWPAReqIE; //If not null, it has the IE byte stream for RSN /WPA - + /* Max ie length 255 * 2(WPA+RSN) + 2 bytes(vendor specific ID) * 2 */ + v_U8_t RSNWPAReqIE[(SIR_MAC_MAX_IE_LENGTH * 2) + 4]; v_U8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; //it is ignored if [0] is 0. v_U8_t RSNAuthType; v_U8_t RSNEncryptType; diff --git a/drivers/staging/prima/CORE/SAP/src/sapFsm.c b/drivers/staging/prima/CORE/SAP/src/sapFsm.c index 4ebbae5be49d..9e48d8cc619c 100644 --- a/drivers/staging/prima/CORE/SAP/src/sapFsm.c +++ b/drivers/staging/prima/CORE/SAP/src/sapFsm.c @@ -1337,7 +1337,8 @@ sapconvertToCsrProfile(tsap_Config_t *pconfig_params, eCsrRoamBssType bssType, t VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, " %s Fail to alloc memory", __func__); return eSAP_STATUS_FAILURE; } - vos_mem_copy(profile->pRSNReqIE, pconfig_params->pRSNWPAReqIE, pconfig_params->RSNWPAReqIELength); + vos_mem_copy(profile->pRSNReqIE, pconfig_params->RSNWPAReqIE, + pconfig_params->RSNWPAReqIELength); profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; } From 1bcee0273e29d01ce2e9dc20faa545ea5efe9a5e Mon Sep 17 00:00:00 2001 From: Pothula Hanumantha Reddy Date: Wed, 28 Dec 2016 17:55:19 +0530 Subject: [PATCH 125/281] prima: Fix array out-of-bounds & integer underflow in _iw_set_genie qcacld-2.0 to prima propagation 'wrqu->data.length' holds the total number of IE data buffer. Add a check to make sure the number of remaining data to be read is greater than or equal to IE length. Also, advance the buffer pointer to point to the next element only if next element is present. Change-Id: Ic60f3e0650f365955dab4099eb8740e9789e00cc CRs-Fixed: 1100132 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 07d2e6b9d264..91bc35c891ce 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -2565,6 +2565,13 @@ static int __iw_set_genie(struct net_device *dev, hddLog(VOS_TRACE_LEVEL_INFO, "%s: IE[0x%X], LEN[%d]", __func__, elementId, eLen); + if (remLen < eLen) { + hddLog(LOGE, "Remaining len: %u less than ie len: %u", + remLen, eLen); + ret = -EINVAL; + goto exit; + } + switch ( elementId ) { case IE_EID_VENDOR: @@ -2647,8 +2654,11 @@ static int __iw_set_genie(struct net_device *dev, hddLog (LOGE, "%s Set UNKNOWN IE %X",__func__, elementId); goto exit; } - genie += eLen; remLen -= eLen; + + /* Move genie only if next element is present */ + if (remLen >= 2) + genie += eLen; } exit: From c3d407f3beda30c2743d641298dd053bb6e4a857 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 25 Nov 2016 16:24:13 +0530 Subject: [PATCH 126/281] wlan: Add configuration option for bad RSSI in PER based roaming In PER based roaming candidate selection, candidates are discarded if their RSSI are too low which is considered as bad RSSI. Add changes to remove constant value for bad RSSI and add configuration parameter based on ini. CRs-Fixed: 1094330 Change-Id: Ia0a442a27c06cec82de8112b7c11fb30a0e14493 --- drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 9 +++++++++ drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 11 +++++++++++ drivers/staging/prima/CORE/SME/inc/csrApi.h | 1 + drivers/staging/prima/CORE/SME/inc/csrInternal.h | 1 + drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c | 5 +++++ drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 2 +- 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 92faaaa85619..30462702e488 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -994,6 +994,14 @@ typedef enum #define CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MIN (5) #define CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MAX (50) #define CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_DEFAULT (10) + +/* + * Minimum RSSI value below which candidate will not be eligible for roam + */ +#define CFG_PER_ROAM_BAD_RSSI "gPERMinRssiThresholdForRoam" +#define CFG_PER_ROAM_BAD_RSSI_MIN (-100) +#define CFG_PER_ROAM_BAD_RSSI_MAX (-40) +#define CFG_PER_ROAM_BAD_RSSI_DEFAULT (-80) #endif #define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME "PktClassificationBasis" // DSCP or 802.1Q @@ -3090,6 +3098,7 @@ typedef struct v_BOOL_t isPERRoamRxPathEnabled; v_BOOL_t isPERRoamCCAEnabled; v_S15_t PERRoamFullScanThreshold; + v_S15_t PERMinRssiThresholdForRoam; v_U16_t rateUpThreshold; v_U16_t rateDownThreshold; v_U16_t PERroamTriggerPercent; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index f68c005064fc..1fe84f0b94f0 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -2875,6 +2875,13 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_DEFAULT, CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MIN, CFG_PER_ROAM_FULL_SCAN_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_PER_ROAM_BAD_RSSI, WLAN_PARAM_SignedInteger, + hdd_config_t, PERMinRssiThresholdForRoam, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_BAD_RSSI_DEFAULT, + CFG_PER_ROAM_BAD_RSSI_MIN, + CFG_PER_ROAM_BAD_RSSI_MAX), #endif REG_VARIABLE( CFG_ENABLE_ADAPT_RX_DRAIN_NAME, WLAN_PARAM_Integer, @@ -4282,6 +4289,10 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) "Name = [gPERRoamFullScanThreshold] Value = [%u] ", pHddCtx->cfg_ini->PERRoamFullScanThreshold); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + "Name = [gPERMinRssiThresholdForRoam] Value = [%d] ", + pHddCtx->cfg_ini->PERMinRssiThresholdForRoam); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [gPERRoamScanInterval] Value = [%lu] ", (long unsigned int)pHddCtx->cfg_ini->waitPeriodForNextPERScan); diff --git a/drivers/staging/prima/CORE/SME/inc/csrApi.h b/drivers/staging/prima/CORE/SME/inc/csrApi.h index ef7f97d3dd37..73b65c58c088 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrApi.h +++ b/drivers/staging/prima/CORE/SME/inc/csrApi.h @@ -1191,6 +1191,7 @@ typedef struct tagCsrConfigParam v_BOOL_t isPERRoamEnabled; v_BOOL_t isPERRoamCCAEnabled; v_S15_t PERRoamFullScanThreshold; + v_S15_t PERMinRssiThresholdForRoam; v_U32_t rateUpThreshold; v_U32_t rateDownThreshold; v_U32_t waitPeriodForNextPERScan; diff --git a/drivers/staging/prima/CORE/SME/inc/csrInternal.h b/drivers/staging/prima/CORE/SME/inc/csrInternal.h index 318c25517c25..b2d7d1a6aafe 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrInternal.h +++ b/drivers/staging/prima/CORE/SME/inc/csrInternal.h @@ -627,6 +627,7 @@ typedef struct tagCsrConfig v_BOOL_t isPERRoamEnabled; v_BOOL_t isPERRoamCCAEnabled; v_S15_t PERRoamFullScanThreshold; + v_S15_t PERMinRssiThresholdForRoam; tANI_U32 rateUpThreshold; tANI_U32 rateDownThreshold; tANI_U32 waitPeriodForNextPERScan; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index 24e93f852195..87c6af3178cc 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -1965,6 +1965,9 @@ eHalStatus csrChangeDefaultConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pPa pParam->PERRoamFullScanThreshold; pMac->roam.configParam.PERroamTriggerPercent = pParam->PERroamTriggerPercent; + pMac->roam.configParam.PERMinRssiThresholdForRoam = + pParam->PERMinRssiThresholdForRoam; + pMac->PERroamTimeout = pParam->waitPeriodForNextPERScan; #endif #ifdef FEATURE_WLAN_LFR pMac->roam.configParam.isFastRoamIniFeatureEnabled = pParam->isFastRoamIniFeatureEnabled; @@ -2191,6 +2194,8 @@ eHalStatus csrGetConfigParam(tpAniSirGlobal pMac, tCsrConfigParam *pParam) pMac->roam.configParam.PERRoamFullScanThreshold; pParam->PERroamTriggerPercent = pMac->roam.configParam.PERroamTriggerPercent; + pParam->PERMinRssiThresholdForRoam = + pMac->roam.configParam.PERMinRssiThresholdForRoam; #endif #ifdef FEATURE_WLAN_LFR pParam->isFastRoamIniFeatureEnabled = pMac->roam.configParam.isFastRoamIniFeatureEnabled; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 984836e7625b..f25a4c1ed9d6 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -2208,7 +2208,7 @@ static tANI_S32 csrFindCongestionScore (tpAniSirGlobal pMac, tCsrScanResult *pBs return -1; } - if (bssInfo->rssi < PER_BAD_RSSI) { + if (bssInfo->rssi < pMac->roam.configParam.PERMinRssiThresholdForRoam) { smsLog(pMac, LOG1, FL("discrarding candidate due to low rssi=%d bssid " MAC_ADDRESS_STR), bssInfo->rssi, From b366846db6cd7d6b4353a4cee5e9b23860f32945 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Wed, 28 Dec 2016 12:52:13 +0530 Subject: [PATCH 127/281] wlan: Check for config support before sendig carrier off Presently, driver is doing carrier off in stop bss which may lead to framework to reload driver. Add check for configuation support for internal SAP restart before sending carrier off to framework so that framework won't do SAP reload. Change-Id: If1aa6267455b389b3662c049b733430b9e1b716c CRs-Fixed: 1103575 --- .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index b3499b92e3b7..1d116e76b16c 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -1291,7 +1291,19 @@ stopbss : /* Stop the pkts from n/w stack as we are going to free all of * the TX WMM queues for all STAID's */ - hdd_hostapd_stop(dev); + + /* + * If channel avoidance is in progress means driver is performing SAP + * restart. So don't do carrier off, which may lead framework to do + * driver reload. + */ + hddLog(LOG1, FL("ch avoid in progress: %d"), + pHddCtx->is_ch_avoid_in_progress); + if (pHddCtx->is_ch_avoid_in_progress && + pHddCtx->cfg_ini->sap_restrt_ch_avoid) + netif_tx_disable(dev); + else + hdd_hostapd_stop(dev); /* reclaim all resources allocated to the BSS */ vos_status = hdd_softap_stop_bss(pHostapdAdapter); @@ -1528,11 +1540,13 @@ static void hdd_unsafe_channel_restart_sap(hdd_adapter_t *adapter, adapter->sessionCtx.ap.sapConfig.channel = AUTO_CHANNEL_SELECT; - netif_tx_disable(adapter->dev); - if (hdd_ctx->cfg_ini->sap_restrt_ch_avoid) - schedule_work( - &hdd_ctx->sap_start_work); + if (hdd_ctx->cfg_ini->sap_restrt_ch_avoid) { + netif_tx_disable(adapter->dev); + schedule_work(&hdd_ctx->sap_start_work); + } else { + hdd_hostapd_stop(adapter->dev); + } return; } From a2fe7657cee2861265b16ee955eeb12fa2f88630 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Konamki Date: Fri, 9 Dec 2016 12:35:31 +0530 Subject: [PATCH 128/281] wlan: Replace time of the day with jiffies during scan reject Scan reject changes wrongly used time of the day timestamp for last_scan_reject_timestamp which leads to device crash if time is changed for device in between. Add changes to use jiffies instead of time of the day and intialize scan_reject_reason and scan_reject_session_id with proper values. Change-Id: Ic2d331e712c2762eca592a3a643c386d743d3ee7 CRs-Fixed: 1099854 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 4 ++-- drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c | 4 ++-- drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 0fb2c54a3b7e..c6e831cfbd46 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -13196,10 +13196,10 @@ int __wlan_hdd_cfg80211_scan( struct wiphy *wiphy, { pHddCtx->last_scan_reject_session_id = curr_session_id; pHddCtx->last_scan_reject_reason = curr_reason; - pHddCtx->last_scan_reject_timestamp = vos_timer_get_system_time(); + pHddCtx->last_scan_reject_timestamp = jiffies_to_msecs(jiffies); } else { - if ((vos_timer_get_system_time() - + if ((jiffies_to_msecs(jiffies) - pHddCtx->last_scan_reject_timestamp) >= SCAN_REJECT_THRESHOLD_TIME) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index 7ef39cdfae1a..ea945b563eeb 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2497,8 +2497,8 @@ VOS_STATUS hdd_wlan_re_init(void) /* Restart all adapters */ hdd_start_all_adapters(pHddCtx); - pHddCtx->last_scan_reject_session_id = 0; - pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; pHddCtx->last_scan_reject_timestamp = 0; pHddCtx->hdd_mcastbcast_filter_set = FALSE; pHddCtx->btCoexModeSet = FALSE; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 9593d6e4206c..46f569184391 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -11652,8 +11652,8 @@ int hdd_wlan_startup(struct device *dev ) ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx; pHddCtx->parent_dev = dev; - pHddCtx->last_scan_reject_session_id = 0; - pHddCtx->last_scan_reject_reason = 0xFF; + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; pHddCtx->last_scan_reject_timestamp = 0; init_completion(&pHddCtx->full_pwr_comp_var); From 5fce6f91f0e4639b0d4015b608ff4fc53fc81c83 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Fri, 6 Jan 2017 14:52:09 +0530 Subject: [PATCH 129/281] wlan: Request FW recovery after three mgmt TX timeout Sometimes due to frames stuck in station's BTQM queues TX channels are getting masked and resulting in TX time out for management frames. To recover from this send dump FW command to flush all the BTQM frames to unmask the channels. In this change send dump firmware BTQM flush command after three management frames TX timeout. Change-Id: I926a70790a09000583dcd8bef03543e24f122b9a CRs-Fixed: 1108399 --- drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 90f795a3d7fd..d9b72178efb2 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -90,7 +90,9 @@ /* Recover with ssr if tx timeouts continuously * for threshold number of times. */ -#define WDA_TX_FAILURE_RECOVERY_THRESHOLD 3 +#define WDA_TX_FAILURE_RECOVERY_THRESHOLD 5 +/* BTQM flush FW dump command */ +#define WDA_TX_FW_RECOVERY_THRESHOLD 3 #define IS_WDI_STATUS_FAILURE(status) \ ((WDI_STATUS_SUCCESS != (status)) && (WDI_STATUS_PENDING != (status))) @@ -14414,12 +14416,23 @@ VOS_STATUS WDA_TxPacket(tWDA_CbContext *pWDA, } pWDA->mgmtTxfailureCnt++; + /* Request firmware recovery */ + if (WDA_TX_FW_RECOVERY_THRESHOLD == + pWDA->mgmtTxfailureCnt) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Request firmware for recovery", __func__); + WLANTL_TLDebugMessage(WLANTL_DEBUG_FW_CLEANUP); + } + /* SSR if timeout continously for * WDA_TX_FAILURE_RECOVERY_THRESHOLD times. */ if (WDA_TX_FAILURE_RECOVERY_THRESHOLD == pWDA->mgmtTxfailureCnt) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Request system recovery", __func__); vos_wlanRestart(); } status = VOS_STATUS_E_FAILURE; From ea29bc466744b9232c9c8c21538e47a5d892aaf0 Mon Sep 17 00:00:00 2001 From: Deepthi Gowri Date: Wed, 9 Nov 2016 16:58:47 +0530 Subject: [PATCH 130/281] wlan: Enable DFS channel for a single channel scan In csrScanCopyRequest(), the DFS channels are ignored if ini parameter gSkipDfsChannelInP2pSearch is enabled. If the supplicant issues a single channel scan for a DFS channel, driver will do a full scan. As its a single channel scan which is a DFS channel would be ignored and the num of channels to scan would be zero. And if the number of channels to scan are zero, driver does a full scan which would impact the overall connection time. To address this, enable DFS channel for a single channel scan. CRs-Fixed: 1085450 Change-Id: Idf063f9d67797f1a1b678e5b8a837f05b9c65388 --- .../prima/CORE/SME/src/csr/csrApiScan.c | 203 ++++++++++-------- .../prima/CORE/SME/src/csr/csrInsideApi.h | 2 + 2 files changed, 115 insertions(+), 90 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index f25a4c1ed9d6..478c8662b13b 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -6822,98 +6822,60 @@ eHalStatus csrScanCopyRequest(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, tCs new_index = 0; pMac->roam.numValidChannels = len; - /* Since in CsrScanRequest,value of pMac->scan.nextScanID - * is incremented before calling CsrScanCopyRequest, as a - * result pMac->scan.nextScanID is equal to ONE for the - * first scan. If number of channels is less than - * max chan for dwell time no need to skip dfs - * in first scan as anyway few channels will be scanned and - * it will not take much time to display results on GUI. - */ - if (((pSrcReq->ChannelInfo.numOfChannels >= - pMac->roam.configParam.max_chan_for_dwell_time_cfg) && - (pMac->roam.configParam.initialScanSkipDFSCh && - 1 == pMac->scan.nextScanID)) ||(pMac->miracast_mode)) - { - smsLog(pMac, LOG1, - FL("Initial scan, scan only non-DFS channels")); - - for (index = 0; index < pSrcReq->ChannelInfo. - numOfChannels ; index++ ) - { - if((csrRoamIsValidChannel(pMac, pSrcReq->ChannelInfo. - ChannelList[index]))) - { - /*Skiipping DFS Channels for 1st scan */ - if(NV_CHANNEL_DFS == - vos_nv_getChannelEnabledState(pSrcReq->ChannelInfo. - ChannelList[index])) - continue ; - - pDstReq->ChannelInfo.ChannelList[new_index] = - pSrcReq->ChannelInfo.ChannelList[index]; - new_index++; - - } - } - pMac->roam.configParam.initialScanSkipDFSCh = 0; - } - else - { - for ( index = 0; index < pSrcReq->ChannelInfo. - numOfChannels ; index++ ) + /* Since in CsrScanRequest,value of pMac->scan. + * nextScanID is incremented before calling + * CsrScanCopyRequest, as a result pMac->scan. + * nextScanID is equal to ONE for the first scan. + * If number of channels is less than max chan + * for dwell time no need to skip dfs in first + * scan as anyway few channels will be scanned + * and it will not take much time to display + * results on GUI. + */ + if (((pSrcReq->ChannelInfo.numOfChannels >= + pMac->roam.configParam. + max_chan_for_dwell_time_cfg) && + (pMac->roam.configParam. + initialScanSkipDFSCh && + 1 == pMac->scan.nextScanID)) || + (pMac->miracast_mode)) { - /* Skip CH 144 if firmware support not present */ - if (pSrcReq->ChannelInfo.ChannelList[index] == 144 && !ch144_support) - continue; + smsLog(pMac, LOG1, + FL("Initial scan, scan only non-DFS channels")); - /* Allow scan on valid channels only. - */ - if ( ( csrRoamIsValidChannel(pMac, pSrcReq->ChannelInfo.ChannelList[index]) ) ) + for (index = 0; index < pSrcReq->ChannelInfo. + numOfChannels ; index++ ) { - if( ((pSrcReq->skipDfsChnlInP2pSearch || - (pMac->scan.fEnableDFSChnlScan == - DFS_CHNL_SCAN_DISABLED)) && - (NV_CHANNEL_DFS == vos_nv_getChannelEnabledState(pSrcReq->ChannelInfo.ChannelList[index])) ) -#ifdef FEATURE_WLAN_LFR - /* - * If LFR is requesting a contiguous scan - * (i.e. numOfChannels > 1), then ignore - * DFS channels. - * TODO: vos_nv_getChannelEnabledState is returning - * 120, 124 and 128 as non-DFS channels. Hence, the - * use of direct check for channels below. - */ - || ((eCSR_SCAN_HO_BG_SCAN == pSrcReq->requestType) && - (pSrcReq->ChannelInfo.numOfChannels > 1) && - (CSR_IS_CHANNEL_DFS(pSrcReq->ChannelInfo.ChannelList[index])) && - !pMac->roam.configParam.allowDFSChannelRoam) -#endif - ) + if((csrRoamIsValidChannel(pMac, + pSrcReq->ChannelInfo. + ChannelList[index]))) { -#ifdef FEATURE_WLAN_LFR - smsLog(pMac, LOG2, - FL(" reqType=%s (%d), numOfChannels=%d," - " ignoring DFS channel %d"), - sme_requestTypetoString(pSrcReq->requestType), - pSrcReq->requestType, - pSrcReq->ChannelInfo.numOfChannels, - pSrcReq->ChannelInfo.ChannelList[index]); -#endif - continue; - } + /*Skiipping DFS Channels for 1st scan */ + if(NV_CHANNEL_DFS == + vos_nv_getChannelEnabledState( + pSrcReq->ChannelInfo. + ChannelList[index])) + continue ; + + pDstReq->ChannelInfo. + ChannelList[new_index] = + pSrcReq->ChannelInfo.ChannelList[index]; + new_index++; - pDstReq->ChannelInfo.ChannelList[new_index] = - pSrcReq->ChannelInfo.ChannelList[index]; - new_index++; + } } + pMac->roam.configParam.initialScanSkipDFSCh = 0; } - } + else + csrValidateScanChannels(pMac, pDstReq, pSrcReq, + new_index, ch144_support); pDstReq->ChannelInfo.numOfChannels = new_index; #ifdef FEATURE_WLAN_LFR - if ( ( ( eCSR_SCAN_HO_BG_SCAN == pSrcReq->requestType ) || - ( eCSR_SCAN_P2P_DISCOVERY == pSrcReq->requestType ) ) && - ( 0 == pDstReq->ChannelInfo.numOfChannels ) ) + if ( ( ( eCSR_SCAN_HO_BG_SCAN == + pSrcReq->requestType ) || + ( eCSR_SCAN_P2P_DISCOVERY == + pSrcReq->requestType ) ) && + ( 0 == pDstReq->ChannelInfo.numOfChannels ) ) { /* * No valid channels found in the request. @@ -6924,16 +6886,17 @@ eHalStatus csrScanCopyRequest(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, tCs * all valid channels which is not desirable. */ smsLog(pMac, LOGE, FL(" no valid channels found" - " (request=%d)"), pSrcReq->requestType); - for ( index = 0; index < pSrcReq->ChannelInfo.numOfChannels ; index++ ) + " (request=%d)"), pSrcReq->requestType); + for ( index = 0; index < pSrcReq->ChannelInfo. + numOfChannels ; index++ ) { smsLog(pMac, LOGE, FL("pSrcReq index=%d" - " channel=%d"), index, - pSrcReq->ChannelInfo.ChannelList[index]); + " channel=%d"), index, + pSrcReq->ChannelInfo.ChannelList[index]); } status = eHAL_STATUS_FAILURE; break; - } + } #endif } else @@ -6943,8 +6906,9 @@ eHalStatus csrScanCopyRequest(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, tCs vos_mem_copy(pDstReq->ChannelInfo.ChannelList, pSrcReq->ChannelInfo.ChannelList, pSrcReq->ChannelInfo.numOfChannels - * sizeof(*pDstReq->ChannelInfo.ChannelList)); - pDstReq->ChannelInfo.numOfChannels = pSrcReq->ChannelInfo.numOfChannels; + * sizeof(*pDstReq->ChannelInfo.ChannelList)); + pDstReq->ChannelInfo.numOfChannels = + pSrcReq->ChannelInfo.numOfChannels; } }//Allocate memory for Channel List } @@ -9382,3 +9346,62 @@ void UpdateCCKMTSF(tANI_U32 *timeStamp0, tANI_U32 *timeStamp1, tANI_U32 *incr) *timeStamp1 = (tANI_U32)((timeStamp64 >> 32) & 0xffffffff); } #endif + +void csrValidateScanChannels(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, + tCsrScanRequest *pSrcReq, int new_index, tANI_U8 ch144_support) +{ + + int index; + for ( index = 0; index < pSrcReq->ChannelInfo. + numOfChannels ; index++ ) + { + /* Skip CH 144 if firmware support not present */ + if (pSrcReq->ChannelInfo.ChannelList[index] == 144 && !ch144_support) + continue; + + /* Allow scan on valid channels only. + */ + if ( ( csrRoamIsValidChannel(pMac, + pSrcReq->ChannelInfo.ChannelList[index]) ) ) + { + if( ((pSrcReq->skipDfsChnlInP2pSearch || + (pMac->scan.fEnableDFSChnlScan == + DFS_CHNL_SCAN_DISABLED)) && + (NV_CHANNEL_DFS == vos_nv_getChannelEnabledState( + pSrcReq->ChannelInfo.ChannelList[index])) && + (pSrcReq->ChannelInfo.numOfChannels > 1)) +#ifdef FEATURE_WLAN_LFR + /* + * If LFR is requesting a contiguous scan + * (i.e. numOfChannels > 1), then ignore + * DFS channels. + * TODO: vos_nv_getChannelEnabledState is returning + * 120, 124 and 128 as non-DFS channels. Hence, the + * use of direct check for channels below. + */ + || ((eCSR_SCAN_HO_BG_SCAN == pSrcReq->requestType) && + (pSrcReq->ChannelInfo.numOfChannels > 1) && + (CSR_IS_CHANNEL_DFS( + pSrcReq->ChannelInfo.ChannelList[index])) && + !pMac->roam.configParam.allowDFSChannelRoam) +#endif + ) + { +#ifdef FEATURE_WLAN_LFR + smsLog(pMac, LOG1, + FL(" reqType=%s (%d), numOfChannels=%d," + " ignoring DFS channel:%d"), + sme_requestTypetoString(pSrcReq->requestType), + pSrcReq->requestType, + pSrcReq->ChannelInfo.numOfChannels, + pSrcReq->ChannelInfo.ChannelList[index]); +#endif + continue; + } + + pDstReq->ChannelInfo.ChannelList[new_index] = + pSrcReq->ChannelInfo.ChannelList[index]; + new_index++; + } + } +} diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h index 9bd0e51ff4c6..f5de46939da5 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h +++ b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h @@ -1103,5 +1103,7 @@ void csr_remove_bssid_from_scan_list(tpAniSirGlobal pMac, #ifdef WLAN_FEATURE_AP_HT40_24G eHalStatus csrSetHT2040Mode(tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U8 cbMode); #endif +void csrValidateScanChannels(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, + tCsrScanRequest *pSrcReq, int new_index, tANI_U8 ch144_support); #endif From 90f5460b45826e1dbf9a5a8de7d2d9f14ea3d266 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Tue, 3 Jan 2017 11:26:38 +0530 Subject: [PATCH 131/281] wlan: Send proper IEs number when sec chan bcn filter is skipped Even if sec chan bcn filter is skipped the count of IEs sent to firmware include it. Due to this firmware assume that one extra IE is sent and as the value of buffer being 0 it assume the IE to be ssid. In case of some APs with malformed beacons the FW keeps on waking up the host assuming the SSID has change. To fix this if sec chan bcn filter is skipped, remove it from the total count of IEs sent. Change-Id: I01a3298ea5d02d36339691c006fd9222c84b71f0 CRs-Fixed: 1106798 --- .../staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c | 7 ++++++- drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c index 91e028be9b4d..3f064aa30131 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limSendMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -799,6 +799,7 @@ tSirRetStatus limSendBeaconFilterInfo(tpAniSirGlobal pMac,tpPESession psessionEn tANI_U32 i; tANI_U32 msgSize; tANI_BOOLEAN ignore_secchannel_bcn_filter = false; + bool filter_skipped = false; tpBeaconFilterIe pIe; tpDphHashNode pStaDs; @@ -874,6 +875,7 @@ tSirRetStatus limSendBeaconFilterInfo(tpAniSirGlobal pMac,tpPESession psessionEn { limLog( pMac, LOGW, FL("Skip Secondary Channel bcn filter when channel is 20Mhz")); + filter_skipped = true; continue; } pIe = (tpBeaconFilterIe) ptr; @@ -885,6 +887,9 @@ tSirRetStatus limSendBeaconFilterInfo(tpAniSirGlobal pMac,tpPESession psessionEn pIe->byte.ref = beaconFilterTable[i].byte.ref; ptr += sizeof(tBeaconFilterIe); } + if (filter_skipped) + pBeaconFilterMsg->ieNum--; + msgQ.type = WDA_BEACON_FILTER_IND; msgQ.reserved = 0; msgQ.bodyptr = pBeaconFilterMsg; diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index d9b72178efb2..555defd1ec4b 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -11267,6 +11267,7 @@ VOS_STATUS WDA_SetBeaconFilterReq(tWDA_CbContext *pWDA, vos_mem_free(wdiBeaconFilterInfo); return VOS_STATUS_E_NOMEM; } + vos_mem_zero(wdiBeaconFilterInfo, sizeof(WDI_BeaconFilterReqParamsType)); wdiBeaconFilterInfo->wdiBeaconFilterInfo.usBeaconInterval = pBeaconFilterInfo->beaconInterval; wdiBeaconFilterInfo->wdiBeaconFilterInfo.usCapabilityInfo = From bf1f8857834fd36194d91ee90ed8d57bf26c7bf4 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Mon, 5 Dec 2016 11:57:36 +0530 Subject: [PATCH 132/281] wlan: Add support for new cfg80211 connect api qcacld-2.0 to pronto propagation The new cfg80211 connect api 'cfg80211_connect_bss' takes a new input parameter, the connected bss. This is required for the kernel to map its current_bss to the bss on the correct channel when more than one bssid, ssid pair is present on different channels with the kernel. Without this the kernel might report a wrong channel as the associated channel. Hence add support in driver to use the new connect api. Change-Id: I1e5ded1b40ca324469917acebf17a03cc1e1c679 CRs-Fixed: 1008794 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 4 + .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 38 ++++----- .../prima/CORE/HDD/src/wlan_hdd_main.c | 78 ++++++++++++++++++- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 396111f4a686..fd19afad506f 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1732,6 +1732,10 @@ VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx ); +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + tCsrRoamInfo *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 * resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp); void hdd_dump_concurrency_info(hdd_context_t *pHddCtx); hdd_adapter_t * hdd_get_adapter_by_name( hdd_context_t *pHddCtx, tANI_U8 *name ); hdd_adapter_t * hdd_get_adapter_by_macaddr( hdd_context_t *pHddCtx, tSirMacAddr macAddr ); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 9b87c1692722..58d682d92afa 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -1815,11 +1815,11 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs { hddLog(LOG1, "%s ft_carrier_on is %d, sending connect " "indication", __FUNCTION__, ft_carrier_on); - cfg80211_connect_result(dev, pRoamInfo->bssid, - pFTAssocReq, assocReqlen, - pFTAssocRsp, assocRsplen, - WLAN_STATUS_SUCCESS, - GFP_KERNEL); + hdd_connect_result(dev, pRoamInfo->bssid, pRoamInfo, + pFTAssocReq, assocReqlen, + pFTAssocRsp, assocRsplen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); } } else @@ -1857,13 +1857,13 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs " result:%d and Status:%d", __func__, MAC_ADDR_ARRAY(pRoamInfo->bssid), roamResult, roamStatus); - /* inform connect result to nl80211 */ - cfg80211_connect_result(dev, pRoamInfo->bssid, - reqRsnIe, reqRsnLength, - rspRsnIe, rspRsnLength, - WLAN_STATUS_SUCCESS, - GFP_KERNEL); + hdd_connect_result(dev, pRoamInfo->bssid, + pRoamInfo, + reqRsnIe, reqRsnLength, + rspRsnIe, rspRsnLength, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); } } } @@ -2056,30 +2056,30 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs if ( eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == roamResult ) { if (pRoamInfo) - cfg80211_connect_result ( dev, pRoamInfo->bssid, + hdd_connect_result(dev, pRoamInfo->bssid, NULL, NULL, 0, NULL, 0, WLAN_STATUS_ASSOC_DENIED_UNSPEC, - GFP_KERNEL ); + GFP_KERNEL); else - cfg80211_connect_result ( dev, pWextState->req_bssId, + hdd_connect_result(dev, pWextState->req_bssId, NULL, NULL, 0, NULL, 0, WLAN_STATUS_ASSOC_DENIED_UNSPEC, - GFP_KERNEL ); + GFP_KERNEL); } else { if (pRoamInfo) - cfg80211_connect_result ( dev, pRoamInfo->bssid, + hdd_connect_result(dev, pRoamInfo->bssid, NULL, NULL, 0, NULL, 0, pRoamInfo->reasonCode ? pRoamInfo->reasonCode : WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL ); + GFP_KERNEL); else - cfg80211_connect_result ( dev, pWextState->req_bssId, + hdd_connect_result(dev, pWextState->req_bssId, NULL, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL ); + GFP_KERNEL); } /*Clear the roam profile*/ hdd_clearRoamProfileIe( pAdapter ); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 46f569184391..3d97e12d24cf 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -9480,6 +9480,82 @@ VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ) return VOS_STATUS_SUCCESS; } +/** + * hdd_connect_result() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @roam_info: information about connected bss + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * + * The API is a wrapper to send connection status to supplicant + * + * Return: Void + */ +#if defined CFG80211_CONNECT_BSS +void hdd_connect_result(struct net_device *dev, + const u8 *bssid, + tCsrRoamInfo *roam_info, + const u8 *req_ie, + size_t req_ie_len, + const u8 *resp_ie, + size_t resp_ie_len, + u16 status, + gfp_t gfp) +{ + hdd_adapter_t *padapter = (hdd_adapter_t *) netdev_priv(dev); + struct cfg80211_bss *bss = NULL; + + if (WLAN_STATUS_SUCCESS == status) { + struct ieee80211_channel *chan; + int freq; + int chan_no = roam_info->pBssDesc->channelId;; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_5GHZ); + + chan = ieee80211_get_channel(padapter->wdev.wiphy, freq); + + bss = cfg80211_get_bss(padapter->wdev.wiphy, chan, bssid, + roam_info->u.pConnectedProfile->SSID.ssId, + roam_info->u.pConnectedProfile->SSID.length, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) \ + && !defined(WITH_BACKPORTS) && !defined(IEEE80211_PRIVACY) + WLAN_CAPABILITY_ESS + WLAN_CAPABILITY_ESS); +#else + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); +#endif + } + + cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); +} +#else +void hdd_connect_result(struct net_device *dev, + const u8 *bssid, + tCsrRoamInfo *roam_info, + const u8 *req_ie, + size_t req_ie_len, + const u8 * resp_ie, + size_t resp_ie_len, + u16 status, + gfp_t gfp) +{ + cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); +} +#endif + VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) { hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; @@ -9536,7 +9612,7 @@ VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) * Indicate connect failure to supplicant if we were in the * process of connecting */ - cfg80211_connect_result(pAdapter->dev, NULL, + hdd_connect_result(pAdapter->dev, NULL, NULL, NULL, 0, NULL, 0, WLAN_STATUS_ASSOC_DENIED_UNSPEC, GFP_KERNEL); From cfb2923d513314fc64127b6b12a8e9cfa61ef6e7 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Mon, 5 Dec 2016 15:16:30 +0530 Subject: [PATCH 133/281] wlan: Use cfg80211_roamed_bss API to indicate the roaming After disconnect request, the driver sends disconnect indication to the kernel and it schedules a workqueue to process this disconnect event. Now if this workqueue is delayed and connect request is received before its scheduled, the disconnect event workqueue reset the ssid_len of the wdev. Now as the ssid_len does not match with bss ssid length the get bss returns NULL and thus roam indication is not sent to supplicant. To fix this use cfg80211_roamed_bss to indicate the roaming and use the ssid and ssid len from driver to get the bss. Change-Id: I5b88ce41951cb61582ee801be124ca0b5b6b825b CRs-Fixed: 1098150 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 4 ++ .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 27 +++++++-- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 12 +--- .../prima/CORE/HDD/src/wlan_hdd_main.c | 55 +++++++++++++++---- 4 files changed, 72 insertions(+), 26 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index fd19afad506f..b8316b80faa4 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1732,6 +1732,10 @@ VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ); VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx ); +struct cfg80211_bss* hdd_get_bss_entry(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len); void hdd_connect_result(struct net_device *dev, const u8 *bssid, tCsrRoamInfo *roam_info, const u8 *req_ie, size_t req_ie_len, const u8 * resp_ie, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 58d682d92afa..4fc44c2557a4 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -1500,7 +1500,10 @@ static void hdd_SendReAssocEvent(struct net_device *dev, hdd_adapter_t *pAdapter u8 *pFTAssocRsp = NULL; v_U8_t *rspRsnIe = kmalloc(IW_GENERIC_IE_MAX, GFP_KERNEL); tANI_U32 rspRsnLength = 0; + struct cfg80211_bss* bss; + tCsrRoamConnectedProfile roam_profile; struct ieee80211_channel *chan; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); if (!rspRsnIe) { hddLog(LOGE, "%s: Unable to allocate RSN IE", __func__); @@ -1534,8 +1537,15 @@ static void hdd_SendReAssocEvent(struct net_device *dev, hdd_adapter_t *pAdapter memcpy(rspRsnIe, pFTAssocRsp, len); memset(rspRsnIe + len, 0, IW_GENERIC_IE_MAX - len); - chan = ieee80211_get_channel(pAdapter->wdev.wiphy, (int) pCsrRoamInfo->pBssDesc->channelId); - cfg80211_roamed(dev,chan,pCsrRoamInfo->bssid, + chan = ieee80211_get_channel(pAdapter->wdev.wiphy, + (int) pCsrRoamInfo->pBssDesc->channelId); + vos_mem_zero(&roam_profile, sizeof(tCsrRoamConnectedProfile)); + sme_RoamGetConnectProfile(hHal, pAdapter->sessionId, &roam_profile); + bss = hdd_get_bss_entry(pAdapter->wdev.wiphy, + chan, pCsrRoamInfo->bssid, + &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + cfg80211_roamed_bss(dev, bss, reqRsnIe, reqRsnLength, rspRsnIe, rspRsnLength,GFP_KERNEL); @@ -1780,6 +1790,8 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs { if ( !hddDisconInProgress ) { + struct cfg80211_bss *roam_bss; + hddLog(LOG1, "%s ft_carrier_on is %d, sending roamed " "indication", __FUNCTION__, ft_carrier_on); chan = ieee80211_get_channel(pAdapter->wdev.wiphy, @@ -1791,9 +1803,14 @@ static eHalStatus hdd_AssociationCompletionHandler( hdd_adapter_t *pAdapter, tCs { vos_record_roam_event(e_HDD_SEND_REASSOC_RSP, NULL, 0); } - cfg80211_roamed(dev,chan, pRoamInfo->bssid, - pFTAssocReq, assocReqlen, pFTAssocRsp, assocRsplen, - GFP_KERNEL); + roam_bss = hdd_get_bss_entry(pAdapter->wdev.wiphy, + chan, pRoamInfo->bssid, + pRoamInfo->u.pConnectedProfile->SSID.ssId, + pRoamInfo->u.pConnectedProfile->SSID.length); + cfg80211_roamed_bss(dev, roam_bss, + pFTAssocReq, assocReqlen, + pFTAssocRsp, assocRsplen, + GFP_KERNEL); } if (sme_GetFTPTKState(WLAN_HDD_GET_HAL_CTX(pAdapter))) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index c6e831cfbd46..5669d069873e 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -12163,15 +12163,9 @@ struct cfg80211_bss* wlan_hdd_cfg80211_update_bss_list( struct wiphy *wiphy = wdev->wiphy; struct cfg80211_bss *bss = NULL; - bss = cfg80211_get_bss(wiphy, NULL, bssid, - NULL, - 0, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && !defined(WITH_BACKPORTS) \ - && !defined(IEEE80211_PRIVACY) - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); -#else - IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); -#endif + bss = hdd_get_bss_entry(wiphy, + NULL, bssid, + NULL, 0); if (bss == NULL) { hddLog(LOGE, FL("BSS not present")); } else { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 3d97e12d24cf..3ba6c403d711 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -9480,6 +9480,45 @@ VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ) return VOS_STATUS_SUCCESS; } +/** + * hdd_get_bss_entry() - Get the bss entry matching the chan, bssid and ssid + * @wiphy: wiphy + * @channel: channel of the BSS to find + * @bssid: bssid of the BSS to find + * @ssid: ssid of the BSS to find + * @ssid_len: ssid len of of the BSS to find + * + * The API is a wrapper to get bss from kernel matching the chan, + * bssid and ssid + * + * Return: Void + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) \ + && !defined(WITH_BACKPORTS) && !defined(IEEE80211_PRIVACY) + +struct cfg80211_bss* hdd_get_bss_entry(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); +} +#else +struct cfg80211_bss* hdd_get_bss_entry(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); +} +#endif + /** * hdd_connect_result() - API to send connection status to supplicant * @dev: network device @@ -9523,18 +9562,10 @@ void hdd_connect_result(struct net_device *dev, IEEE80211_BAND_5GHZ); chan = ieee80211_get_channel(padapter->wdev.wiphy, freq); - - bss = cfg80211_get_bss(padapter->wdev.wiphy, chan, bssid, - roam_info->u.pConnectedProfile->SSID.ssId, - roam_info->u.pConnectedProfile->SSID.length, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) \ - && !defined(WITH_BACKPORTS) && !defined(IEEE80211_PRIVACY) - WLAN_CAPABILITY_ESS - WLAN_CAPABILITY_ESS); -#else - IEEE80211_BSS_TYPE_ESS, - IEEE80211_PRIVACY_ANY); -#endif + bss = hdd_get_bss_entry(padapter->wdev.wiphy, + chan, bssid, + roam_info->u.pConnectedProfile->SSID.ssId, + roam_info->u.pConnectedProfile->SSID.length); } cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, From c77f3b9b5280dd19344f44cd5d21d18478185ca0 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Wed, 4 Jan 2017 15:27:13 +0530 Subject: [PATCH 134/281] wlan: Prioritize the bssid_hint, if it fails try with other BSS If connect request has bssid_hint the behaviour is same as when connect request has bssid present. So driver only tries to connect to BSSID present in the bssid_hint. With this change if bssid_hint is provided in connect request driver will prioritize connection to the BSSID provided and if it fails to connect to bssid_hint, driver will try to connect to other APs with same profile. Change-Id: Ie7fd29cdfb2013aca1d4944272da6b3c29a16ab3 CRs-Fixed: 1107816 --- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 35 +++++++++++-------- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 3 +- drivers/staging/prima/CORE/SME/inc/csrApi.h | 5 +-- .../prima/CORE/SME/src/csr/csrApiRoam.c | 4 ++- .../prima/CORE/SME/src/csr/csrApiScan.c | 18 +++++++++- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 5669d069873e..3db14725a318 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -13662,7 +13662,6 @@ int wlan_hdd_cfg80211_connect_start( hdd_adapter_t *pAdapter, v_U32_t roamId; tCsrRoamProfile *pRoamProfile; eCsrAuthType RSNAuthType; - const u8 *pValidBssid = NULL; ENTER(); @@ -13710,31 +13709,39 @@ int wlan_hdd_cfg80211_connect_start( hdd_adapter_t *pAdapter, vos_mem_copy((void *)(pRoamProfile->SSIDs.SSIDList->SSID.ssId), ssid, ssid_len); + vos_mem_zero(pRoamProfile->BSSIDs.bssid, WNI_CFG_BSSID_LEN); + vos_mem_zero(pRoamProfile->bssid_hint, WNI_CFG_BSSID_LEN); + if (bssid) - { - pValidBssid = bssid; - } - else if (bssid_hint) - { - pValidBssid = bssid_hint; - } - if (pValidBssid) { pRoamProfile->BSSIDs.numOfBSSIDs = 1; - vos_mem_copy((void *)(pRoamProfile->BSSIDs.bssid), pValidBssid, + vos_mem_copy(pRoamProfile->BSSIDs.bssid, bssid, WNI_CFG_BSSID_LEN); /* Save BSSID in seperate variable as well, as RoamProfile BSSID is getting zeroed out in the association process. And in case of join failure we should send valid BSSID to supplicant */ - vos_mem_copy((void *)(pWextState->req_bssId), pValidBssid, + vos_mem_copy(pWextState->req_bssId, bssid, WNI_CFG_BSSID_LEN); + } - else + else if (bssid_hint) { - vos_mem_zero((void *)(pRoamProfile->BSSIDs.bssid),WNI_CFG_BSSID_LEN); + /* Store bssid_hint to use in the scan filter. */ + vos_mem_copy(pRoamProfile->bssid_hint, bssid_hint, + WNI_CFG_BSSID_LEN); + /* + * Save BSSID in seperate variable as well, as RoamProfile + * BSSID is getting zeroed out in the association process. And in + * case of join failure we should send valid BSSID to supplicant + */ + vos_mem_copy(pWextState->req_bssId, bssid_hint, + WNI_CFG_BSSID_LEN); + hddLog(LOG1, FL(" bssid_hint: "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pRoamProfile->bssid_hint)); } + hddLog(LOG1, FL("Connect to SSID: %s opertating Channel: %u"), pRoamProfile->SSIDs.SSIDList->SSID.ssId, operatingChannel); if ((IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion) || diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 91bc35c891ce..b5e0fcc83116 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1539,6 +1539,7 @@ void hdd_clearRoamProfileIe( hdd_adapter_t *pAdapter) pWextState->roamProfile.AuthType.numEntries = 1; pWextState->roamProfile.AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + vos_mem_zero((pWextState->roamProfile.bssid_hint), WNI_CFG_BSSID_LEN); #ifdef WLAN_FEATURE_11W pWextState->roamProfile.MFPEnabled = eANI_BOOLEAN_FALSE; pWextState->roamProfile.MFPRequired = 0; diff --git a/drivers/staging/prima/CORE/SME/inc/csrApi.h b/drivers/staging/prima/CORE/SME/inc/csrApi.h index 73b65c58c088..bab7602f8708 100644 --- a/drivers/staging/prima/CORE/SME/inc/csrApi.h +++ b/drivers/staging/prima/CORE/SME/inc/csrApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -405,6 +405,7 @@ typedef struct tagCsrScanResultFilter #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD tANI_BOOLEAN isPERRoamScan; #endif + tCsrBssid bssid_hint; }tCsrScanResultFilter; @@ -958,7 +959,7 @@ typedef struct tagCsrRoamProfile tCsrMobilityDomainInfo MDID; #endif tVOS_CON_MODE csrPersona; - + tCsrBssid bssid_hint; }tCsrRoamProfile; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index 87c6af3178cc..ae9b6ddf1ab3 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -9563,6 +9563,8 @@ eHalStatus csrRoamPrepareFilterFromProfile(tpAniSirGlobal pMac, tCsrRoamProfile pScanFilter->MDID.mobilityDomain = pProfile->MDID.mobilityDomain; } #endif + vos_mem_copy(pScanFilter->bssid_hint, + pProfile->bssid_hint, VOS_MAC_ADDR_SIZE); #ifdef WLAN_FEATURE_11W // Management Frame Protection diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 478c8662b13b..5e2329d37bd5 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2689,6 +2689,14 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, LL_ACCESS_NOLOCK); } } + /* bssid hint AP should be on head */ + else if (pFilter && + vos_mem_compare(pResult->Result.BssDescriptor.bssId, + pFilter->bssid_hint, VOS_MAC_ADDR_SIZE)) + { + csrLLInsertHead(&pRetList->List, + &pResult->Link, LL_ACCESS_NOLOCK); + } else { //To sort the list @@ -2699,6 +2707,14 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, while(pTmpEntry) { pTmpResult = GET_BASE_ADDR( pTmpEntry, tCsrScanResult, Link ); + /* Skip the bssid hint AP, as it should be on head */ + if (pFilter && + vos_mem_compare(pResult->Result.BssDescriptor.bssId, + pFilter->bssid_hint, VOS_MAC_ADDR_SIZE)) { + pTmpEntry = csrLLNext(&pRetList->List, + pTmpEntry, LL_ACCESS_NOLOCK); + continue; + } #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD if (pFilter && pFilter->isPERRoamScan) { csrFindCongestionScore(pMac, pResult); From b9009bb6d0b1dca446fee4d110da232d221dae4f Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Thu, 12 Jan 2017 13:42:53 +0530 Subject: [PATCH 135/281] prima: Process pno ioctl appropriately propagation from qcacld-2.0 to prima While processing setpno ioctl, input arguments are not validated and also while parsing arguments, there is a possibility of Host accessing memory beyond memory allocated as there is no check whether is Host is accessing valid memory or not. Validate input arguments and make sure Host won't access invalid memory, while processing setpno ioctl. Change-Id: Ica9ea56283d55282cff3ccd349e4bc1c08b80e70 CRs-Fixed: 1097868 --- .../prima/CORE/HDD/inc/wlan_hdd_cfg80211.h | 6 +- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 59 +++++++++++++++---- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h index ab932ddb8784..f00390dcc22f 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -102,12 +102,14 @@ #define MAX_CHANNEL NUM_2_4GHZ_CHANNELS + NUM_5GHZ_CHANNELS +#define IS_CHANNEL_VALID(channel) ((channel >= 0 && channel < 15) \ + || (channel >= 36 && channel <= 184)) + #ifdef WLAN_FEATURE_LINK_LAYER_STATS /* Number of Radios */ #define NUM_RADIOS 0x1 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ - typedef struct { u8 element_id; u8 len; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index b5e0fcc83116..4d1162bcfe12 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -9681,8 +9681,9 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, serialized by the kernel rtnl_lock and hence does not need to be reentrant */ tSirPNOScanReq pnoRequest = {0}; - char *ptr; + char *ptr, *data; v_U8_t i,j, ucParams, ucMode; + size_t len; eHalStatus status = eHAL_STATUS_FAILURE; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -9727,12 +9728,25 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, scan every 5 seconds 2 times, scan every 300 seconds until stopped -----------------------------------------------------------------------*/ - ptr = extra + nOffset; - if (1 != sscanf(ptr,"%hhu%n", &(pnoRequest.enable), &nOffset)) + /* making sure argument string ends with '\0' */ + len = (wrqu->data.length-nOffset) + 1; + data = vos_mem_malloc(len); + if (NULL == data) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("fail to allocate memory %zu"), len); + return -EINVAL; + } + vos_mem_zero(data, len); + vos_mem_copy(data, &extra[nOffset], (len-1)); + data[len] = '\0'; + ptr = data; + + if (1 != sscanf(ptr," %hhu%n", &(pnoRequest.enable), &nOffset)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "PNO enable input is not valid %s",ptr); + vos_mem_free(data); return VOS_STATUS_E_FAILURE; } @@ -9748,9 +9762,11 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: failed to disable PNO", __func__); + vos_mem_free(data); return VOS_STATUS_E_FAILURE; } pHddCtx->isPnoEnable = FALSE; + vos_mem_free(data); return VOS_STATUS_SUCCESS; } @@ -9758,13 +9774,14 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, FL("already PNO is enabled")); + vos_mem_free(data); return -EBUSY; } pHddCtx->isPnoEnable = TRUE; ptr += nOffset; - if (1 != sscanf(ptr,"%hhu %n", &(pnoRequest.ucNetworksCount), &nOffset)) + if (1 != sscanf(ptr," %hhu %n", &(pnoRequest.ucNetworksCount), &nOffset)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "PNO count input not valid %s",ptr); @@ -9805,7 +9822,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, pnoRequest.aNetworks[i].ssId.length = 0; - ucParams = sscanf(ptr,"%hhu %n", + ucParams = sscanf(ptr," %hhu %n", &(pnoRequest.aNetworks[i].ssId.length),&nOffset); if (1 != ucParams) @@ -9831,7 +9848,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, pnoRequest.aNetworks[i].ssId.length); ptr += pnoRequest.aNetworks[i].ssId.length; - ucParams = sscanf(ptr,"%u %u %hhu %n", + ucParams = sscanf(ptr," %u %u %hhu %n", &(pnoRequest.aNetworks[i].authentication), &(pnoRequest.aNetworks[i].encryption), &(pnoRequest.aNetworks[i].ucChannelCount), @@ -9875,19 +9892,26 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, { for ( j = 0; j < pnoRequest.aNetworks[i].ucChannelCount; j++) { - if (1 != sscanf(ptr,"%hhu %n", + if (1 != sscanf(ptr," %hhu %n", &(pnoRequest.aNetworks[i].aChannels[j]), &nOffset)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "PNO network channel input is not valid %s",ptr); - goto error; + goto error; } + if (!IS_CHANNEL_VALID(pnoRequest.aNetworks[i].aChannels[j])) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("invalid channel: %hhu"), + pnoRequest.aNetworks[i].aChannels[j]); + goto error; + } + /*Advance to next channel number*/ ptr += nOffset; } } - if (1 != sscanf(ptr,"%u %n", + if (1 != sscanf(ptr," %u %n", &(pnoRequest.aNetworks[i].bcastNetwType), &nOffset)) { @@ -9895,6 +9919,12 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, "PNO broadcast network type input is not valid %s",ptr); goto error; } + if (pnoRequest.aNetworks[i].bcastNetwType > 2) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("invalid bcast nw type: %u"), + pnoRequest.aNetworks[i].bcastNetwType); + goto error; + } VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "PNO bcastNetwType %d offset %d", @@ -9904,7 +9934,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, /*Advance to rssi Threshold*/ ptr += nOffset; - if (1 != sscanf(ptr,"%hhu %n", + if (1 != sscanf(ptr," %hhu %n", &(pnoRequest.aNetworks[i].rssiThreshold), &nOffset)) { @@ -9921,7 +9951,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, ptr += nOffset; }/*For ucNetworkCount*/ - ucParams = sscanf(ptr,"%hhu %n", + ucParams = sscanf(ptr," %hhu %n", &(pnoRequest.scanTimers.ucScanTimersCount), &nOffset); @@ -9944,7 +9974,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, for ( i = 0; i < pnoRequest.scanTimers.ucScanTimersCount; i++ ) { - ucParams = sscanf(ptr,"%u %u %n", + ucParams = sscanf(ptr," %u %u %n", &(pnoRequest.scanTimers.aTimerValues[i].uTimerValue), &( pnoRequest.scanTimers.aTimerValues[i].uTimerRepeat), &nOffset); @@ -9978,7 +10008,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, pnoRequest.scanTimers.aTimerValues[0].uTimerRepeat = 0; } - ucParams = sscanf(ptr,"%hhu %n",&(ucMode), &nOffset); + ucParams = sscanf(ptr," %hhu %n",&(ucMode), &nOffset); pnoRequest.modePNO = ucMode; /*for LA we just expose suspend option*/ @@ -10012,6 +10042,7 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: PNO enabled", __func__); + vos_mem_free(data); return VOS_STATUS_SUCCESS; } error: @@ -10024,6 +10055,8 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, vos_mem_free(pnoRequest.p24GProbeTemplate); if (pnoRequest.p5GProbeTemplate) vos_mem_free(pnoRequest.p5GProbeTemplate); + + vos_mem_free(data); return VOS_STATUS_E_FAILURE; }/*iw_set_pno*/ From 8299019090da36d9df7f04c7e4de39156c746485 Mon Sep 17 00:00:00 2001 From: "Selvaraj, Sridhar" Date: Wed, 18 Jan 2017 13:11:25 +0530 Subject: [PATCH 136/281] wlan: Allow fastreassoc driver command for connected BSSID Currently host driver rejects fastreassoc driver command if the reassoc is for the connected BSSID. This is required for WMM cert test case. Allow fastreassoc driver command for connected BSSID case also. Change-Id: If45e433578c56002f055ef4d3cecf1bd86416509 CRs-Fixed: 1112899 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 3ba6c403d711..cf353fa678d4 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -3056,6 +3056,8 @@ static VOS_STATUS wlan_hdd_handle_fastreassoc(hdd_adapter_t *pAdapter, hdd_station_ctx_t *pHddStaCtx = NULL; hdd_context_t *pHddCtx = NULL; int ret; + tCsrRoamModifyProfileFields mod_profile_fields; + uint32_t roam_id = 0; pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); pHddCtx = WLAN_HDD_GET_CTX(pAdapter); @@ -3076,8 +3078,12 @@ static VOS_STATUS wlan_hdd_handle_fastreassoc(hdd_adapter_t *pAdapter, if (vos_mem_compare(targetApBssid, pHddStaCtx->conn_info.bssId, sizeof(tSirMacAddr))) { + sme_GetModifyProfileFields(pHddCtx->hHal, pAdapter->sessionId, + &mod_profile_fields); + sme_RoamReassoc(pHddCtx->hHal, pAdapter->sessionId, NULL, + mod_profile_fields, &roam_id, 1); hddLog(LOG1, FL("Reassoc BSSID is same as currently associated AP bssid")); - return eHAL_STATUS_FAILURE; + return eHAL_STATUS_SUCCESS; } /* Check channel number is a valid channel number */ From 8b3befb15e39316f940982bda98cf420bbbd71a2 Mon Sep 17 00:00:00 2001 From: Agrawal Ashish Date: Fri, 27 Jan 2017 12:52:25 +0530 Subject: [PATCH 137/281] wlan: Configure correct max tx power to firmware When processing link measurement request, driver should send the min value of AP's power in link measurement request, configured power and negotiated tx power at the time of join. Change-Id: I45d9e2e1e8f30e6aa52328212e74908d14f06559 CRs-Fixed: 1116747 --- .../MAC/src/pe/lim/limProcessSmeReqMessages.c | 11 +-- .../prima/CORE/MAC/src/pe/rrm/rrmApi.c | 70 +++++-------------- .../CORE/MAC/src/pe/sch/schBeaconProcess.c | 5 +- .../prima/CORE/SME/src/csr/csrApiRoam.c | 4 +- .../prima/CORE/WDA/inc/legacy/halTypes.h | 9 ++- 5 files changed, 31 insertions(+), 68 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c index 72840abcec44..1eafb0ef6787 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -76,13 +76,6 @@ #include #endif -#ifdef FEATURE_WLAN_ESE -/* These are the min/max tx power (non virtual rates) range - supported by prima hardware */ -#define MIN_TX_PWR_CAP 8 -#define MAX_TX_PWR_CAP 22 - -#endif #define JOIN_FAILURE_TIMEOUT 1000 // in msecs /* This overhead is time for sending NOA start to host in case of GO/sending NULL data & receiving ACK @@ -2192,7 +2185,7 @@ __limProcessSmeJoinReq(tpAniSirGlobal pMac, tANI_U32 *pMsgBuf) } /*** end __limProcessSmeJoinReq() ***/ -#ifdef FEATURE_WLAN_ESE +#if defined FEATURE_WLAN_ESE || defined WLAN_FEATURE_VOWIFI tANI_U8 limGetMaxTxPower(tPowerdBm regMax, tPowerdBm apTxPower, tANI_U8 iniTxPower) { tANI_U8 maxTxPower = 0; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/rrm/rrmApi.c b/drivers/staging/prima/CORE/MAC/src/pe/rrm/rrmApi.c index d094864e419e..435163546345 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/rrm/rrmApi.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/rrm/rrmApi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -282,59 +282,25 @@ rrmProcessLinkMeasurementRequest( tpAniSirGlobal pMac, return eSIR_FAILURE; } pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo ); - if( (uint8)(pSessionEntry->maxTxPower) != pLinkReq->MaxTxPower.maxTxPower ) + LinkReport.txPower = limGetMaxTxPower (pSessionEntry->maxTxPower, + pLinkReq->MaxTxPower.maxTxPower, + pMac->roam.configParam.nTxPowerCap); + + if ((LinkReport.txPower != (uint8)(pSessionEntry->maxTxPower)) && + (eSIR_SUCCESS == rrmSendSetMaxTxPowerReq (pMac, + (tPowerdBm)(LinkReport.txPower), + pSessionEntry))) { - PELOGW(limLog( pMac, - LOGW, - FL(" maxTx power in link request is not same as local... " - " Local = %d LinkReq = %d"), - pSessionEntry->maxTxPower, - pLinkReq->MaxTxPower.maxTxPower );) - if( (MIN_STA_PWR_CAP_DBM <= pLinkReq->MaxTxPower.maxTxPower) && - (MAX_STA_PWR_CAP_DBM >= pLinkReq->MaxTxPower.maxTxPower) ) - { - LinkReport.txPower = pLinkReq->MaxTxPower.maxTxPower; - } - else if( MIN_STA_PWR_CAP_DBM > pLinkReq->MaxTxPower.maxTxPower ) - { - LinkReport.txPower = MIN_STA_PWR_CAP_DBM; - } - else if( MAX_STA_PWR_CAP_DBM < pLinkReq->MaxTxPower.maxTxPower ) - { - LinkReport.txPower = MAX_STA_PWR_CAP_DBM; - } - - if( (LinkReport.txPower != (uint8)(pSessionEntry->maxTxPower)) && - (eSIR_SUCCESS == rrmSendSetMaxTxPowerReq ( pMac, - (tPowerdBm)(LinkReport.txPower), - pSessionEntry)) ) - { - pSessionEntry->maxTxPower = (tPowerdBm)(LinkReport.txPower); - } + PELOGW (limLog (pMac, + LOGW, + FL(" maxTx power in link report is not same as local..." + " Local = %d Link Request TxPower = %d" + " Link Report TxPower = %d"), + pSessionEntry->maxTxPower, + LinkReport.txPower, + pLinkReq->MaxTxPower.maxTxPower);) + pSessionEntry->maxTxPower = (tPowerdBm)(LinkReport.txPower); } - else - { - if( (MIN_STA_PWR_CAP_DBM <= (uint8)(pSessionEntry->maxTxPower)) && - (MAX_STA_PWR_CAP_DBM >= (uint8)(pSessionEntry->maxTxPower)) ) - { - LinkReport.txPower = (uint8)(pSessionEntry->maxTxPower); - } - else if( MIN_STA_PWR_CAP_DBM > (uint8)(pSessionEntry->maxTxPower) ) - { - LinkReport.txPower = MIN_STA_PWR_CAP_DBM; - } - else if( MAX_STA_PWR_CAP_DBM < (uint8)(pSessionEntry->maxTxPower) ) - { - LinkReport.txPower = MAX_STA_PWR_CAP_DBM; - } - } - PELOGW(limLog( pMac, - LOGW, - FL(" maxTx power in link request is not same as local... " - " Local = %d Link Report TxPower = %d"), - pSessionEntry->maxTxPower, - LinkReport.txPower );) - LinkReport.dialogToken = pLinkReq->DialogToken.token; LinkReport.rxAntenna = 0; LinkReport.txAntenna = 0; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c index 8d3230947d16..79f1ae8b0e6b 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/sch/schBeaconProcess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -656,7 +656,8 @@ static void __schBeaconProcessForSession( tpAniSirGlobal pMac, { localRRMConstraint = 0; } - maxTxPower = VOS_MIN(regMax,(regMax - localRRMConstraint)); + maxTxPower = limGetMaxTxPower(regMax, regMax - localRRMConstraint, + pMac->roam.configParam.nTxPowerCap); } #elif defined FEATURE_WLAN_ESE maxTxPower = regMax; diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index ae9b6ddf1ab3..9e8e305f80b7 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c @@ -13224,7 +13224,7 @@ static void csrPrepareJoinReassocReqBuffer( tpAniSirGlobal pMac, // corresponds to --- pMsg->spectrumMgtIndicator = ON; vos_mem_copy(pBuf, (tANI_U8 *)&fTmp, sizeof(tAniBool)); pBuf += sizeof(tAniBool); - *pBuf++ = MIN_STA_PWR_CAP_DBM; // it is for pMsg->powerCap.minTxPower = 0; + *pBuf++ = MIN_TX_PWR_CAP; // it is for pMsg->powerCap.minTxPower = 0; found = csrSearchChannelListForTxPower(pMac, pBssDescription, &channelGroup); // This is required for 11k test VoWiFi Ent: Test 2. // We need the power capabilities for Assoc Req. @@ -13237,7 +13237,7 @@ static void csrPrepareJoinReassocReqBuffer( tpAniSirGlobal pMac, } else { - *pBuf++ = MAX_STA_PWR_CAP_DBM; + *pBuf++ = MAX_TX_PWR_CAP; } size = sizeof(pMac->roam.validChannelList); if(HAL_STATUS_SUCCESS(csrGetCfgValidChannels(pMac, (tANI_U8 *)pMac->roam.validChannelList, &size))) diff --git a/drivers/staging/prima/CORE/WDA/inc/legacy/halTypes.h b/drivers/staging/prima/CORE/WDA/inc/legacy/halTypes.h index b2fb3377289b..804925a4f933 100644 --- a/drivers/staging/prima/CORE/WDA/inc/legacy/halTypes.h +++ b/drivers/staging/prima/CORE/WDA/inc/legacy/halTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -348,8 +348,11 @@ typedef enum #define HAL_MAX_TXPOWER_INVALID 127 -#define MIN_STA_PWR_CAP_DBM 13 -#define MAX_STA_PWR_CAP_DBM 19 +/* These are the min/max tx power (non virtual rates) range + * supported by rome/prima hardware + */ +#define MIN_TX_PWR_CAP 8 +#define MAX_TX_PWR_CAP 30 /* Moving the miscellaneous defination required by UMAC are moved here from * volansdefs.h */ From b48a3163415d3fd25de1eb0bf80ca8dd1852f43a Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Tue, 24 Jan 2017 10:07:08 +0530 Subject: [PATCH 138/281] wlan: Fix bssid hint logic to keep the AP on head of the list Driver uses pResult to make sure that the bssid hint AP remains on the head. But as pResult is the new entry that need to be added it doesn't effect the bssid hint AP. To fix it use pTmpResult instead of pResult. Change-Id: I166ace17c2fe5c9afac29f651b99c1b6c0fbb5f5 CRs-Fixed: 1114660 --- drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 5e2329d37bd5..2d2e5f8272b7 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -2708,8 +2708,8 @@ eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, { pTmpResult = GET_BASE_ADDR( pTmpEntry, tCsrScanResult, Link ); /* Skip the bssid hint AP, as it should be on head */ - if (pFilter && - vos_mem_compare(pResult->Result.BssDescriptor.bssId, + if (pFilter && vos_mem_compare( + pTmpResult->Result.BssDescriptor.bssId, pFilter->bssid_hint, VOS_MAC_ADDR_SIZE)) { pTmpEntry = csrLLNext(&pRetList->List, pTmpEntry, LL_ACCESS_NOLOCK); From 1fdf3243803e5936d11143c1802698c1f6813a8f Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Tue, 9 Aug 2016 18:19:04 +0530 Subject: [PATCH 139/281] wlan: Remove the support for iw_set_priv ioctl iw_set_priv is obsolete, now hdd_ioctl handles the driver commands. Remove the code related to iw_set_priv ioctl CRs-Fixed: 1048052 Change-Id: I3e50fdc2f648ace1b6c260e3d579d93d8e546446 --- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 393 +----------------- 1 file changed, 1 insertion(+), 392 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 4d1162bcfe12..5828a8b058ad 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -3775,70 +3775,6 @@ static int iw_get_linkspeed_priv(struct net_device *dev, return ret; } -/* - * Support for the RSSI & RSSI-APPROX private commands - * Per the WiFi framework the response must be of the form - * " rssi " - * unless we are not associated, in which case the response is - * "OK" - */ -static int iw_get_rssi(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - char *cmd = extra; - int len = wrqu->data.length; - v_S7_t s7Rssi = 0; - hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length; - VOS_STATUS vosStatus; - int rc; - - if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) || - (0 == ssidlen) || (ssidlen >= len)) - { - /* we are not connected or our SSID is too long - so we cannot report an rssi */ - rc = scnprintf(cmd, len, "OK"); - } - else - { - /* we are connected with a valid SSID - so we can write the SSID into the return buffer - (note that it is not NUL-terminated) */ - memcpy(cmd, pHddStaCtx->conn_info.SSID.SSID.ssId, ssidlen ); - - wlan_hdd_get_station_stats(pAdapter); - vosStatus = wlan_hdd_get_rssi(pAdapter, &s7Rssi); - - if (VOS_STATUS_SUCCESS == vosStatus) - { - /* append the rssi to the ssid in the format required by - the WiFI Framework */ - rc = scnprintf(&cmd[ssidlen], len - ssidlen, " rssi %d", s7Rssi); - rc += ssidlen; - } - else - { - rc = -1; - } - } - - /* verify that we wrote a valid response */ - if ((rc < 0) || (rc >= len)) - { - // encoding or length error? - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Unable to encode RSSI, got [%s]", - __func__, cmd); - return -EIO; - } - - /* a value is being successfully returned */ - return rc; -} - /* * Support for SoftAP channel range private command */ @@ -4277,333 +4213,6 @@ void* wlan_hdd_change_country_code_callback(void *pAdapter) return NULL; } -static int __iw_set_priv(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - hdd_adapter_t *pAdapter; - char *cmd = NULL; - int cmd_len = wrqu->data.length; - int rc = 0, ret = 0; - VOS_STATUS vos_status = VOS_STATUS_SUCCESS; - - hdd_context_t *pHddCtx; - - ENTER(); - - pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); - if (NULL == pAdapter) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "mem_alloc_copy_from_user_helper fail"); - return -EINVAL; - } - pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - rc = wlan_hdd_validate_context(pHddCtx); - if (0 != rc) - { - return rc; - } - - cmd = mem_alloc_copy_from_user_helper(wrqu->data.pointer, - wrqu->data.length); - if (NULL == cmd) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "mem_alloc_copy_from_user_helper fail"); - return -ENOMEM; - } - - if (ioctl_debug) - { - pr_info("%s: req [%s] len [%d]\n", __func__, cmd, cmd_len); - } - - hddLog(VOS_TRACE_LEVEL_INFO_MED, - "%s: ***Received %s cmd from Wi-Fi GUI***", __func__, cmd); - - if (strncmp(cmd, "CSCAN", 5) == 0 ) - { - if (eHAL_STATUS_SUCCESS != iw_set_cscan(dev, info, wrqu, cmd)) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "%s: Error in iw_set_scan!", __func__); - rc = -EINVAL; - } - } - else if( strcasecmp(cmd, "start") == 0 ) { - - hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "Start command"); - /*Exit from Deep sleep or standby if we get the driver START cmd from android GUI*/ - - vos_status = wlan_hdd_exit_lowpower(pHddCtx, pAdapter); - if (vos_status == VOS_STATUS_SUCCESS) - { - union iwreq_data wrqu; - char buf[10]; - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlcpy(buf, "START", sizeof(buf)); - wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); - } - else - { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s: START CMD Status %d", __func__, vos_status); - rc = -EIO; - } - goto done; - } - else if( strcasecmp(cmd, "stop") == 0 ) - { - union iwreq_data wrqu; - char buf[10]; - - hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "Stop command"); - - wlan_hdd_enter_lowpower(pHddCtx); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlcpy(buf, "STOP", sizeof(buf)); - wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); - goto done; - } - else if (strcasecmp(cmd, "macaddr") == 0) - { - ret = snprintf(cmd, cmd_len, "Macaddr = " MAC_ADDRESS_STR, - MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes)); - } - else if (strcasecmp(cmd, "scan-active") == 0) - { - hddLog(LOG1, - FL("making default scan to active")); - pHddCtx->scan_info.scan_mode = eSIR_ACTIVE_SCAN; - ret = snprintf(cmd, cmd_len, "OK"); - } - else if (strcasecmp(cmd, "scan-passive") == 0) - { - hddLog(LOG1, - FL("making default scan to passive")); - pHddCtx->scan_info.scan_mode = eSIR_PASSIVE_SCAN; - ret = snprintf(cmd, cmd_len, "OK"); - } - else if( strcasecmp(cmd, "scan-mode") == 0 ) - { - ret = snprintf(cmd, cmd_len, "ScanMode = %u", pHddCtx->scan_info.scan_mode); - } - else if( strcasecmp(cmd, "linkspeed") == 0 ) - { - ret = iw_get_linkspeed(dev, info, wrqu, cmd); - } - else if( strncasecmp(cmd, "rssi", 4) == 0 ) - { - ret = iw_get_rssi(dev, info, wrqu, cmd); - } - else if( strncasecmp(cmd, "powermode", 9) == 0 ) { - int mode; - char *ptr; - - if (9 < cmd_len) - { - ptr = (char*)(cmd + 9); - - }else{ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "CMD LENGTH %d is not correct",cmd_len); - kfree(cmd); - return -EINVAL; - } - - if (1 != sscanf(ptr,"%d",&mode)) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "powermode input %s is not correct",ptr); - kfree(cmd); - return -EIO; - } - - wlan_hdd_enter_bmps(pAdapter, mode); - /*TODO:Set the power mode*/ - } - else if (strncasecmp(cmd, "getpower", 8) == 0 ) { - v_U32_t pmc_state; - v_U16_t value; - - pmc_state = pmcGetPmcState(WLAN_HDD_GET_HAL_CTX(pAdapter)); - if(pmc_state == BMPS) { - value = DRIVER_POWER_MODE_AUTO; - } - else { - value = DRIVER_POWER_MODE_ACTIVE; - } - ret = snprintf(cmd, cmd_len, "powermode = %u", value); - } - else if( strncasecmp(cmd, "btcoexmode", 10) == 0 ) { - hddLog( VOS_TRACE_LEVEL_INFO, "btcoexmode"); - /*TODO: set the btcoexmode*/ - } - else if( strcasecmp(cmd, "btcoexstat") == 0 ) { - - hddLog(VOS_TRACE_LEVEL_INFO, "BtCoex Status"); - /*TODO: Return the btcoex status*/ - } - else if( strcasecmp(cmd, "rxfilter-start") == 0 ) { - - hddLog(VOS_TRACE_LEVEL_INFO, "Rx Data Filter Start command"); - - /*TODO: Enable Rx data Filter*/ - } - else if( strcasecmp(cmd, "rxfilter-stop") == 0 ) { - - hddLog(VOS_TRACE_LEVEL_INFO, "Rx Data Filter Stop command"); - - /*TODO: Disable Rx data Filter*/ - } - else if( strcasecmp(cmd, "rxfilter-statistics") == 0 ) { - - hddLog( VOS_TRACE_LEVEL_INFO, "Rx Data Filter Statistics command"); - /*TODO: rxfilter-statistics*/ - } - else if( strncasecmp(cmd, "rxfilter-add", 12) == 0 ) { - - hddLog( VOS_TRACE_LEVEL_INFO, "rxfilter-add"); - /*TODO: rxfilter-add*/ - } - else if( strncasecmp(cmd, "rxfilter-remove",15) == 0 ) { - - hddLog( VOS_TRACE_LEVEL_INFO, "rxfilter-remove"); - /*TODO: rxfilter-remove*/ - } -#ifdef FEATURE_WLAN_SCAN_PNO - else if( strncasecmp(cmd, "pnosetup", 8) == 0 ) { - hddLog( VOS_TRACE_LEVEL_INFO, "pnosetup"); - /*TODO: support pnosetup*/ - } - else if( strncasecmp(cmd, "pnoforce", 8) == 0 ) { - hddLog( VOS_TRACE_LEVEL_INFO, "pnoforce"); - /*TODO: support pnoforce*/ - } - else if( strncasecmp(cmd, "pno",3) == 0 ) { - - hddLog( VOS_TRACE_LEVEL_INFO, "pno"); - vos_status = iw_set_pno(dev, info, wrqu, cmd, 3); - kfree(cmd); - return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; - } - else if( strncasecmp(cmd, "rssifilter",10) == 0 ) { - hddLog( VOS_TRACE_LEVEL_INFO, "rssifilter"); - vos_status = iw_set_rssi_filter(dev, info, wrqu, cmd, 10); - kfree(cmd); - return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; - } -#endif /*FEATURE_WLAN_SCAN_PNO*/ - else if( strncasecmp(cmd, "powerparams",11) == 0 ) { - hddLog( VOS_TRACE_LEVEL_INFO, "powerparams"); - vos_status = iw_set_power_params(dev, info, wrqu, cmd, 11); - kfree(cmd); - return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; - } - else if( 0 == strncasecmp(cmd, "CONFIG-TX-TRACKING", 18) ) { - tSirTxPerTrackingParam tTxPerTrackingParam; - char *ptr; - - if (18 < cmd_len) - { - ptr = (char*)(cmd + 18); - }else{ - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "CMD LENGTH %d is not correct",cmd_len); - kfree(cmd); - return -EINVAL; - } - - if (4 != sscanf(ptr,"%hhu %hhu %hhu %u", - &(tTxPerTrackingParam.ucTxPerTrackingEnable), - &(tTxPerTrackingParam.ucTxPerTrackingPeriod), - &(tTxPerTrackingParam.ucTxPerTrackingRatio), - &(tTxPerTrackingParam.uTxPerTrackingWatermark))) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, - "CONFIG-TX-TRACKING %s input is not correct",ptr); - kfree(cmd); - return -EIO; - } - - // parameters checking - // period has to be larger than 0 - if (0 == tTxPerTrackingParam.ucTxPerTrackingPeriod) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Period input is not correct"); - kfree(cmd); - return -EIO; - } - - // use default value 5 is the input is not reasonable. in unit of 10% - if ((tTxPerTrackingParam.ucTxPerTrackingRatio > TX_PER_TRACKING_MAX_RATIO) || (0 == tTxPerTrackingParam.ucTxPerTrackingRatio)) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Ratio input is not good. use default 5"); - tTxPerTrackingParam.ucTxPerTrackingRatio = TX_PER_TRACKING_DEFAULT_RATIO; - } - - // default is 5 - if (0 == tTxPerTrackingParam.uTxPerTrackingWatermark) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Tx Packet number input is not good. use default 5"); - tTxPerTrackingParam.uTxPerTrackingWatermark = TX_PER_TRACKING_DEFAULT_WATERMARK; - } - - if (eHAL_STATUS_SUCCESS != - sme_SetTxPerTracking(pHddCtx->hHal, - hdd_tx_per_hit_cb, - (void*)pAdapter, &tTxPerTrackingParam)) { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Set Tx PER Tracking Failed!"); - rc = -EIO; - } - } - else { - hddLog( VOS_TRACE_LEVEL_WARN, "%s: Unsupported GUI command %s", - __func__, cmd); - } -done: - /* many of the commands write information back into the command - string using snprintf(). check the return value here in one - place */ - if ((ret < 0) || (ret >= cmd_len)) - { - /* there was an encoding error or overflow */ - rc = -EINVAL; - } - else if (ret > 0) - { - if (copy_to_user(wrqu->data.pointer, cmd, ret)) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: failed to copy data to user buffer", __func__); - kfree(cmd); - return -EFAULT; - } - wrqu->data.length = ret; - } - - if (ioctl_debug) - { - pr_info("%s: rsp [%s] len [%d] status %d\n", - __func__, cmd, wrqu->data.length, rc); - } - kfree(cmd); - EXIT(); - return rc; -} - -static int iw_set_priv(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - vos_ssr_protect(__func__); - ret = __iw_set_priv(dev, info, wrqu, extra); - vos_ssr_unprotect(__func__); - - return ret; -} - static int __iw_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -10842,7 +10451,7 @@ static const iw_handler we_handler[] = (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL, /* SIOCSIWRANGE */ (iw_handler) iw_get_range, /* SIOCGIWRANGE */ - (iw_handler) iw_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCSIWPRIV */ (iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCSIWSTATS */ (iw_handler) NULL, /* SIOCGIWSTATS */ From e0890387431914a5f28fc8b2accd050d5b2d5734 Mon Sep 17 00:00:00 2001 From: c_manjee Date: Wed, 25 Jan 2017 12:25:27 +0530 Subject: [PATCH 140/281] wlan: Add NULL check for tail, probe response and assoc response In wlan_hdd_cfg80211_alloc_new_beacon API, tail or proberesp_ies or assocresp_ies can be NULL and dereferenced by passing to memcpy Add NULL check for tail and proberesp_ies and assocresp_ies. CRs-Fixed: 1115270 Change-Id: I90d3946a2aaca4fe93113da3b351343d281917a5 --- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 3db14725a318..395fa7b2aac4 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -8474,10 +8474,14 @@ int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, beacon->proberesp_ies_len = proberesp_ies_len; beacon->assocresp_ies_len= assocresp_ies_len; - memcpy(beacon->head, head, head_len); - memcpy(beacon->tail, tail, tail_len); - memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); - memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); + if (head && head_len) + memcpy(beacon->head, head, head_len); + if (tail && tail_len) + memcpy(beacon->tail, tail, tail_len); + if (proberesp_ies && proberesp_ies_len) + memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); + if (assocresp_ies && assocresp_ies_len) + memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); *ppBeacon = beacon; From 5524456e093baaca143b33072d935ee31680dfcd Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Thu, 19 Jan 2017 15:25:25 +0530 Subject: [PATCH 141/281] prima: Resolve out of bound memory access, while processing setpno propagation from qcacld-2.0 to prima While processing setpno ioctl, there is an out of bound memory issue when Host is copying ioctl arguments to a local buffer. While copying ioctl arguments, make sure valid indices are used. Change-Id: I03078df7135f5f1daf1d9bead7d4410e58fb848a CRs-Fixed: 1112355 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 5828a8b058ad..a1510f0cea39 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -9348,7 +9348,6 @@ VOS_STATUS iw_set_pno(struct net_device *dev, struct iw_request_info *info, } vos_mem_zero(data, len); vos_mem_copy(data, &extra[nOffset], (len-1)); - data[len] = '\0'; ptr = data; if (1 != sscanf(ptr," %hhu%n", &(pnoRequest.enable), &nOffset)) From 455519343f3e94c043bb08971f601a8b5f737de2 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Wed, 18 Jan 2017 16:16:08 +0530 Subject: [PATCH 142/281] wlan: Add support in driver to do sap restart during SSR qcacld-2.0 to prima propagation Presently, during subsystem restart Host is sending sap restart indication to framework(via carrier off) to do SAP unload/load. But SAP restart functionality is removed in framework when the carrier off event is received, leading SAP fails to come-up after subsystem restart. Add support in driver to do SAP restart internally without sending restart indication to framework, during subsystem restart. This feature is controlled by ini param 'gEnableSapInternalRestart' and by default it's enabled. Change-Id: I76cb73c1887d4d8124cd9a1c29b9aac47642072a CRs-Fixed: 1105651 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h | 12 +- .../prima/CORE/HDD/inc/wlan_hdd_hostapd.h | 4 + .../prima/CORE/HDD/inc/wlan_hdd_main.h | 5 +- .../staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 17 +-- .../CORE/HDD/src/wlan_hdd_early_suspend.c | 36 +++++- .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 108 +++++++++++++++++- .../prima/CORE/HDD/src/wlan_hdd_main.c | 86 +++++++++++++- 7 files changed, 247 insertions(+), 21 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 30462702e488..e0128541cc97 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2871,10 +2871,10 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ #define CFG_SAP_PROBE_RESP_OFFLOAD_MAX (1) #define CFG_SAP_PROBE_RESP_OFFLOAD_DEFAULT (1) -#define CFG_CH_AVOID_SAP_RESTART_NAME "sap_ch_avoid_restart" -#define CFG_CH_AVOID_SAP_RESTART_MIN (0) -#define CFG_CH_AVOID_SAP_RESTART_MAX (1) -#define CFG_CH_AVOID_SAP_RESTART_DEFAULT (1) +#define CFG_SAP_INTERNAL_RESTART_NAME "gEnableSapInternalRestart" +#define CFG_SAP_INTERNAL_RESTART_MIN (0) +#define CFG_SAP_INTERNAL_RESTART_MAX (1) +#define CFG_SAP_INTERNAL_RESTART_DEFAULT (1) /*--------------------------------------------------------------------------- Type declarations @@ -3436,7 +3436,7 @@ typedef struct uint32_t edca_be_aifs; v_BOOL_t sendMgmtPktViaWQ5; v_BOOL_t sap_probe_resp_offload; - v_BOOL_t sap_restrt_ch_avoid; + v_BOOL_t sap_internal_restart; } hdd_config_t; /*--------------------------------------------------------------------------- diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h index 3b1eb5d0d963..5529887d076d 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h @@ -116,4 +116,8 @@ void hdd_restart_softap (hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); void hdd_hostapd_ch_avoid_cb(void *pAdapter, void *indParam); #endif /* FEATURE_WLAN_CH_AVOID */ int hdd_del_all_sta(hdd_adapter_t *pAdapter); + +void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter); +void hdd_sap_destroy_events(hdd_adapter_t *adapter); + #endif // end #if !defined( WLAN_HDD_HOSTAPD_H ) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index b8316b80faa4..85447484704e 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1970,4 +1970,7 @@ void wlan_hdd_defer_scan_init_work(hdd_context_t *pHddCtx, unsigned long delay); int hdd_reassoc(hdd_adapter_t *pAdapter, const tANI_U8 *bssid, const tANI_U8 channel, const handoff_src src); + +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter); + #endif // end #if !defined( WLAN_HDD_MAIN_H ) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index 1fe84f0b94f0..c08c4cc913d0 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3742,12 +3742,13 @@ REG_VARIABLE( CFG_EXTSCAN_ENABLE, WLAN_PARAM_Integer, CFG_SAP_PROBE_RESP_OFFLOAD_MIN, CFG_SAP_PROBE_RESP_OFFLOAD_MAX), - REG_VARIABLE(CFG_CH_AVOID_SAP_RESTART_NAME, WLAN_PARAM_Integer, - hdd_config_t, sap_restrt_ch_avoid, + REG_VARIABLE(CFG_SAP_INTERNAL_RESTART_NAME, WLAN_PARAM_Integer, + hdd_config_t, sap_internal_restart, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, - CFG_CH_AVOID_SAP_RESTART_DEFAULT, - CFG_CH_AVOID_SAP_RESTART_MIN, - CFG_CH_AVOID_SAP_RESTART_MAX), + CFG_SAP_INTERNAL_RESTART_DEFAULT, + CFG_SAP_INTERNAL_RESTART_MIN, + CFG_SAP_INTERNAL_RESTART_MAX), + }; /* @@ -4310,8 +4311,8 @@ static void print_hdd_cfg(hdd_context_t *pHddCtx) pHddCtx->cfg_ini->rateUpThreshold); #endif VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, - "Name = [sap_ch_avoid_restart] Value = [%u] ", - pHddCtx->cfg_ini->sap_restrt_ch_avoid); + "Name = [gEnableSapInternalRestart] Value = [%u] ", + pHddCtx->cfg_ini->sap_internal_restart); } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index ea945b563eeb..f7547fe5e9ab 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2317,7 +2317,34 @@ VOS_STATUS hdd_wlan_shutdown(void) return VOS_STATUS_SUCCESS; } - +/** + * hdd_ssr_restart_sap() - restart sap on SSR + * @hdd_ctx: hdd context + * + * Return: nothing + */ +static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx) +{ + VOS_STATUS status; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter (hdd_ctx, &adapter_node); + while (NULL != adapter_node && VOS_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter && adapter->device_mode == WLAN_HDD_SOFTAP) { + hddLog(VOS_TRACE_LEVEL_INFO, FL("in sap mode %p"), + adapter); + wlan_hdd_start_sap(adapter); + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + EXIT(); +} /* the HDD interface to WLAN driver re-init. * This is called to initialize/start WLAN driver after a shutdown. @@ -2366,7 +2393,8 @@ VOS_STATUS hdd_wlan_re_init(void) vos_set_reinit_in_progress(VOS_MODULE_ID_VOSS, TRUE); /* The driver should always be initialized in STA mode after SSR */ - hdd_set_conparam(0); + if (VOS_STA_SAP_MODE != hdd_get_conparam()) + hdd_set_conparam(0); dev = wcnss_wlan_get_device(); if (NULL == dev) @@ -2617,5 +2645,9 @@ VOS_STATUS hdd_wlan_re_init(void) success: /* Trigger replay of BTC events */ send_btc_nlink_msg(WLAN_MODULE_DOWN_IND, 0); + + if (pHddCtx->cfg_ini->sap_internal_restart) + hdd_ssr_restart_sap(pHddCtx); + return VOS_STATUS_SUCCESS; } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index 1d116e76b16c..33f7d5039c74 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -1300,7 +1300,7 @@ stopbss : hddLog(LOG1, FL("ch avoid in progress: %d"), pHddCtx->is_ch_avoid_in_progress); if (pHddCtx->is_ch_avoid_in_progress && - pHddCtx->cfg_ini->sap_restrt_ch_avoid) + pHddCtx->cfg_ini->sap_internal_restart) netif_tx_disable(dev); else hdd_hostapd_stop(dev); @@ -1541,7 +1541,7 @@ static void hdd_unsafe_channel_restart_sap(hdd_adapter_t *adapter, AUTO_CHANNEL_SELECT; - if (hdd_ctx->cfg_ini->sap_restrt_ch_avoid) { + if (hdd_ctx->cfg_ini->sap_internal_restart) { netif_tx_disable(adapter->dev); schedule_work(&hdd_ctx->sap_start_work); } else { @@ -4871,3 +4871,107 @@ VOS_STATUS hdd_unregister_hostapd(hdd_adapter_t *pAdapter, tANI_U8 rtnl_held) EXIT(); return 0; } + +/** + * hdd_sap_indicate_disconnect_for_sta() - Indicate disconnect indication + * to supplicant, if there any clients connected to SAP interface. + * @adapter: sap adapter context + * + * Return: nothing + */ +void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter) +{ + tSap_Event sap_event; + int staId; + hdd_context_t *hdd_ctx; + v_CONTEXT_t vos_ctx; + ptSapContext sap_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + return; + } + + vos_ctx = hdd_ctx->pvosContext; + if (NULL == vos_ctx) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: VOS context is not valid",__func__); + return; + } + + sap_ctx = VOS_GET_SAP_CB(vos_ctx); + if (!sap_ctx) { + hddLog(LOGE, FL("invalid sap context")); + return; + } + + for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) { + if (sap_ctx->aStaInfo[staId].isUsed) { + hddLog(LOG1, FL("staId: %d isUsed: %d %p"), + staId, sap_ctx->aStaInfo[staId].isUsed, + sap_ctx); + + if (vos_is_macaddr_broadcast( + &sap_ctx->aStaInfo[staId].macAddrSTA)) + continue; + + sap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + vos_mem_copy( + &sap_event.sapevt. + sapStationDisassocCompleteEvent.staMac, + &sap_ctx->aStaInfo[staId].macAddrSTA, + sizeof(v_MACADDR_t)); + sap_event.sapevt.sapStationDisassocCompleteEvent. + reason = + eSAP_MAC_INITATED_DISASSOC; + sap_event.sapevt.sapStationDisassocCompleteEvent. + statusCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + hdd_hostapd_SAPEventCB(&sap_event, + sap_ctx->pUsrContext); + } + } + + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + + EXIT(); +} + +/** + * hdd_sap_destroy_events() - Destroy sap evets + * @adapter: sap adapter context + * + * Return: nothing + */ +void hdd_sap_destroy_events(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx; + v_CONTEXT_t vos_ctx; + ptSapContext sap_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + return; + } + + vos_ctx = hdd_ctx->pvosContext; + if (NULL == vos_ctx) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: VOS context is not valid",__func__); + return; + } + + sap_ctx = VOS_GET_SAP_CB(vos_ctx); + if (!sap_ctx) { + hddLog(LOGE, FL("invalid sap context")); + return; + } + + if (!VOS_IS_STATUS_SUCCESS(vos_lock_destroy(&sap_ctx->SapGlobalLock))) + VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + FL("WLANSAP_Stop failed destroy lock")); +} diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index cf353fa678d4..c76d7c83c559 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -9437,7 +9437,18 @@ VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ) pAdapter = pAdapterNode->pAdapter; hddLog(VOS_TRACE_LEVEL_INFO, FL("Disabling queues")); netif_tx_disable(pAdapter->dev); - netif_carrier_off(pAdapter->dev); + + if (pHddCtx->cfg_ini->sap_internal_restart && + pAdapter->device_mode == WLAN_HDD_SOFTAP) { + hddLog(LOG1, FL("driver supports sap restart")); + vos_flush_work(&pHddCtx->sap_start_work); + hdd_sap_indicate_disconnect_for_sta(pAdapter); + hdd_cleanup_actionframe(pHddCtx, pAdapter); + hdd_softap_deinit_tx_rx(pAdapter); + hdd_sap_destroy_events(pAdapter); + } else { + netif_carrier_off(pAdapter->dev); + } pAdapter->sessionCtx.station.hdd_ReassocScenario = VOS_FALSE; @@ -9657,7 +9668,15 @@ VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) break; case WLAN_HDD_SOFTAP: - /* softAP can handle SSR */ + if (pHddCtx->cfg_ini->sap_internal_restart) { + hdd_init_ap_mode(pAdapter); + status = hdd_sta_id_hash_attach(pAdapter); + if (VOS_STATUS_SUCCESS != status) + { + hddLog(VOS_TRACE_LEVEL_FATAL, + FL("failed to attach hash for")); + } + } break; case WLAN_HDD_P2P_GO: @@ -14825,6 +14844,69 @@ void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter) } +/** + * wlan_hdd_start_sap() - This function starts bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the starting of sap adapter. + * + * Return: void. + */ +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + VOS_STATUS vos_status; + hdd_context_t *hdd_ctx; + tsap_Config_t *pConfig; + + if (NULL == ap_adapter) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("ap_adapter is NULL here")); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + pConfig = &ap_adapter->sessionCtx.ap.sapConfig; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + goto end; + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + hddLog(LOGE, FL("SAP Not able to set AP IEs")); + goto end; + } + + vos_event_reset(&hostapd_state->vosEvent); + if (WLANSAP_StartBss(hdd_ctx->pvosContext, hdd_hostapd_SAPEventCB, + &hdd_ap_ctx->sapConfig, (v_PVOID_t)ap_adapter->dev) + != VOS_STATUS_SUCCESS) { + goto end; + } + + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + FL("Waiting for SAP to start")); + vos_status = vos_wait_single_event(&hostapd_state->vosEvent, 10000); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + FL("SAP Start failed")); + goto end; + } + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, + FL("SAP Start Success")); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + + wlan_hdd_incr_active_session(hdd_ctx, ap_adapter->device_mode); + hostapd_state->bCommit = TRUE; + +end: + mutex_unlock(&hdd_ctx->sap_lock); + return; +} + //Register the module init/exit functions module_init(hdd_module_init); module_exit(hdd_module_exit); From 15ed5a3eb094ce083a7cf4184913d6144a162610 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Fri, 27 Jan 2017 16:43:45 +0530 Subject: [PATCH 143/281] prima: Avoid overflow of "set_bssid_hotlist" params qcacld2.0 to prima propgation The wlan driver supports the following vendor command: QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST This command supplies a "number of APs" attribute as well as a list of per-AP attributes. However there is no validation that the number of APs provided won't overflow the destination buffer. In addition there is no validation that the number of APs actually provided matches the number of APs expected. To address these issues: * Verify that the expected number of APs doesn't exceed the maximum allowed number of APs * Verify that the actual number of APs supplied doesn't exceed the expected number of APs * Only process the actual number of supplied APs if it is less than the expected number of APs. Change-Id: I41e36d11bc3e71928866a27afc2fbf046b59f0f5 CRs-Fixed: 1095770 --- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 395fa7b2aac4..7fb4537d8f43 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -3764,10 +3764,20 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, pReqMsg->numBssid = nla_get_u32( tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]); + if (pReqMsg->numBssid > WLAN_EXTSCAN_MAX_HOTLIST_APS) { + hddLog(LOGE, FL("Number of AP: %u exceeds max: %u"), + pReqMsg->numBssid, WLAN_EXTSCAN_MAX_HOTLIST_APS); + goto fail; + } hddLog(VOS_TRACE_LEVEL_INFO, FL("Number of AP (%d)"), pReqMsg->numBssid); nla_for_each_nested(apTh, tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], rem) { + if (i == pReqMsg->numBssid) { + hddLog(LOGW, FL("Ignoring excess AP")); + break; + } + if(nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, nla_data(apTh), nla_len(apTh), NULL)) { @@ -3806,6 +3816,12 @@ static int __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, i++; } + if (i < pReqMsg->numBssid) { + hddLog(LOGW, FL("Number of AP %u less than expected %u"), + i, pReqMsg->numBssid); + pReqMsg->numBssid = i; + } + context = &pHddCtx->ext_scan_context; spin_lock(&hdd_context_lock); INIT_COMPLETION(context->response_event); From 94bccb1433b83c27419027acffa72d272d685971 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Mon, 6 Feb 2017 15:04:47 +0530 Subject: [PATCH 144/281] wlan: Correct value for bad RSSI in PER based roaming Bad rssi value for PER based roam is not assigned to sme roam config correctly from hdd config which is causing all candidates to be discarding after the event. Add changes to assign value from hdd config to sme config. Change-Id: Iee6aaa2ea890adbce3e6479adc7fffe6e88da44c CRs-Fixed: 2002633 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c | 3 ++- drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index c08c4cc913d0..27e4d6ca47da 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c @@ -6131,7 +6131,8 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->csrConfig.PERRoamFullScanThreshold = pConfig->PERRoamFullScanThreshold * -1; smeConfig->csrConfig.PERroamTriggerPercent = pConfig->PERroamTriggerPercent; - + smeConfig->csrConfig.PERMinRssiThresholdForRoam = + pConfig->PERMinRssiThresholdForRoam; if (0 == smeConfig->csrConfig.isRoamOffloadScanEnabled) { diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 2d2e5f8272b7..e0bec48c8ede 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -2210,8 +2210,9 @@ static tANI_S32 csrFindCongestionScore (tpAniSirGlobal pMac, tCsrScanResult *pBs if (bssInfo->rssi < pMac->roam.configParam.PERMinRssiThresholdForRoam) { smsLog(pMac, LOG1, - FL("discrarding candidate due to low rssi=%d bssid " + FL("discarding candidate due to low rssi=%d than %d, bssid " MAC_ADDRESS_STR), bssInfo->rssi, + pMac->roam.configParam.PERMinRssiThresholdForRoam, MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId)); return 0; } From 04dfce772cb48f6c87c734f2f04b5baa6e4386ac Mon Sep 17 00:00:00 2001 From: Arunk Khandavalli Date: Mon, 16 Jan 2017 11:44:46 +0530 Subject: [PATCH 145/281] wlan: Get debug information when the HAL_START_RSP fails When there is a timout during in the vos_start waiting for HAL_START_RSP from the firmware there is not much debug information if the SMD event is recieved or if the mcthread is stuck, dump following information : 1) SMD stats, open/read/write/close smd stats. 2) Dump the infomation regarding the messages processed by the MCthread. 3) Also probe the mcthread if it is stuck and dump the mcthread struck info CRs-Fixed: 1110501 Change-Id: I48041576a5af26b466a9a50b8185d5f3655ff56d --- .../prima/CORE/SYS/common/src/wlan_qct_sys.c | 4 +- drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 15 ++++- drivers/staging/prima/CORE/VOSS/src/vos_api.c | 56 ++++++++++++++++++- .../staging/prima/CORE/VOSS/src/vos_sched.c | 22 +++++++- .../staging/prima/CORE/VOSS/src/vos_sched.h | 4 +- .../prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 3 +- .../CORE/WDI/TRP/CTS/inc/wlan_qct_wdi_cts.h | 14 ++++- .../CORE/WDI/TRP/CTS/src/wlan_qct_wdi_cts.c | 26 ++++++++- 8 files changed, 134 insertions(+), 10 deletions(-) diff --git a/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c b/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c index be54dffb7fbc..11f9fe5636e2 100644 --- a/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c +++ b/drivers/staging/prima/CORE/SYS/common/src/wlan_qct_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -778,7 +778,7 @@ void wlan_sys_probe(void) vosMessage.reserved = FTM_SYS_MSG_COOKIE; vosMessage.type = SYS_MSG_ID_MC_THR_PROBE; - vosMessage.callback = NULL; + vosMessage.callback = vos_dump_thread_stacks; vosMessage.bodyptr = NULL; vos_mq_post_message(VOS_MQ_ID_SYS, &vosMessage); diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index 99039cd3cc4a..b1b846cd3f92 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -208,6 +208,17 @@ enum log_event_host_reason_code { WLAN_LOG_REASON_SCAN_NOT_ALLOWED, }; +/** + * vos_wdi_trace_event_type: Trace type for WDI Write/Read + * VOS_WDI_READ: Log the WDI read event + * VOS_WDI_WRITE: Log the WDI write event + */ +typedef enum +{ + VOS_WDI_READ, + VOS_WDI_WRITE, +} vos_wdi_trace_event_type; + /*------------------------------------------------------------------------- Function declarations and documenation ------------------------------------------------------------------------*/ @@ -512,5 +523,7 @@ void vos_updatePktStatsInfo(void * pktStat); bool vos_is_wlan_logging_enabled(void); v_BOOL_t vos_is_probe_rsp_offload_enabled(void); - +void vos_smd_dump_stats(void); +void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event); +void vos_dump_wdi_events(void); #endif // if !defined __VOS_NVITEM_H diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index 7d347fbdaa4a..f218b8e5d3a9 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -83,7 +83,7 @@ #include "bapInternal.h" #include "bap_hdd_main.h" #endif //WLAN_BTAMP_FEATURE - +#include "wlan_qct_wdi_cts.h" /*--------------------------------------------------------------------------- * Preprocessor Definitions and Constants @@ -100,6 +100,9 @@ /* Approximate amount of time to wait for WDA to issue a DUMP req */ #define VOS_WDA_RESP_TIMEOUT WDA_STOP_TIMEOUT +/* Trace index for WDI Read/Write */ +#define VOS_TRACE_INDEX_MAX 256 + /*--------------------------------------------------------------------------- * Data definitions * ------------------------------------------------------------------------*/ @@ -107,6 +110,16 @@ static VosContextType gVosContext; static pVosContextType gpVosContext; static v_U8_t vos_multicast_logging; +struct vos_wdi_trace +{ + vos_wdi_trace_event_type event; + uint16 message; + uint64 time; +}; + +static struct vos_wdi_trace gvos_wdi_msg_trace[VOS_TRACE_INDEX_MAX]; +uint16 gvos_wdi_msg_trace_index = 0; + /*--------------------------------------------------------------------------- * Forward declaration * ------------------------------------------------------------------------*/ @@ -898,6 +911,12 @@ VOS_STATUS vos_start( v_CONTEXT_t vosContext ) if ( vStatus == VOS_STATUS_E_TIMEOUT ) { WDA_setNeedShutdown(vosContext); + vos_smd_dump_stats(); + vos_dump_wdi_events(); + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s: Test MC thread by posting a probe message to SYS", + __func__); + wlan_sys_probe(); } VOS_ASSERT(0); return VOS_STATUS_E_FAILURE; @@ -3610,3 +3629,38 @@ v_BOOL_t vos_is_probe_rsp_offload_enabled(void) return pHddCtx->cfg_ini->sap_probe_resp_offload; } + +void vos_smd_dump_stats(void) +{ + WCTS_Dump_Smd_status(); +} + +void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event) +{ + + if (gvos_wdi_msg_trace_index >= VOS_TRACE_INDEX_MAX) + { + gvos_wdi_msg_trace_index = 0; + } + + gvos_wdi_msg_trace[gvos_wdi_msg_trace_index].event = event; + gvos_wdi_msg_trace[gvos_wdi_msg_trace_index].time = + vos_get_monotonic_boottime(); + gvos_wdi_msg_trace[gvos_wdi_msg_trace_index].message = msg; + gvos_wdi_msg_trace_index++; + + return; +} + +void vos_dump_wdi_events(void) +{ + int i; + + for(i = 0; i < VOS_TRACE_INDEX_MAX; i++) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s:event:%d time:%lld msg:%d ",__func__, + gvos_wdi_msg_trace[i].event, + gvos_wdi_msg_trace[i].time, + gvos_wdi_msg_trace[i].message); + } +} diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c index 0dafd2531e1a..f9014e7f8bbf 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2206,3 +2206,23 @@ void vos_dump_stack(uint8_t thread_id) "%s: Invalid thread %d invoked",__func__, thread_id); } } + +void vos_dump_thread_stacks(int threadId) +{ + /* Make sure that Vos Watchdog context has been initialized */ + if (gpVosWatchdogContext == NULL) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + "%s: gpVosWatchdogContext == NULL", __func__); + return; + } + hddLog(LOGE, FL("Thread Stuck count reached threshold!!!" + "MC Count %d RX count %d TX count %d"), + gpVosWatchdogContext->mcThreadStuckCount, + gpVosWatchdogContext->rxThreadStuckCount, + gpVosWatchdogContext->txThreadStuckCount); + + vos_dump_stack(MC_Thread); + vos_dump_stack(TX_Thread); + vos_dump_stack(RX_Thread); +} diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h index 5082757578f6..cd9c1e2df21d 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_sched.h +++ b/drivers/staging/prima/CORE/VOSS/src/vos_sched.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -537,6 +537,6 @@ void vos_ssr_unprotect(const char *caller_func); void vos_wd_reset_thread_stuck_count(int threadId); bool vos_is_wd_thread(int threadId); void vos_dump_stack(uint8_t value); - +void vos_dump_thread_stacks(int threadId); #endif // #if !defined __VOSS_SCHED_H diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 2b6d407242d9..62acabfa049c 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -22651,6 +22651,7 @@ WDI_RXMsgCTSCB } wdiEventData.wdiResponse = HAL_2_WDI_RSP_TYPE( pHalMsgHeader->msgType ); + vos_log_wdi_event(wdiEventData.wdiResponse, VOS_WDI_READ); /*The message itself starts after the header*/ wdiEventData.pEventData = (wpt_uint8*)pMsg + sizeof(tHalMsgHeader); diff --git a/drivers/staging/prima/CORE/WDI/TRP/CTS/inc/wlan_qct_wdi_cts.h b/drivers/staging/prima/CORE/WDI/TRP/CTS/inc/wlan_qct_wdi_cts.h index 16bfad0d3b94..daf87b06ded1 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/CTS/inc/wlan_qct_wdi_cts.h +++ b/drivers/staging/prima/CORE/WDI/TRP/CTS/inc/wlan_qct_wdi_cts.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013,2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -97,6 +97,16 @@ typedef enum WCTS_EVENT_MAX } WCTS_NotifyEventType; +struct WdiSmdStats +{ + int smd_event_data; + int smd_event_open; + int smd_event_close; + int smd_event_status; + int smd_event_reopen_ready; + int smd_event_err; +}; + /*---------------------------------------------------------------------------- * WDI callback types *--------------------------------------------------------------------------*/ @@ -253,4 +263,6 @@ WCTS_ClearPendingQueue ( WCTS_HandleType wctsHandle ); + +void WCTS_Dump_Smd_status(void); #endif /* #ifndef WLAN_QCT_WDI_CTS_H */ diff --git a/drivers/staging/prima/CORE/WDI/TRP/CTS/src/wlan_qct_wdi_cts.c b/drivers/staging/prima/CORE/WDI/TRP/CTS/src/wlan_qct_wdi_cts.c index 9c04d8827b43..ddf4d4d71a5a 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/CTS/src/wlan_qct_wdi_cts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/CTS/src/wlan_qct_wdi_cts.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -108,6 +108,8 @@ static WCTS_HandleType gwctsHandle; /* time to wait for SMD channel to close (in msecs) */ #define WCTS_SMD_CLOSE_TIMEOUT 5000 +/* Global Variable for WDI SMD stats */ +static struct WdiSmdStats gWdiSmdStats; /*---------------------------------------------------------------------------- * Type Declarations * -------------------------------------------------------------------------*/ @@ -528,6 +530,7 @@ WCTS_NotifyCallback wpalDriverReInit(); return; } + gWdiSmdStats.smd_event_open++; palMsg = &pWCTSCb->wctsOpenMsg; break; @@ -543,6 +546,7 @@ WCTS_NotifyCallback WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: received SMD_EVENT_DATA from SMD", __func__); palMsg = &pWCTSCb->wctsDataMsg; + gWdiSmdStats.smd_event_data++; break; case SMD_EVENT_CLOSE: @@ -560,11 +564,13 @@ WCTS_NotifyCallback /* subsystem restart: shutdown */ wpalDriverShutdown(); + gWdiSmdStats.smd_event_close++; return; case SMD_EVENT_STATUS: WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "%s: received SMD_EVENT_STATUS from SMD", __func__); + gWdiSmdStats.smd_event_status++; return; case SMD_EVENT_REOPEN_READY: @@ -575,12 +581,14 @@ WCTS_NotifyCallback running, this one is received when the threads are closed and the rmmod thread is waiting. so just unblock that thread */ wpalEventSet(&pWCTSCb->wctsEvent); + gWdiSmdStats.smd_event_reopen_ready++; return; default: WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "%s: Unexpected event %u received from SMD", __func__, event); + gWdiSmdStats.smd_event_err++; return; } @@ -977,3 +985,19 @@ WCTS_SendMessage return eWLAN_PAL_STATUS_SUCCESS; }/*WCTS_SendMessage*/ + +void WCTS_Dump_Smd_status(void) +{ + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Read Stats: %d", gWdiSmdStats.smd_event_data); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Open Stats: %d", gWdiSmdStats.smd_event_open); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Close Stats: %d", gWdiSmdStats.smd_event_close); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Status Stats: %d", gWdiSmdStats.smd_event_status); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Reopen Stats: %d", gWdiSmdStats.smd_event_reopen_ready); + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "Smd Error Stats: %d", gWdiSmdStats.smd_event_err); +} From 79d4d1b6e8c8f1cad9ca4f53adfc52ae89920e8b Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 20 Jan 2017 15:19:13 -0800 Subject: [PATCH 146/281] ANDROID: sdcardfs: Allow non-owners to touch This modifies the permission checks in setattr to allow for non-owners to modify the timestamp of files to things other than the current time. This still requires write access, as enforced by the permission call, but relaxes the requirement that the caller must be the owner, allowing those with group permissions to change it as well. Bug: 11118565 Change-Id: Ied31f0cce2797675c7ef179eeb4e088185adcbad Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 892fe8cfb4c8..53b2a7024d7e 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -751,6 +751,11 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ + /* prepare our own lower struct iattr (with the lower file) */ + memcpy(&lower_ia, ia, sizeof(lower_ia)); + /* Allow touch updating timestamps. A previous permission check ensures + * we have write access. Changes to mode, owner, and group are ignored*/ + ia->ia_valid |= ATTR_FORCE; err = inode_change_ok(&tmp, ia); if (!err) { @@ -776,8 +781,6 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct lower_mnt = lower_path.mnt; lower_inode = sdcardfs_lower_inode(inode); - /* prepare our own lower struct iattr (with the lower file) */ - memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); From 436ed2272d420220c7b4f52e67b9aa7d5dab5b75 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Sat, 21 Jan 2017 00:35:26 -0800 Subject: [PATCH 147/281] ANDROID: sdcardfs: Refactor configfs interface This refactors the configfs code to be more easily extended. It will allow additional files to be added easily. Bug: 34542611 Bug: 34262585 Change-Id: I73c9b0ae5ca7eb27f4ebef3e6807f088b512d539 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/packagelist.c | 156 +++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 80 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index dac5d0f7d2de..7321aa609dcf 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -220,39 +220,29 @@ static void packagelist_destroy(void) printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); } -struct package_appid { +struct package_details { struct config_item item; - int add_pid; + const char* name; }; -static inline struct package_appid *to_package_appid(struct config_item *item) +static inline struct package_details *to_package_details(struct config_item *item) { - return item ? container_of(item, struct package_appid, item) : NULL; + return item ? container_of(item, struct package_details, item) : NULL; } -static struct configfs_attribute package_appid_attr_add_pid = { - .ca_owner = THIS_MODULE, - .ca_name = "appid", - .ca_mode = S_IRUGO | S_IWUGO, -}; - -static struct configfs_attribute *package_appid_attrs[] = { - &package_appid_attr_add_pid, - NULL, -}; +CONFIGFS_ATTR_STRUCT(package_details); +#define PACKAGE_DETAILS_ATTR(_name, _mode, _show, _store) \ +struct package_details_attribute package_details_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) -static ssize_t package_appid_attr_show(struct config_item *item, - struct configfs_attribute *attr, +static ssize_t package_details_appid_show(struct package_details *package_details, char *page) { - return scnprintf(page, PAGE_SIZE, "%u\n", get_appid(item->ci_name)); + return scnprintf(page, PAGE_SIZE, "%u\n", get_appid(package_details->name)); } -static ssize_t package_appid_attr_store(struct config_item *item, - struct configfs_attribute *attr, +static ssize_t package_details_appid_store(struct package_details *package_details, const char *page, size_t count) { - struct package_appid *package_appid = to_package_appid(item); unsigned int tmp; int ret; @@ -260,73 +250,76 @@ static ssize_t package_appid_attr_store(struct config_item *item, if (ret) return ret; - ret = insert_packagelist_entry(item->ci_name, tmp); - package_appid->add_pid = tmp; + ret = insert_packagelist_entry(package_details->name, tmp); + if (ret) return ret; return count; } -static void package_appid_release(struct config_item *item) +static void package_details_release(struct config_item *item) { - printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name); - /* item->ci_name is freed already, so we rely on the dentry */ - remove_packagelist_entry(item->ci_dentry->d_name.name); - kfree(to_package_appid(item)); + struct package_details *package_details = to_package_details(item); + printk(KERN_INFO "sdcardfs: removing %s\n", package_details->name); + remove_packagelist_entry(package_details->name); + kfree(package_details->name); + kfree(package_details); } -static struct configfs_item_operations package_appid_item_ops = { - .release = package_appid_release, - .show_attribute = package_appid_attr_show, - .store_attribute = package_appid_attr_store, +PACKAGE_DETAILS_ATTR(appid, S_IRUGO | S_IWUGO, package_details_appid_show, package_details_appid_store); + +static struct configfs_attribute *package_details_attrs[] = { + &package_details_attr_appid.attr, + NULL, +}; + +CONFIGFS_ATTR_OPS(package_details); +static struct configfs_item_operations package_details_item_ops = { + .release = package_details_release, + .show_attribute = package_details_attr_show, + .store_attribute = package_details_attr_store, }; static struct config_item_type package_appid_type = { - .ct_item_ops = &package_appid_item_ops, - .ct_attrs = package_appid_attrs, + .ct_item_ops = &package_details_item_ops, + .ct_attrs = package_details_attrs, .ct_owner = THIS_MODULE, }; - -struct sdcardfs_packages { - struct config_group group; +struct packages { + struct configfs_subsystem subsystem; }; -static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item) +static inline struct packages *to_packages(struct config_item *item) { - return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL; + return item ? container_of(to_configfs_subsystem(to_config_group(item)), struct packages, subsystem) : NULL; } -static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name) +CONFIGFS_ATTR_STRUCT(packages); +#define PACKAGES_ATTR(_name, _mode, _show, _store) \ +struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) +#define PACKAGES_ATTR_RO(_name, _show) \ +struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR_RO(_name, _show); + +static struct config_item *packages_make_item(struct config_group *group, const char *name) { - struct package_appid *package_appid; + struct package_details *package_details; - package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL); - if (!package_appid) + package_details = kzalloc(sizeof(struct package_details), GFP_KERNEL); + if (!package_details) + return ERR_PTR(-ENOMEM); + package_details->name = kstrdup(name, GFP_KERNEL); + if (!package_details->name) return ERR_PTR(-ENOMEM); - config_item_init_type_name(&package_appid->item, name, + config_item_init_type_name(&package_details->item, name, &package_appid_type); - package_appid->add_pid = 0; - - return &package_appid->item; + return &package_details->item; } -static struct configfs_attribute sdcardfs_packages_attr_description = { - .ca_owner = THIS_MODULE, - .ca_name = "packages_gid.list", - .ca_mode = S_IRUGO, -}; - -static struct configfs_attribute *sdcardfs_packages_attrs[] = { - &sdcardfs_packages_attr_description, - NULL, -}; - -static ssize_t packages_attr_show(struct config_item *item, - struct configfs_attribute *attr, +static ssize_t packages_list_show(struct packages *packages, char *page) { struct hashtable_entry *hash_cur; @@ -349,38 +342,41 @@ static ssize_t packages_attr_show(struct config_item *item, return count; } -static void sdcardfs_packages_release(struct config_item *item) -{ +struct packages_attribute packages_attr_packages_gid_list = __CONFIGFS_ATTR_RO(packages_gid.list, packages_list_show); - printk(KERN_INFO "sdcardfs: destroyed something?\n"); - kfree(to_sdcardfs_packages(item)); -} +static struct configfs_attribute *packages_attrs[] = { + &packages_attr_packages_gid_list.attr, + NULL, +}; -static struct configfs_item_operations sdcardfs_packages_item_ops = { - .release = sdcardfs_packages_release, - .show_attribute = packages_attr_show, +CONFIGFS_ATTR_OPS(packages) +static struct configfs_item_operations packages_item_ops = { + .show_attribute = packages_attr_show, + .store_attribute = packages_attr_store, }; /* * Note that, since no extra work is required on ->drop_item(), * no ->drop_item() is provided. */ -static struct configfs_group_operations sdcardfs_packages_group_ops = { - .make_item = sdcardfs_packages_make_item, +static struct configfs_group_operations packages_group_ops = { + .make_item = packages_make_item, }; -static struct config_item_type sdcardfs_packages_type = { - .ct_item_ops = &sdcardfs_packages_item_ops, - .ct_group_ops = &sdcardfs_packages_group_ops, - .ct_attrs = sdcardfs_packages_attrs, +static struct config_item_type packages_type = { + .ct_item_ops = &packages_item_ops, + .ct_group_ops = &packages_group_ops, + .ct_attrs = packages_attrs, .ct_owner = THIS_MODULE, }; -static struct configfs_subsystem sdcardfs_packages_subsys = { - .su_group = { - .cg_item = { - .ci_namebuf = "sdcardfs", - .ci_type = &sdcardfs_packages_type, +static struct packages sdcardfs_packages = { + .subsystem = { + .su_group = { + .cg_item = { + .ci_namebuf = "sdcardfs", + .ci_type = &packages_type, + }, }, }, }; @@ -388,7 +384,7 @@ static struct configfs_subsystem sdcardfs_packages_subsys = { static int configfs_sdcardfs_init(void) { int ret; - struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; + struct configfs_subsystem *subsys = &sdcardfs_packages.subsystem; config_group_init(&subsys->su_group); mutex_init(&subsys->su_mutex); @@ -403,7 +399,7 @@ static int configfs_sdcardfs_init(void) static void configfs_sdcardfs_exit(void) { - configfs_unregister_subsystem(&sdcardfs_packages_subsys); + configfs_unregister_subsystem(&sdcardfs_packages.subsystem); } int packagelist_init(void) From d4b7250de7734c63806e41b96f91cae0bd611a6f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Sun, 22 Jan 2017 15:32:49 -0800 Subject: [PATCH 148/281] ANDROID: sdcardfs: add support for user permission isolation This allows you to hide the existence of a package from a user by adding them to an exclude list. If a user creates that package's folder and is on the exclude list, they will not see that package's id. Bug: 34542611 Change-Id: I9eb82e0bf2457d7eb81ee56153b9c7d2f6646323 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 32 +++-- fs/sdcardfs/packagelist.c | 275 +++++++++++++++++++++++++++++++++---- fs/sdcardfs/sdcardfs.h | 17 ++- 3 files changed, 284 insertions(+), 40 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index d6aa3a34c250..12532205f825 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -103,7 +103,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st case PERM_ANDROID_OBB: case PERM_ANDROID_MEDIA: appid = get_appid(newdentry->d_name.name); - if (appid != 0) { + if (appid != 0 && !is_excluded(newdentry->d_name.name, parent_info->userid)) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } set_top(info, &info->vfs_inode); @@ -116,8 +116,10 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) get_derived_permission_new(parent, dentry, dentry); } -static int descendant_may_need_fixup(perm_t perm) { - if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID) +static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) { + if (info->perm == PERM_ROOT) + return (limit->flags & BY_USERID)?info->userid == limit->userid:1; + if (info->perm == PERM_PRE_ROOT || info->perm == PERM_ANDROID) return 1; return 0; } @@ -129,7 +131,7 @@ static int needs_fixup(perm_t perm) { return 0; } -void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) { +void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { struct dentry *child; struct sdcardfs_inode_info *info; if (!dget(dentry)) @@ -143,22 +145,22 @@ void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) if (needs_fixup(info->perm)) { spin_lock(&dentry->d_lock); list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - dget(child); - if (!strncasecmp(child->d_name.name, name, len)) { - if (child->d_inode) { - get_derived_permission(dentry, child); - fixup_tmp_permissions(child->d_inode); - dput(child); - break; - } + dget(child); + if (!(limit->flags & BY_NAME) || !strncasecmp(child->d_name.name, limit->name, limit->length)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fixup_tmp_permissions(child->d_inode); + dput(child); + break; } - dput(child); + } + dput(child); } spin_unlock(&dentry->d_lock); - } else if (descendant_may_need_fixup(info->perm)) { + } else if (descendant_may_need_fixup(info, limit)) { spin_lock(&dentry->d_lock); list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - fixup_perms_recursive(child, name, len); + fixup_perms_recursive(child, limit); } spin_unlock(&dentry->d_lock); } diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 7321aa609dcf..05b5f34ff9e6 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -31,11 +31,13 @@ struct hashtable_entry { struct hlist_node hlist; + struct hlist_node dlist; /* for deletion cleanup */ const char *key; atomic_t value; }; static DEFINE_HASHTABLE(package_to_appid, 8); +static DEFINE_HASHTABLE(package_to_userid, 8); static struct kmem_cache *hashtable_entry_cachep; @@ -69,6 +71,22 @@ appid_t get_appid(const char *app_name) return 0; } +appid_t is_excluded(const char *app_name, userid_t user) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(app_name); + + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (atomic_read(&hash_cur->value) == user && !strcasecmp(app_name, hash_cur->key)) { + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + return 0; +} + /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access * even further, such as enforcing that apps hold sdcard_rw. */ @@ -124,7 +142,7 @@ static struct hashtable_entry *alloc_packagelist_entry(const char *key, return ret; } -static int insert_packagelist_entry_locked(const char *key, appid_t value) +static int insert_packagelist_appid_entry_locked(const char *key, appid_t value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; @@ -143,18 +161,64 @@ static int insert_packagelist_entry_locked(const char *key, appid_t value) return 0; } -static void fixup_perms(struct super_block *sb, const char *key) { - if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - fixup_perms_recursive(sb->s_root, key, strlen(key)); +static int insert_userid_exclude_entry_locked(const char *key, userid_t value) +{ + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + unsigned int hash = str_hash(key); + + /* Only insert if not already present */ + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (atomic_read(&hash_cur->value) == value && !strcasecmp(key, hash_cur->key)) + return 0; + } + new_entry = alloc_packagelist_entry(key, value); + if (!new_entry) + return -ENOMEM; + hash_add_rcu(package_to_userid, &new_entry->hlist, hash); + return 0; +} + +static void fixup_all_perms_name(const char *key) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_NAME, + .name = key, + .length = strlen(key), + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); } } -static void fixup_all_perms(const char *key) +static void fixup_all_perms_name_userid(const char *key, userid_t userid) { struct sdcardfs_sb_info *sbinfo; - list_for_each_entry(sbinfo, &sdcardfs_super_list, list) - if (sbinfo) - fixup_perms(sbinfo->sb, key); + struct limit_search limit = { + .flags = BY_NAME | BY_USERID, + .name = key, + .length = strlen(key), + .userid = userid, + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); + } +} + +static void fixup_all_perms_userid(userid_t userid) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_USERID, + .userid = userid, + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); + } } static int insert_packagelist_entry(const char *key, appid_t value) @@ -162,9 +226,22 @@ static int insert_packagelist_entry(const char *key, appid_t value) int err; mutex_lock(&sdcardfs_super_list_lock); - err = insert_packagelist_entry_locked(key, value); + err = insert_packagelist_appid_entry_locked(key, value); if (!err) - fixup_all_perms(key); + fixup_all_perms_name(key); + mutex_unlock(&sdcardfs_super_list_lock); + + return err; +} + +static int insert_userid_exclude_entry(const char *key, userid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_userid_exclude_entry_locked(key, value); + if (!err) + fixup_all_perms_name_userid(key, value); mutex_unlock(&sdcardfs_super_list_lock); return err; @@ -173,7 +250,7 @@ static int insert_packagelist_entry(const char *key, appid_t value) static void free_packagelist_entry(struct hashtable_entry *entry) { kfree(entry->key); - hash_del_rcu(&entry->hlist); + hash_del_rcu(&entry->dlist); kmem_cache_free(hashtable_entry_cachep, entry); } @@ -181,22 +258,84 @@ static void remove_packagelist_entry_locked(const char *key) { struct hashtable_entry *hash_cur; unsigned int hash = str_hash(key); + struct hlist_node *h_t; + HLIST_HEAD(free_list); + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key)) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + } hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { if (!strcasecmp(key, hash_cur->key)) { hash_del_rcu(&hash_cur->hlist); - synchronize_rcu(); - free_packagelist_entry(hash_cur); - return; + hlist_add_head(&hash_cur->dlist, &free_list); + break; } } + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) + free_packagelist_entry(hash_cur); } static void remove_packagelist_entry(const char *key) { mutex_lock(&sdcardfs_super_list_lock); remove_packagelist_entry_locked(key); - fixup_all_perms(key); + fixup_all_perms_name(key); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void remove_userid_all_entry_locked(userid_t userid) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_t; + HLIST_HEAD(free_list); + int i; + + hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { + if (atomic_read(&hash_cur->value) == userid) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + } + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) { + free_packagelist_entry(hash_cur); + } +} + +static void remove_userid_all_entry(userid_t userid) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_userid_all_entry_locked(userid); + fixup_all_perms_userid(userid); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void remove_userid_exclude_entry_locked(const char *key, userid_t userid) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(key); + + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == userid) { + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_packagelist_entry(hash_cur); + break; + } + } +} + +static void remove_userid_exclude_entry(const char *key, userid_t userid) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_userid_exclude_entry_locked(key, userid); + fixup_all_perms_name_userid(key, userid); mutex_unlock(&sdcardfs_super_list_lock); return; } @@ -210,11 +349,14 @@ static void packagelist_destroy(void) mutex_lock(&sdcardfs_super_list_lock); hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { hash_del_rcu(&hash_cur->hlist); - hlist_add_head(&hash_cur->hlist, &free_list); - + hlist_add_head(&hash_cur->dlist, &free_list); + } + hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); } synchronize_rcu(); - hlist_for_each_entry_safe(hash_cur, h_t, &free_list, hlist) + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) free_packagelist_entry(hash_cur); mutex_unlock(&sdcardfs_super_list_lock); printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); @@ -258,6 +400,57 @@ static ssize_t package_details_appid_store(struct package_details *package_detai return count; } +static ssize_t package_details_excluded_userids_show(struct package_details *package_details, + char *page) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(package_details->name); + int count = 0; + + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (!strcasecmp(package_details->name, hash_cur->key)) + count += scnprintf(page + count, PAGE_SIZE - count, + "%d ", atomic_read(&hash_cur->value)); + } + rcu_read_unlock(); + if (count) + count--; + count += scnprintf(page + count, PAGE_SIZE - count, "\n"); + return count; +} + +static ssize_t package_details_excluded_userids_store(struct package_details *package_details, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + + ret = insert_userid_exclude_entry(package_details->name, tmp); + + if (ret) + return ret; + + return count; +} + +static ssize_t package_details_clear_userid_store(struct package_details *package_details, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + remove_userid_exclude_entry(package_details->name, tmp); + return count; +} + static void package_details_release(struct config_item *item) { struct package_details *package_details = to_package_details(item); @@ -268,13 +461,19 @@ static void package_details_release(struct config_item *item) } PACKAGE_DETAILS_ATTR(appid, S_IRUGO | S_IWUGO, package_details_appid_show, package_details_appid_store); +PACKAGE_DETAILS_ATTR(excluded_userids, S_IRUGO | S_IWUGO, + package_details_excluded_userids_show, package_details_excluded_userids_store); +PACKAGE_DETAILS_ATTR(clear_userid, S_IWUGO, NULL, package_details_clear_userid_store); static struct configfs_attribute *package_details_attrs[] = { &package_details_attr_appid.attr, + &package_details_attr_excluded_userids.attr, + &package_details_attr_clear_userid.attr, NULL, }; CONFIGFS_ATTR_OPS(package_details); + static struct configfs_item_operations package_details_item_ops = { .release = package_details_release, .show_attribute = package_details_attr_show, @@ -310,11 +509,13 @@ static struct config_item *packages_make_item(struct config_group *group, const if (!package_details) return ERR_PTR(-ENOMEM); package_details->name = kstrdup(name, GFP_KERNEL); - if (!package_details->name) + if (!package_details->name) { + kfree(package_details); return ERR_PTR(-ENOMEM); + } config_item_init_type_name(&package_details->item, name, - &package_appid_type); + &package_appid_type); return &package_details->item; } @@ -322,16 +523,26 @@ static struct config_item *packages_make_item(struct config_group *group, const static ssize_t packages_list_show(struct packages *packages, char *page) { - struct hashtable_entry *hash_cur; + struct hashtable_entry *hash_cur_app; + struct hashtable_entry *hash_cur_user; int i; int count = 0, written = 0; const char errormsg[] = "\n"; + unsigned int hash; rcu_read_lock(); - hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { + hash_for_each_rcu(package_to_appid, i, hash_cur_app, hlist) { written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", - (const char *)hash_cur->key, atomic_read(&hash_cur->value)); - if (count + written == PAGE_SIZE - sizeof(errormsg)) { + hash_cur_app->key, atomic_read(&hash_cur_app->value)); + hash = str_hash(hash_cur_app->key); + hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) { + if (!strcasecmp(hash_cur_app->key, hash_cur_user->key)) { + written += scnprintf(page + count + written - 1, + PAGE_SIZE - sizeof(errormsg) - count - written + 1, + " %d\n", atomic_read(&hash_cur_user->value)) - 1; + } + } + if (count + written == PAGE_SIZE - sizeof(errormsg) - 1) { count += scnprintf(page + count, PAGE_SIZE - count, errormsg); break; } @@ -342,10 +553,26 @@ static ssize_t packages_list_show(struct packages *packages, return count; } +static ssize_t packages_remove_userid_store(struct packages *packages, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + remove_userid_all_entry(tmp); + return count; +} + struct packages_attribute packages_attr_packages_gid_list = __CONFIGFS_ATTR_RO(packages_gid.list, packages_list_show); +PACKAGES_ATTR(remove_userid, S_IWUGO, NULL, packages_remove_userid_store); + static struct configfs_attribute *packages_attrs[] = { &packages_attr_packages_gid_list.attr, + &packages_attr_remove_userid.attr, NULL, }; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index b47bc0b93315..e91d281cec3f 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -335,6 +335,11 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ SDCARDFS_DENT_FUNC(lower_path) SDCARDFS_DENT_FUNC(orig_path) +static inline bool sbinfo_has_sdcard_magic(struct sdcardfs_sb_info *sbinfo) +{ + return sbinfo && sbinfo->sb && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC; +} + /* grab a refererence if we aren't linking to ourself */ static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top) { @@ -442,18 +447,28 @@ extern struct list_head sdcardfs_super_list; /* for packagelist.c */ extern appid_t get_appid(const char *app_name); +extern appid_t is_excluded(const char *app_name, userid_t userid); extern int check_caller_access_to_name(struct inode *parent_node, const char* name); extern int open_flags_to_access_mode(int open_flags); extern int packagelist_init(void); extern void packagelist_exit(void); /* for derived_perm.c */ +#define BY_NAME (1 << 0) +#define BY_USERID (1 << 1) +struct limit_search { + unsigned int flags; + const char *name; + size_t length; + userid_t userid; +}; + extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); extern void fixup_top_recursive(struct dentry *parent); -extern void fixup_perms_recursive(struct dentry *dentry, const char *name, size_t len); +extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); extern void update_derived_permission_lock(struct dentry *dentry); extern int need_graft_path(struct dentry *dentry); From f69e1d32bb10ff43380646c1906cf984a3fd99e3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 26 Jan 2017 20:10:34 -0800 Subject: [PATCH 149/281] ANDROID: sdcardfs: Remove redundant operation We call get_derived_permission_new unconditionally, so we don't need to call update_derived_permission_lock, which does the same thing. Change-Id: I0748100828c6af806da807241a33bf42be614935 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/inode.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 53b2a7024d7e..e1a680a45c84 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -515,17 +515,6 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dir != old_dir) { sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); - - /* update the derived permission of the old_dentry - * with its new parent - */ - new_parent = dget_parent(new_dentry); - if(new_parent) { - if(old_dentry->d_inode) { - update_derived_permission_lock(old_dentry); - } - dput(new_parent); - } } /* At this point, not all dentry information has been moved, so * we pass along new_dentry for the name.*/ From 3fc0f13c2cf6793bc2718dde755e27ce50ed5e09 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 25 Jan 2017 13:48:45 -0800 Subject: [PATCH 150/281] ANDROID: sdcardfs: Add GID Derivation to sdcardfs This changes sdcardfs to modify the user and group in the underlying filesystem depending on its usage. Ownership is set by Android user, and package, as well as if the file is under obb or cache. Other files can be labeled by extension. Those values are set via the configfs interace. To add an entry, mkdir -p [configfs root]/sdcardfs/extensions/[gid]/[ext] Bug: 34262585 Change-Id: I4e030ce84f094a678376349b1a96923e5076a0f4 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 160 +++++++++++++++++++++++-- fs/sdcardfs/file.c | 2 +- fs/sdcardfs/inode.c | 35 +++--- fs/sdcardfs/lookup.c | 3 +- fs/sdcardfs/multiuser.h | 28 +++-- fs/sdcardfs/packagelist.c | 236 ++++++++++++++++++++++++++++++++++--- fs/sdcardfs/sdcardfs.h | 25 +++- 7 files changed, 429 insertions(+), 60 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 12532205f825..6d585c1815f1 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -30,6 +30,8 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->userid = pi->userid; ci->d_uid = pi->d_uid; ci->under_android = pi->under_android; + ci->under_cache = pi->under_cache; + ci->under_obb = pi->under_obb; set_top(ci, pi->top); } @@ -43,11 +45,13 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, info->userid = userid; info->d_uid = uid; info->under_android = under_android; + info->under_cache = false; + info->under_obb = false; set_top(info, top); } /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ -void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry) +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name) { struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); @@ -57,26 +61,30 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st * the properties are maintained on its private fields * because the inode attributes will be modified with that of * its lower inode. - * The derived state will be updated on the last - * stage of each system call by fix_derived_permission(inode). + * These values are used by our custom permission call instead + * of using the inode permissions. */ inherit_derived_state(parent->d_inode, dentry->d_inode); + /* Files don't get special labels */ + if (!S_ISDIR(dentry->d_inode->i_mode)) + return; /* Derive custom permissions based on parent and current node */ switch (parent_info->perm) { case PERM_INHERIT: + case PERM_ANDROID_PACKAGE_CACHE: /* Already inherited above */ break; case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; - info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10); + info->userid = simple_strtoul(name, NULL, 10); set_top(info, &info->vfs_inode); break; case PERM_ROOT: /* Assume masked off by default. */ - if (!strcasecmp(newdentry->d_name.name, "Android")) { + if (!strcasecmp(name, "Android")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->under_android = true; @@ -84,36 +92,145 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, st } break; case PERM_ANDROID: - if (!strcasecmp(newdentry->d_name.name, "data")) { + if (!strcasecmp(name, "data")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; set_top(info, &info->vfs_inode); - } else if (!strcasecmp(newdentry->d_name.name, "obb")) { + } else if (!strcasecmp(name, "obb")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; + info->under_obb = true; set_top(info, &info->vfs_inode); /* Single OBB directory is always shared */ - } else if (!strcasecmp(newdentry->d_name.name, "media")) { + } else if (!strcasecmp(name, "media")) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; set_top(info, &info->vfs_inode); } break; - case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: + case PERM_ANDROID_DATA: case PERM_ANDROID_MEDIA: - appid = get_appid(newdentry->d_name.name); - if (appid != 0 && !is_excluded(newdentry->d_name.name, parent_info->userid)) { + info->perm = PERM_ANDROID_PACKAGE; + appid = get_appid(name); + if (appid != 0 && !is_excluded(name, parent_info->userid)) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } set_top(info, &info->vfs_inode); break; + case PERM_ANDROID_PACKAGE: + if (!strcasecmp(name, "cache")) { + info->perm = PERM_ANDROID_PACKAGE_CACHE; + info->under_cache = true; + } + break; } } void get_derived_permission(struct dentry *parent, struct dentry *dentry) { - get_derived_permission_new(parent, dentry, dentry); + get_derived_permission_new(parent, dentry, dentry->d_name.name); +} + +static appid_t get_type(const char *name) { + const char *ext = strrchr(name, '.'); + appid_t id; + + if (ext && ext[0]) { + ext = &ext[1]; + id = get_ext_gid(ext); + return id?:AID_MEDIA_RW; + } + return AID_MEDIA_RW; +} + +void fixup_lower_ownership(struct dentry* dentry, const char *name) { + struct path path; + struct inode *inode; + int error; + struct sdcardfs_inode_info *info; + struct sdcardfs_inode_info *info_top; + perm_t perm; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + uid_t uid = sbi->options.fs_low_uid; + gid_t gid = sbi->options.fs_low_gid; + struct iattr newattrs; + + info = SDCARDFS_I(dentry->d_inode); + perm = info->perm; + if (info->under_obb) { + perm = PERM_ANDROID_OBB; + } else if (info->under_cache) { + perm = PERM_ANDROID_PACKAGE_CACHE; + } else if (perm == PERM_INHERIT) { + info_top = SDCARDFS_I(grab_top(info)); + perm = info_top->perm; + release_top(info); + } + + switch (perm) { + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + case PERM_ANDROID_PACKAGE: + case PERM_ANDROID_PACKAGE_CACHE: + uid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_OBB: + uid = AID_MEDIA_OBB; + break; + case PERM_PRE_ROOT: + default: + break; + } + switch (perm) { + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + if (S_ISDIR(dentry->d_inode->i_mode)) + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); + else + gid = multiuser_get_uid(info->userid, get_type(name)); + break; + case PERM_ANDROID_OBB: + gid = AID_MEDIA_OBB; + break; + case PERM_ANDROID_PACKAGE: + if (info->d_uid != 0) + gid = multiuser_get_ext_gid(info->userid, info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_PACKAGE_CACHE: + if (info->d_uid != 0) + gid = multiuser_get_cache_gid(info->userid, info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_PRE_ROOT: + default: + break; + } + + sdcardfs_get_lower_path(dentry, &path); + inode = path.dentry->d_inode; + if (path.dentry->d_inode->i_gid != gid || path.dentry->d_inode->i_uid != uid) { + newattrs.ia_valid = ATTR_GID | ATTR_UID | ATTR_FORCE; + newattrs.ia_uid = make_kuid(current_user_ns(), uid); + newattrs.ia_gid = make_kgid(current_user_ns(), gid); + if (!S_ISDIR(inode->i_mode)) + newattrs.ia_valid |= + ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; + mutex_lock(&inode->i_mutex); + error = security_path_chown(&path, newattrs.ia_uid, newattrs.ia_gid); + if (!error) + error = notify_change2(path.mnt, path.dentry, &newattrs); + mutex_unlock(&inode->i_mutex); + if (error) + pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n"); + } } static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) { @@ -167,9 +284,28 @@ void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { dput(dentry); } +void drop_recursive(struct dentry *parent) { + struct dentry *dentry; + struct sdcardfs_inode_info *info; + if (!parent->d_inode) + return; + info = SDCARDFS_I(parent->d_inode); + spin_lock(&parent->d_lock); + list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { + if (dentry->d_inode) { + if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { + drop_recursive(dentry); + d_drop(dentry); + } + } + } + spin_unlock(&parent->d_lock); +} + void fixup_top_recursive(struct dentry *parent) { struct dentry *dentry; struct sdcardfs_inode_info *info; + if (!parent->d_inode) return; info = SDCARDFS_I(parent->d_inode); diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 2b3aa03ab271..71d8af2d6e6d 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -225,7 +225,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) } /* save current_cred and override it */ - OVERRIDE_CRED(sbi, saved_cred); + OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode)); file->f_mode |= FMODE_NONMAPPABLE; file->private_data = diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index e1a680a45c84..8311b3e53163 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -22,16 +22,21 @@ #include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ -const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info) { struct cred * cred; const struct cred * old_cred; + uid_t uid; cred = prepare_creds(); if (!cred) return NULL; - cred->fsuid = sbi->options.fs_low_uid; + if (info->under_obb) + uid = AID_MEDIA_OBB; + else + uid = multiuser_get_uid(info->userid, sbi->options.fs_low_uid); + cred->fsuid = uid; cred->fsgid = sbi->options.fs_low_gid; old_cred = override_creds(cred); @@ -70,7 +75,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -98,6 +103,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, goto out; fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + fixup_lower_ownership(dentry, dentry->d_name.name); out: current->fs = saved_fs; @@ -171,7 +177,7 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -279,7 +285,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* check disk space */ if (!check_min_free_space(dentry, 0, 1)) { @@ -343,9 +349,8 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); - + fixup_lower_ownership(dentry, dentry->d_name.name); unlock_dir(lower_parent_dentry); - if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; @@ -353,6 +358,8 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { + REVERT_CRED(saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dentry->d_inode)); set_fs_pwd(current->fs, &lower_path); touch_err = touch(".nomedia", 0664); if (touch_err) { @@ -390,7 +397,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry * the dentry on the original path should be deleted. */ @@ -466,7 +473,6 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *lower_new_dir_dentry = NULL; struct vfsmount *lower_mnt = NULL; struct dentry *trap = NULL; - struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; const struct cred *saved_cred = NULL; @@ -480,7 +486,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir)); sdcardfs_get_real_lower(old_dentry, &lower_old_path); sdcardfs_get_lower_path(new_dentry, &lower_new_path); @@ -516,11 +522,10 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } - /* At this point, not all dentry information has been moved, so - * we pass along new_dentry for the name.*/ - get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry); + get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry->d_name.name); fixup_tmp_permissions(old_dentry->d_inode); - fixup_top_recursive(old_dentry); + fixup_lower_ownership(old_dentry, new_dentry->d_name.name); + drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */ out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); @@ -763,7 +768,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct goto out_err; /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode)); sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index d02501213620..165da604cf14 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -368,7 +368,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, } /* save current_cred and override it */ - OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred); + OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); sdcardfs_get_lower_path(parent, &lower_parent_path); @@ -392,6 +392,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, /* get derived permission */ get_derived_permission(parent, dentry); fixup_tmp_permissions(dentry->d_inode); + fixup_lower_ownership(dentry, dentry->d_name.name); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index 923ba101dfa9..52bc20080904 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -18,20 +18,32 @@ * General Public License. */ -#define MULTIUSER_APP_PER_USER_RANGE 100000 +#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */ +#define AID_APP_START 10000 /* first app user */ +#define AID_APP_END 19999 /* last app user */ +#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */ +#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */ +#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ typedef uid_t userid_t; typedef uid_t appid_t; -static inline userid_t multiuser_get_user_id(uid_t uid) { - return uid / MULTIUSER_APP_PER_USER_RANGE; +static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) { + return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } -static inline appid_t multiuser_get_app_id(uid_t uid) { - return uid % MULTIUSER_APP_PER_USER_RANGE; +static inline gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) { + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START); + } else { + return -1; + } } -static inline uid_t multiuser_get_uid(userid_t userId, appid_t appId) { - return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE); +static inline gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id) { + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START); + } else { + return -1; + } } - diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 05b5f34ff9e6..d7b31aad87d5 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -21,6 +21,7 @@ #include "sdcardfs.h" #include #include +#include #include @@ -38,6 +39,8 @@ struct hashtable_entry { static DEFINE_HASHTABLE(package_to_appid, 8); static DEFINE_HASHTABLE(package_to_userid, 8); +static DEFINE_HASHTABLE(ext_to_groupid, 8); + static struct kmem_cache *hashtable_entry_cachep; @@ -53,15 +56,33 @@ static unsigned int str_hash(const char *key) { return h; } -appid_t get_appid(const char *app_name) +appid_t get_appid(const char *key) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(app_name); + unsigned int hash = str_hash(key); appid_t ret_id; rcu_read_lock(); hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(app_name, hash_cur->key)) { + if (!strcasecmp(key, hash_cur->key)) { + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); + return ret_id; + } + } + rcu_read_unlock(); + return 0; +} + +appid_t get_ext_gid(const char *key) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(key); + appid_t ret_id; + + rcu_read_lock(); + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key)) { ret_id = atomic_read(&hash_cur->value); rcu_read_unlock(); return ret_id; @@ -124,7 +145,7 @@ int open_flags_to_access_mode(int open_flags) { } } -static struct hashtable_entry *alloc_packagelist_entry(const char *key, +static struct hashtable_entry *alloc_hashtable_entry(const char *key, appid_t value) { struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, @@ -154,13 +175,31 @@ static int insert_packagelist_appid_entry_locked(const char *key, appid_t value) return 0; } } - new_entry = alloc_packagelist_entry(key, value); + new_entry = alloc_hashtable_entry(key, value); if (!new_entry) return -ENOMEM; hash_add_rcu(package_to_appid, &new_entry->hlist, hash); return 0; } +static int insert_ext_gid_entry_locked(const char *key, appid_t value) +{ + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + unsigned int hash = str_hash(key); + + /* An extension can only belong to one gid */ + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key)) + return -EINVAL; + } + new_entry = alloc_hashtable_entry(key, value); + if (!new_entry) + return -ENOMEM; + hash_add_rcu(ext_to_groupid, &new_entry->hlist, hash); + return 0; +} + static int insert_userid_exclude_entry_locked(const char *key, userid_t value) { struct hashtable_entry *hash_cur; @@ -172,7 +211,7 @@ static int insert_userid_exclude_entry_locked(const char *key, userid_t value) if (atomic_read(&hash_cur->value) == value && !strcasecmp(key, hash_cur->key)) return 0; } - new_entry = alloc_packagelist_entry(key, value); + new_entry = alloc_hashtable_entry(key, value); if (!new_entry) return -ENOMEM; hash_add_rcu(package_to_userid, &new_entry->hlist, hash); @@ -234,6 +273,17 @@ static int insert_packagelist_entry(const char *key, appid_t value) return err; } +static int insert_ext_gid_entry(const char *key, appid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_ext_gid_entry_locked(key, value); + mutex_unlock(&sdcardfs_super_list_lock); + + return err; +} + static int insert_userid_exclude_entry(const char *key, userid_t value) { int err; @@ -247,7 +297,7 @@ static int insert_userid_exclude_entry(const char *key, userid_t value) return err; } -static void free_packagelist_entry(struct hashtable_entry *entry) +static void free_hashtable_entry(struct hashtable_entry *entry) { kfree(entry->key); hash_del_rcu(&entry->dlist); @@ -276,7 +326,7 @@ static void remove_packagelist_entry_locked(const char *key) } synchronize_rcu(); hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) - free_packagelist_entry(hash_cur); + free_hashtable_entry(hash_cur); } static void remove_packagelist_entry(const char *key) @@ -288,6 +338,29 @@ static void remove_packagelist_entry(const char *key) return; } +static void remove_ext_gid_entry_locked(const char *key, gid_t group) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = str_hash(key); + + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == group) { + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_hashtable_entry(hash_cur); + break; + } + } +} + +static void remove_ext_gid_entry(const char *key, gid_t group) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_ext_gid_entry_locked(key, group); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + static void remove_userid_all_entry_locked(userid_t userid) { struct hashtable_entry *hash_cur; @@ -303,7 +376,7 @@ static void remove_userid_all_entry_locked(userid_t userid) } synchronize_rcu(); hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) { - free_packagelist_entry(hash_cur); + free_hashtable_entry(hash_cur); } } @@ -325,7 +398,7 @@ static void remove_userid_exclude_entry_locked(const char *key, userid_t userid) if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == userid) { hash_del_rcu(&hash_cur->hlist); synchronize_rcu(); - free_packagelist_entry(hash_cur); + free_hashtable_entry(hash_cur); break; } } @@ -357,7 +430,7 @@ static void packagelist_destroy(void) } synchronize_rcu(); hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) - free_packagelist_entry(hash_cur); + free_hashtable_entry(hash_cur); mutex_unlock(&sdcardfs_super_list_lock); printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); } @@ -375,6 +448,7 @@ static inline struct package_details *to_package_details(struct config_item *ite CONFIGFS_ATTR_STRUCT(package_details); #define PACKAGE_DETAILS_ATTR(_name, _mode, _show, _store) \ struct package_details_attribute package_details_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) +#define PACKAGE_DETAILS_ATTRIBUTE(name) &package_details_attr_##name.attr static ssize_t package_details_appid_show(struct package_details *package_details, char *page) @@ -466,9 +540,9 @@ PACKAGE_DETAILS_ATTR(excluded_userids, S_IRUGO | S_IWUGO, PACKAGE_DETAILS_ATTR(clear_userid, S_IWUGO, NULL, package_details_clear_userid_store); static struct configfs_attribute *package_details_attrs[] = { - &package_details_attr_appid.attr, - &package_details_attr_excluded_userids.attr, - &package_details_attr_clear_userid.attr, + PACKAGE_DETAILS_ATTRIBUTE(appid), + PACKAGE_DETAILS_ATTRIBUTE(excluded_userids), + PACKAGE_DETAILS_ATTRIBUTE(clear_userid), NULL, }; @@ -486,6 +560,127 @@ static struct config_item_type package_appid_type = { .ct_owner = THIS_MODULE, }; +struct extensions_value { + struct config_group group; + unsigned int num; +}; + +struct extension_details { + struct config_item item; + const char* name; + unsigned int num; +}; + +static inline struct extensions_value *to_extensions_value(struct config_item *item) +{ + return item ? container_of(to_config_group(item), struct extensions_value, group) : NULL; +} + +static inline struct extension_details *to_extension_details(struct config_item *item) +{ + return item ? container_of(item, struct extension_details, item) : NULL; +} + +static void extension_details_release(struct config_item *item) +{ + struct extension_details *extension_details = to_extension_details(item); + + printk(KERN_INFO "sdcardfs: No longer mapping %s files to gid %d\n", + extension_details->name, extension_details->num); + remove_ext_gid_entry(extension_details->name, extension_details->num); + kfree(extension_details->name); + kfree(extension_details); +} + +static struct configfs_item_operations extension_details_item_ops = { + .release = extension_details_release, +}; + +static struct config_item_type extension_details_type = { + .ct_item_ops = &extension_details_item_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item *extension_details_make_item(struct config_group *group, const char *name) +{ + struct extensions_value *extensions_value = to_extensions_value(&group->cg_item); + struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL); + int ret; + if (!extension_details) + return ERR_PTR(-ENOMEM); + + extension_details->name = kstrdup(name, GFP_KERNEL); + if (!extension_details->name) { + kfree(extension_details); + return ERR_PTR(-ENOMEM); + } + extension_details->num = extensions_value->num; + ret = insert_ext_gid_entry(name, extensions_value->num); + + if (ret) { + kfree(extension_details->name); + kfree(extension_details); + return ERR_PTR(ret); + } + config_item_init_type_name(&extension_details->item, name, &extension_details_type); + + return &extension_details->item; +} + +static struct configfs_group_operations extensions_value_group_ops = { + .make_item = extension_details_make_item, +}; + +static struct config_item_type extensions_name_type = { + .ct_group_ops = &extensions_value_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *extensions_make_group(struct config_group *group, const char *name) +{ + struct extensions_value *extensions_value; + unsigned int tmp; + int ret; + + extensions_value = kzalloc(sizeof(struct extensions_value), GFP_KERNEL); + if (!extensions_value) + return ERR_PTR(-ENOMEM); + ret = kstrtouint(name, 10, &tmp); + if (ret) { + kfree(extensions_value); + return ERR_PTR(ret); + } + + extensions_value->num = tmp; + config_group_init_type_name(&extensions_value->group, name, + &extensions_name_type); + return &extensions_value->group; +} + +static void extensions_drop_group(struct config_group *group, struct config_item *item) +{ + struct extensions_value *value = to_extensions_value(item); + printk(KERN_INFO "sdcardfs: No longer mapping any files to gid %d\n", value->num); + kfree(value); +} + +static struct configfs_group_operations extensions_group_ops = { + .make_group = extensions_make_group, + .drop_item = extensions_drop_group, +}; + +static struct config_item_type extensions_type = { + .ct_group_ops = &extensions_group_ops, + .ct_owner = THIS_MODULE, +}; + +struct config_group extension_group = { + .cg_item = { + .ci_namebuf = "extensions", + .ci_type = &extensions_type, + }, +}; + struct packages { struct configfs_subsystem subsystem; }; @@ -569,7 +764,6 @@ static ssize_t packages_remove_userid_store(struct packages *packages, struct packages_attribute packages_attr_packages_gid_list = __CONFIGFS_ATTR_RO(packages_gid.list, packages_list_show); PACKAGES_ATTR(remove_userid, S_IWUGO, NULL, packages_remove_userid_store); - static struct configfs_attribute *packages_attrs[] = { &packages_attr_packages_gid_list.attr, &packages_attr_remove_userid.attr, @@ -597,6 +791,11 @@ static struct config_item_type packages_type = { .ct_owner = THIS_MODULE, }; +struct config_group *sd_default_groups[] = { + &extension_group, + NULL, +}; + static struct packages sdcardfs_packages = { .subsystem = { .su_group = { @@ -604,15 +803,18 @@ static struct packages sdcardfs_packages = { .ci_namebuf = "sdcardfs", .ci_type = &packages_type, }, + .default_groups = sd_default_groups, }, }, }; static int configfs_sdcardfs_init(void) { - int ret; + int ret, i; struct configfs_subsystem *subsys = &sdcardfs_packages.subsystem; - + for (i = 0; sd_default_groups[i]; i++) { + config_group_init(sd_default_groups[i]); + } config_group_init(&subsys->su_group); mutex_init(&subsys->su_mutex); ret = configfs_register_subsystem(subsys); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index e91d281cec3f..c0b554e7c9d0 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -65,6 +65,9 @@ #define AID_SDCARD_PICS 1033 /* external storage photos access */ #define AID_SDCARD_AV 1034 /* external storage audio/video access */ #define AID_SDCARD_ALL 1035 /* access all users external storage */ +#define AID_MEDIA_OBB 1059 /* obb files */ + +#define AID_SDCARD_IMAGE 1057 #define AID_PACKAGE_INFO 1027 @@ -91,12 +94,12 @@ * These two macro should be used in pair, and OVERRIDE_CRED() should be * placed at the beginning of a function, right after variable declaration. */ -#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred) \ - saved_cred = override_fsids(sdcardfs_sbi); \ +#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ if (!saved_cred) { return -ENOMEM; } -#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred) \ - saved_cred = override_fsids(sdcardfs_sbi); \ +#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ if (!saved_cred) { return ERR_PTR(-ENOMEM); } #define REVERT_CRED(saved_cred) revert_fsids(saved_cred) @@ -127,13 +130,18 @@ typedef enum { PERM_ANDROID_OBB, /* This node is "/Android/media" */ PERM_ANDROID_MEDIA, + /* This node is "/Android/[data|media|obb]/[package]" */ + PERM_ANDROID_PACKAGE, + /* This node is "/Android/[data|media|obb]/[package]/cache" */ + PERM_ANDROID_PACKAGE_CACHE, } perm_t; struct sdcardfs_sb_info; struct sdcardfs_mount_options; +struct sdcardfs_inode_info; /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ -const struct cred * override_fsids(struct sdcardfs_sb_info* sbi); +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info); /* Do not directly use this function, use REVERT_CRED() instead. */ void revert_fsids(const struct cred * old_cred); @@ -175,6 +183,8 @@ struct sdcardfs_inode_info { userid_t userid; uid_t d_uid; bool under_android; + bool under_cache; + bool under_obb; /* top folder for ownership */ struct inode *top; @@ -447,6 +457,7 @@ extern struct list_head sdcardfs_super_list; /* for packagelist.c */ extern appid_t get_appid(const char *app_name); +extern appid_t get_ext_gid(const char *app_name); extern appid_t is_excluded(const char *app_name, userid_t userid); extern int check_caller_access_to_name(struct inode *parent_node, const char* name); extern int open_flags_to_access_mode(int open_flags); @@ -466,11 +477,13 @@ struct limit_search { extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); -extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry); +extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name); +extern void drop_recursive(struct dentry *parent); extern void fixup_top_recursive(struct dentry *parent); extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); extern void update_derived_permission_lock(struct dentry *dentry); +void fixup_lower_ownership(struct dentry* dentry, const char *name); extern int need_graft_path(struct dentry *dentry); extern int is_base_obbpath(struct dentry *dentry); extern int is_obbpath_invalid(struct dentry *dentry); From 5d7dae0cd441b177ab8882f23d42de28ad2439c3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 27 Jan 2017 19:35:08 -0800 Subject: [PATCH 151/281] ANDROID: sdcardfs: switch to full_name_hash and qstr Use the kernel's string hash function instead of rolling our own. Additionally, save a bit of calculation by using the qstr struct in place of strings. Change-Id: I0bbeb5ec2a9233f40135ad632e6f22c30ffa95c1 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/packagelist.c | 189 ++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 81 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index d7b31aad87d5..dc5dc4a4b362 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -22,7 +22,7 @@ #include #include #include - +#include #include #include @@ -33,7 +33,7 @@ struct hashtable_entry { struct hlist_node hlist; struct hlist_node dlist; /* for deletion cleanup */ - const char *key; + struct qstr key; atomic_t value; }; @@ -44,27 +44,28 @@ static DEFINE_HASHTABLE(ext_to_groupid, 8); static struct kmem_cache *hashtable_entry_cachep; -static unsigned int str_hash(const char *key) { - int i; - unsigned int h = strlen(key); - char *data = (char *)key; +static void inline qstr_init(struct qstr *q, const char *name) { + q->name = name; + q->len = strlen(q->name); + q->hash = full_name_hash(q->name, q->len); +} - for (i = 0; i < strlen(key); i++) { - h = h * 31 + *data; - data++; - } - return h; +static inline int qstr_copy(const struct qstr *src, struct qstr *dest) { + dest->name = kstrdup(src->name, GFP_KERNEL); + dest->hash_len = src->hash_len; + return !!dest->name; } -appid_t get_appid(const char *key) + +static appid_t __get_appid(const struct qstr *key) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; appid_t ret_id; rcu_read_lock(); hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { + if (!strcasecmp(key->name, hash_cur->key.name)) { ret_id = atomic_read(&hash_cur->value); rcu_read_unlock(); return ret_id; @@ -74,15 +75,22 @@ appid_t get_appid(const char *key) return 0; } -appid_t get_ext_gid(const char *key) +appid_t get_appid(const char *key) +{ + struct qstr q; + qstr_init(&q, key); + return __get_appid(&q); +} + +static appid_t __get_ext_gid(const struct qstr *key) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; appid_t ret_id; rcu_read_lock(); hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { + if (!strcasecmp(key->name, hash_cur->key.name)) { ret_id = atomic_read(&hash_cur->value); rcu_read_unlock(); return ret_id; @@ -92,14 +100,22 @@ appid_t get_ext_gid(const char *key) return 0; } -appid_t is_excluded(const char *app_name, userid_t user) +appid_t get_ext_gid(const char *key) +{ + struct qstr q; + qstr_init(&q, key); + return __get_ext_gid(&q); +} + +static appid_t __is_excluded(const struct qstr *app_name, userid_t user) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(app_name); + unsigned int hash = app_name->hash; rcu_read_lock(); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (atomic_read(&hash_cur->value) == user && !strcasecmp(app_name, hash_cur->key)) { + if (atomic_read(&hash_cur->value) == user && + !strcasecmp(app_name->name, hash_cur->key.name)) { rcu_read_unlock(); return 1; } @@ -108,6 +124,14 @@ appid_t is_excluded(const char *app_name, userid_t user) return 0; } +appid_t is_excluded(const char *app_name, userid_t user) +{ + struct qstr q; + qstr_init(&q, app_name); + return __is_excluded(&q, user); +} + + /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access * even further, such as enforcing that apps hold sdcard_rw. */ @@ -145,7 +169,7 @@ int open_flags_to_access_mode(int open_flags) { } } -static struct hashtable_entry *alloc_hashtable_entry(const char *key, +static struct hashtable_entry *alloc_hashtable_entry(const struct qstr *key, appid_t value) { struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, @@ -153,8 +177,7 @@ static struct hashtable_entry *alloc_hashtable_entry(const char *key, if (!ret) return NULL; - ret->key = kstrdup(key, GFP_KERNEL); - if (!ret->key) { + if (!qstr_copy(key, &ret->key)) { kmem_cache_free(hashtable_entry_cachep, ret); return NULL; } @@ -163,14 +186,14 @@ static struct hashtable_entry *alloc_hashtable_entry(const char *key, return ret; } -static int insert_packagelist_appid_entry_locked(const char *key, appid_t value) +static int insert_packagelist_appid_entry_locked(const struct qstr *key, appid_t value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { + if (!strcasecmp(key->name, hash_cur->key.name)) { atomic_set(&hash_cur->value, value); return 0; } @@ -182,15 +205,15 @@ static int insert_packagelist_appid_entry_locked(const char *key, appid_t value) return 0; } -static int insert_ext_gid_entry_locked(const char *key, appid_t value) +static int insert_ext_gid_entry_locked(const struct qstr *key, appid_t value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; /* An extension can only belong to one gid */ hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) + if (!strcasecmp(key->name, hash_cur->key.name)) return -EINVAL; } new_entry = alloc_hashtable_entry(key, value); @@ -200,15 +223,16 @@ static int insert_ext_gid_entry_locked(const char *key, appid_t value) return 0; } -static int insert_userid_exclude_entry_locked(const char *key, userid_t value) +static int insert_userid_exclude_entry_locked(const struct qstr *key, userid_t value) { struct hashtable_entry *hash_cur; struct hashtable_entry *new_entry; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; /* Only insert if not already present */ hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (atomic_read(&hash_cur->value) == value && !strcasecmp(key, hash_cur->key)) + if (atomic_read(&hash_cur->value) == value && + !strcasecmp(key->name, hash_cur->key.name)) return 0; } new_entry = alloc_hashtable_entry(key, value); @@ -218,13 +242,13 @@ static int insert_userid_exclude_entry_locked(const char *key, userid_t value) return 0; } -static void fixup_all_perms_name(const char *key) +static void fixup_all_perms_name(const struct qstr *key) { struct sdcardfs_sb_info *sbinfo; struct limit_search limit = { .flags = BY_NAME, - .name = key, - .length = strlen(key), + .name = key->name, + .length = key->len, }; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo_has_sdcard_magic(sbinfo)) @@ -232,13 +256,13 @@ static void fixup_all_perms_name(const char *key) } } -static void fixup_all_perms_name_userid(const char *key, userid_t userid) +static void fixup_all_perms_name_userid(const struct qstr *key, userid_t userid) { struct sdcardfs_sb_info *sbinfo; struct limit_search limit = { .flags = BY_NAME | BY_USERID, - .name = key, - .length = strlen(key), + .name = key->name, + .length = key->len, .userid = userid, }; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { @@ -260,7 +284,7 @@ static void fixup_all_perms_userid(userid_t userid) } } -static int insert_packagelist_entry(const char *key, appid_t value) +static int insert_packagelist_entry(const struct qstr *key, appid_t value) { int err; @@ -273,7 +297,7 @@ static int insert_packagelist_entry(const char *key, appid_t value) return err; } -static int insert_ext_gid_entry(const char *key, appid_t value) +static int insert_ext_gid_entry(const struct qstr *key, appid_t value) { int err; @@ -284,7 +308,7 @@ static int insert_ext_gid_entry(const char *key, appid_t value) return err; } -static int insert_userid_exclude_entry(const char *key, userid_t value) +static int insert_userid_exclude_entry(const struct qstr *key, userid_t value) { int err; @@ -299,26 +323,26 @@ static int insert_userid_exclude_entry(const char *key, userid_t value) static void free_hashtable_entry(struct hashtable_entry *entry) { - kfree(entry->key); + kfree(entry->key.name); hash_del_rcu(&entry->dlist); kmem_cache_free(hashtable_entry_cachep, entry); } -static void remove_packagelist_entry_locked(const char *key) +static void remove_packagelist_entry_locked(const struct qstr *key) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; struct hlist_node *h_t; HLIST_HEAD(free_list); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { + if (!strcasecmp(key->name, hash_cur->key.name)) { hash_del_rcu(&hash_cur->hlist); hlist_add_head(&hash_cur->dlist, &free_list); } } hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { + if (!strcasecmp(key->name, hash_cur->key.name)) { hash_del_rcu(&hash_cur->hlist); hlist_add_head(&hash_cur->dlist, &free_list); break; @@ -329,7 +353,7 @@ static void remove_packagelist_entry_locked(const char *key) free_hashtable_entry(hash_cur); } -static void remove_packagelist_entry(const char *key) +static void remove_packagelist_entry(const struct qstr *key) { mutex_lock(&sdcardfs_super_list_lock); remove_packagelist_entry_locked(key); @@ -338,13 +362,13 @@ static void remove_packagelist_entry(const char *key) return; } -static void remove_ext_gid_entry_locked(const char *key, gid_t group) +static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == group) { + if (!strcasecmp(key->name, hash_cur->key.name) && atomic_read(&hash_cur->value) == group) { hash_del_rcu(&hash_cur->hlist); synchronize_rcu(); free_hashtable_entry(hash_cur); @@ -353,7 +377,7 @@ static void remove_ext_gid_entry_locked(const char *key, gid_t group) } } -static void remove_ext_gid_entry(const char *key, gid_t group) +static void remove_ext_gid_entry(const struct qstr *key, gid_t group) { mutex_lock(&sdcardfs_super_list_lock); remove_ext_gid_entry_locked(key, group); @@ -389,13 +413,14 @@ static void remove_userid_all_entry(userid_t userid) return; } -static void remove_userid_exclude_entry_locked(const char *key, userid_t userid) +static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t userid) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + unsigned int hash = key->hash; hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key) && atomic_read(&hash_cur->value) == userid) { + if (!strcasecmp(key->name, hash_cur->key.name) && + atomic_read(&hash_cur->value) == userid) { hash_del_rcu(&hash_cur->hlist); synchronize_rcu(); free_hashtable_entry(hash_cur); @@ -404,7 +429,7 @@ static void remove_userid_exclude_entry_locked(const char *key, userid_t userid) } } -static void remove_userid_exclude_entry(const char *key, userid_t userid) +static void remove_userid_exclude_entry(const struct qstr *key, userid_t userid) { mutex_lock(&sdcardfs_super_list_lock); remove_userid_exclude_entry_locked(key, userid); @@ -437,7 +462,7 @@ static void packagelist_destroy(void) struct package_details { struct config_item item; - const char* name; + struct qstr name; }; static inline struct package_details *to_package_details(struct config_item *item) @@ -453,7 +478,7 @@ struct package_details_attribute package_details_attr_##_name = __CONFIGFS_ATTR( static ssize_t package_details_appid_show(struct package_details *package_details, char *page) { - return scnprintf(page, PAGE_SIZE, "%u\n", get_appid(package_details->name)); + return scnprintf(page, PAGE_SIZE, "%u\n", __get_appid(&package_details->name)); } static ssize_t package_details_appid_store(struct package_details *package_details, @@ -466,7 +491,7 @@ static ssize_t package_details_appid_store(struct package_details *package_detai if (ret) return ret; - ret = insert_packagelist_entry(package_details->name, tmp); + ret = insert_packagelist_entry(&package_details->name, tmp); if (ret) return ret; @@ -478,12 +503,12 @@ static ssize_t package_details_excluded_userids_show(struct package_details *pac char *page) { struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(package_details->name); + unsigned int hash = package_details->name.hash; int count = 0; rcu_read_lock(); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(package_details->name, hash_cur->key)) + if (!strcasecmp(package_details->name.name, hash_cur->key.name)) count += scnprintf(page + count, PAGE_SIZE - count, "%d ", atomic_read(&hash_cur->value)); } @@ -504,7 +529,7 @@ static ssize_t package_details_excluded_userids_store(struct package_details *pa if (ret) return ret; - ret = insert_userid_exclude_entry(package_details->name, tmp); + ret = insert_userid_exclude_entry(&package_details->name, tmp); if (ret) return ret; @@ -521,16 +546,16 @@ static ssize_t package_details_clear_userid_store(struct package_details *packag ret = kstrtouint(page, 10, &tmp); if (ret) return ret; - remove_userid_exclude_entry(package_details->name, tmp); + remove_userid_exclude_entry(&package_details->name, tmp); return count; } static void package_details_release(struct config_item *item) { struct package_details *package_details = to_package_details(item); - printk(KERN_INFO "sdcardfs: removing %s\n", package_details->name); - remove_packagelist_entry(package_details->name); - kfree(package_details->name); + printk(KERN_INFO "sdcardfs: removing %s\n", package_details->name.name); + remove_packagelist_entry(&package_details->name); + kfree(package_details->name.name); kfree(package_details); } @@ -567,7 +592,7 @@ struct extensions_value { struct extension_details { struct config_item item; - const char* name; + struct qstr name; unsigned int num; }; @@ -586,9 +611,9 @@ static void extension_details_release(struct config_item *item) struct extension_details *extension_details = to_extension_details(item); printk(KERN_INFO "sdcardfs: No longer mapping %s files to gid %d\n", - extension_details->name, extension_details->num); - remove_ext_gid_entry(extension_details->name, extension_details->num); - kfree(extension_details->name); + extension_details->name.name, extension_details->num); + remove_ext_gid_entry(&extension_details->name, extension_details->num); + kfree(extension_details->name.name); kfree(extension_details); } @@ -605,20 +630,21 @@ static struct config_item *extension_details_make_item(struct config_group *grou { struct extensions_value *extensions_value = to_extensions_value(&group->cg_item); struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL); + const char *tmp; int ret; if (!extension_details) return ERR_PTR(-ENOMEM); - extension_details->name = kstrdup(name, GFP_KERNEL); - if (!extension_details->name) { + tmp = kstrdup(name, GFP_KERNEL); + if (!tmp) { kfree(extension_details); return ERR_PTR(-ENOMEM); } - extension_details->num = extensions_value->num; - ret = insert_ext_gid_entry(name, extensions_value->num); + qstr_init(&extension_details->name, tmp); + ret = insert_ext_gid_entry(&extension_details->name, extensions_value->num); if (ret) { - kfree(extension_details->name); + kfree(extension_details->name.name); kfree(extension_details); return ERR_PTR(ret); } @@ -699,16 +725,17 @@ struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR_RO(_name, _sho static struct config_item *packages_make_item(struct config_group *group, const char *name) { struct package_details *package_details; + const char *tmp; package_details = kzalloc(sizeof(struct package_details), GFP_KERNEL); if (!package_details) return ERR_PTR(-ENOMEM); - package_details->name = kstrdup(name, GFP_KERNEL); - if (!package_details->name) { + tmp = kstrdup(name, GFP_KERNEL); + if (!tmp) { kfree(package_details); return ERR_PTR(-ENOMEM); } - + qstr_init(&package_details->name, tmp); config_item_init_type_name(&package_details->item, name, &package_appid_type); @@ -728,13 +755,13 @@ static ssize_t packages_list_show(struct packages *packages, rcu_read_lock(); hash_for_each_rcu(package_to_appid, i, hash_cur_app, hlist) { written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", - hash_cur_app->key, atomic_read(&hash_cur_app->value)); - hash = str_hash(hash_cur_app->key); + hash_cur_app->key.name, atomic_read(&hash_cur_app->value)); + hash = hash_cur_app->key.hash; hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) { - if (!strcasecmp(hash_cur_app->key, hash_cur_user->key)) { + if (!strcasecmp(hash_cur_app->key.name, hash_cur_user->key.name)) { written += scnprintf(page + count + written - 1, PAGE_SIZE - sizeof(errormsg) - count - written + 1, - " %d\n", atomic_read(&hash_cur_user->value)) - 1; + " %d\n", atomic_read(&hash_cur_user->value)) - 1; } } if (count + written == PAGE_SIZE - sizeof(errormsg) - 1) { From ebfdc6a0836db3f7e63022561278868f7792cea4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 31 Jan 2017 20:07:51 -0800 Subject: [PATCH 152/281] ANDROID: sdcardfs: Switch strcasecmp for internal call This moves our uses of strcasecmp over to an internal call so we can easily change implementations later if we so desire. Additionally, we leverage qstr's where appropriate to save time on comparisons. Change-Id: I32fdc4fd0cd3b7b735dcfd82f60a2516fd8272a5 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/derived_perm.c | 35 ++++++++++++++++++++------------- fs/sdcardfs/file.c | 2 +- fs/sdcardfs/inode.c | 24 ++++++++++++----------- fs/sdcardfs/lookup.c | 18 +++++++---------- fs/sdcardfs/packagelist.c | 40 ++++++++++++++++++++------------------ fs/sdcardfs/sdcardfs.h | 17 ++++++++++++++-- 6 files changed, 78 insertions(+), 58 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 6d585c1815f1..35101ed01ebf 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -51,11 +51,16 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, } /* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ -void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name) +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name) { struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); appid_t appid; + struct qstr q_Android = QSTR_LITERAL("Android"); + struct qstr q_data = QSTR_LITERAL("data"); + struct qstr q_obb = QSTR_LITERAL("obb"); + struct qstr q_media = QSTR_LITERAL("media"); + struct qstr q_cache = QSTR_LITERAL("cache"); /* By default, each inode inherits from its parent. * the properties are maintained on its private fields @@ -79,12 +84,12 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; - info->userid = simple_strtoul(name, NULL, 10); + info->userid = simple_strtoul(name->name, NULL, 10); set_top(info, &info->vfs_inode); break; case PERM_ROOT: /* Assume masked off by default. */ - if (!strcasecmp(name, "Android")) { + if (qstr_case_eq(name, &q_Android)) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID; info->under_android = true; @@ -92,17 +97,17 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co } break; case PERM_ANDROID: - if (!strcasecmp(name, "data")) { + if (qstr_case_eq(name, &q_data)) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_DATA; set_top(info, &info->vfs_inode); - } else if (!strcasecmp(name, "obb")) { + } else if (qstr_case_eq(name, &q_obb)) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_OBB; info->under_obb = true; set_top(info, &info->vfs_inode); /* Single OBB directory is always shared */ - } else if (!strcasecmp(name, "media")) { + } else if (qstr_case_eq(name, &q_media)) { /* App-specific directories inside; let anyone traverse */ info->perm = PERM_ANDROID_MEDIA; set_top(info, &info->vfs_inode); @@ -112,14 +117,14 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co case PERM_ANDROID_DATA: case PERM_ANDROID_MEDIA: info->perm = PERM_ANDROID_PACKAGE; - appid = get_appid(name); - if (appid != 0 && !is_excluded(name, parent_info->userid)) { + appid = get_appid(name->name); + if (appid != 0 && !is_excluded(name->name, parent_info->userid)) { info->d_uid = multiuser_get_uid(parent_info->userid, appid); } set_top(info, &info->vfs_inode); break; case PERM_ANDROID_PACKAGE: - if (!strcasecmp(name, "cache")) { + if (qstr_case_eq(name, &q_cache)) { info->perm = PERM_ANDROID_PACKAGE_CACHE; info->under_cache = true; } @@ -129,7 +134,7 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co void get_derived_permission(struct dentry *parent, struct dentry *dentry) { - get_derived_permission_new(parent, dentry, dentry->d_name.name); + get_derived_permission_new(parent, dentry, &dentry->d_name); } static appid_t get_type(const char *name) { @@ -353,9 +358,10 @@ int need_graft_path(struct dentry *dentry) struct dentry *parent = dget_parent(dentry); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct qstr obb = QSTR_LITERAL("obb"); if(parent_info->perm == PERM_ANDROID && - !strcasecmp(dentry->d_name.name, "obb")) { + qstr_case_eq(&dentry->d_name, &obb)) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ if(!(sbi->options.multiuser == false @@ -392,7 +398,7 @@ int is_obbpath_invalid(struct dentry *dent) } else { obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); if (d_unhashed(di->lower_path.dentry) || - strcasecmp(sbi->obbpath_s, obbpath_s)) { + !str_case_eq(sbi->obbpath_s, obbpath_s)) { ret = 1; } kfree(path_buf); @@ -412,15 +418,16 @@ int is_base_obbpath(struct dentry *dentry) struct dentry *parent = dget_parent(dentry); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct qstr q_obb = QSTR_LITERAL("obb"); spin_lock(&SDCARDFS_D(dentry)->lock); if (sbi->options.multiuser) { if(parent_info->perm == PERM_PRE_ROOT && - !strcasecmp(dentry->d_name.name, "obb")) { + qstr_case_eq(&dentry->d_name, &q_obb)) { ret = 1; } } else if (parent_info->perm == PERM_ANDROID && - !strcasecmp(dentry->d_name.name, "obb")) { + qstr_case_eq(&dentry->d_name, &q_obb)) { ret = 1; } spin_unlock(&SDCARDFS_D(dentry)->lock); diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 71d8af2d6e6d..a9c82b7eadad 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -216,7 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 8311b3e53163..9ec16b8e4487 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -66,7 +66,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct fs_struct *saved_fs; struct fs_struct *copied_fs; - if(!check_caller_access_to_name(dir, dentry->d_name.name)) { + if(!check_caller_access_to_name(dir, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -168,7 +168,7 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) struct path lower_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(dir, dentry->d_name.name)) { + if(!check_caller_access_to_name(dir, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -275,8 +275,10 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode int touch_err = 0; struct fs_struct *saved_fs; struct fs_struct *copied_fs; + struct qstr q_obb = QSTR_LITERAL("obb"); + struct qstr q_data = QSTR_LITERAL("data"); - if(!check_caller_access_to_name(dir, dentry->d_name.name)) { + if(!check_caller_access_to_name(dir, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -351,13 +353,13 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); fixup_lower_ownership(dentry, dentry->d_name.name); unlock_dir(lower_parent_dentry); - if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) + if ((!sbi->options.multiuser) && (qstr_case_eq(&dentry->d_name, &q_obb)) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || - ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { + ((pi->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_data)))) { REVERT_CRED(saved_cred); OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dentry->d_inode)); set_fs_pwd(current->fs, &lower_path); @@ -388,7 +390,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) struct path lower_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(dir, dentry->d_name.name)) { + if(!check_caller_access_to_name(dir, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -476,8 +478,8 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct path lower_old_path, lower_new_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) || - !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) { + if(!check_caller_access_to_name(old_dir, &old_dentry->d_name) || + !check_caller_access_to_name(new_dir, &new_dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " new_dentry: %s, task:%s\n", __func__, new_dentry->d_name.name, current->comm); @@ -522,7 +524,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } - get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry->d_name.name); + get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name); fixup_tmp_permissions(old_dentry->d_inode); fixup_lower_ownership(old_dentry, new_dentry->d_name.name); drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */ @@ -755,7 +757,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct if (!err) { /* check the Android group ID */ parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); @@ -873,7 +875,7 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, int err; parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 165da604cf14..3a2558b7463b 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -219,9 +219,8 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; - const char *name; + const struct qstr *name; struct path lower_path; - struct qstr this; struct sdcardfs_sb_info *sbi; sbi = SDCARDFS_SB(dentry->d_sb); @@ -231,14 +230,14 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, if (IS_ROOT(dentry)) goto out; - name = dentry->d_name.name; + name = &dentry->d_name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ - err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, + err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name->name, 0, &lower_path); /* check for other cases */ if (err == -ENOENT) { @@ -248,7 +247,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, spin_lock(&lower_dir_dentry->d_lock); list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) { if (child && child->d_inode) { - if (strcasecmp(child->d_name.name, name)==0) { + if (qstr_case_eq(&child->d_name, name)) { match = dget(child); break; } @@ -307,14 +306,11 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, goto out; /* instatiate a new negative dentry */ - this.name = name; - this.len = strlen(name); - this.hash = full_name_hash(this.name, this.len); - lower_dentry = d_lookup(lower_dir_dentry, &this); + lower_dentry = d_lookup(lower_dir_dentry, name); if (lower_dentry) goto setup_lower; - lower_dentry = d_alloc(lower_dir_dentry, &this); + lower_dentry = d_alloc(lower_dir_dentry, name); if (!lower_dentry) { err = -ENOMEM; goto out; @@ -359,7 +355,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { ret = ERR_PTR(-EACCES); printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index dc5dc4a4b362..221ad11cb516 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -65,7 +65,7 @@ static appid_t __get_appid(const struct qstr *key) rcu_read_lock(); hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) { + if (qstr_case_eq(key, &hash_cur->key)) { ret_id = atomic_read(&hash_cur->value); rcu_read_unlock(); return ret_id; @@ -90,7 +90,7 @@ static appid_t __get_ext_gid(const struct qstr *key) rcu_read_lock(); hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) { + if (qstr_case_eq(key, &hash_cur->key)) { ret_id = atomic_read(&hash_cur->value); rcu_read_unlock(); return ret_id; @@ -115,7 +115,7 @@ static appid_t __is_excluded(const struct qstr *app_name, userid_t user) rcu_read_lock(); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { if (atomic_read(&hash_cur->value) == user && - !strcasecmp(app_name->name, hash_cur->key.name)) { + qstr_case_eq(app_name, &hash_cur->key)) { rcu_read_unlock(); return 1; } @@ -124,24 +124,26 @@ static appid_t __is_excluded(const struct qstr *app_name, userid_t user) return 0; } -appid_t is_excluded(const char *app_name, userid_t user) +appid_t is_excluded(const char *key, userid_t user) { struct qstr q; - qstr_init(&q, app_name); + qstr_init(&q, key); return __is_excluded(&q, user); } - /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access * even further, such as enforcing that apps hold sdcard_rw. */ -int check_caller_access_to_name(struct inode *parent_node, const char* name) { +int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name) { + struct qstr q_autorun = QSTR_LITERAL("autorun.inf"); + struct qstr q__android_secure = QSTR_LITERAL(".android_secure"); + struct qstr q_android_secure = QSTR_LITERAL("android_secure"); /* Always block security-sensitive files at root */ if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { - if (!strcasecmp(name, "autorun.inf") - || !strcasecmp(name, ".android_secure") - || !strcasecmp(name, "android_secure")) { + if (qstr_case_eq(name, &q_autorun) + || qstr_case_eq(name, &q__android_secure) + || qstr_case_eq(name, &q_android_secure)) { return 0; } } @@ -193,7 +195,7 @@ static int insert_packagelist_appid_entry_locked(const struct qstr *key, appid_t unsigned int hash = key->hash; hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) { + if (qstr_case_eq(key, &hash_cur->key)) { atomic_set(&hash_cur->value, value); return 0; } @@ -213,7 +215,7 @@ static int insert_ext_gid_entry_locked(const struct qstr *key, appid_t value) /* An extension can only belong to one gid */ hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) + if (qstr_case_eq(key, &hash_cur->key)) return -EINVAL; } new_entry = alloc_hashtable_entry(key, value); @@ -232,7 +234,7 @@ static int insert_userid_exclude_entry_locked(const struct qstr *key, userid_t v /* Only insert if not already present */ hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { if (atomic_read(&hash_cur->value) == value && - !strcasecmp(key->name, hash_cur->key.name)) + qstr_case_eq(key, &hash_cur->key)) return 0; } new_entry = alloc_hashtable_entry(key, value); @@ -336,13 +338,13 @@ static void remove_packagelist_entry_locked(const struct qstr *key) HLIST_HEAD(free_list); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) { + if (qstr_case_eq(key, &hash_cur->key)) { hash_del_rcu(&hash_cur->hlist); hlist_add_head(&hash_cur->dlist, &free_list); } } hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name)) { + if (qstr_case_eq(key, &hash_cur->key)) { hash_del_rcu(&hash_cur->hlist); hlist_add_head(&hash_cur->dlist, &free_list); break; @@ -368,7 +370,7 @@ static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) unsigned int hash = key->hash; hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name) && atomic_read(&hash_cur->value) == group) { + if (qstr_case_eq(key, &hash_cur->key) && atomic_read(&hash_cur->value) == group) { hash_del_rcu(&hash_cur->hlist); synchronize_rcu(); free_hashtable_entry(hash_cur); @@ -419,7 +421,7 @@ static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t unsigned int hash = key->hash; hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(key->name, hash_cur->key.name) && + if (qstr_case_eq(key, &hash_cur->key) && atomic_read(&hash_cur->value) == userid) { hash_del_rcu(&hash_cur->hlist); synchronize_rcu(); @@ -508,7 +510,7 @@ static ssize_t package_details_excluded_userids_show(struct package_details *pac rcu_read_lock(); hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { - if (!strcasecmp(package_details->name.name, hash_cur->key.name)) + if (qstr_case_eq(&package_details->name, &hash_cur->key)) count += scnprintf(page + count, PAGE_SIZE - count, "%d ", atomic_read(&hash_cur->value)); } @@ -758,7 +760,7 @@ static ssize_t packages_list_show(struct packages *packages, hash_cur_app->key.name, atomic_read(&hash_cur_app->value)); hash = hash_cur_app->key.hash; hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) { - if (!strcasecmp(hash_cur_app->key.name, hash_cur_user->key.name)) { + if (qstr_case_eq(&hash_cur_app->key, &hash_cur_user->key)) { written += scnprintf(page + count + written - 1, PAGE_SIZE - sizeof(errormsg) - count - written + 1, " %d\n", atomic_read(&hash_cur_user->value)) - 1; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index c0b554e7c9d0..71d6ff5d4565 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -459,7 +459,7 @@ extern struct list_head sdcardfs_super_list; extern appid_t get_appid(const char *app_name); extern appid_t get_ext_gid(const char *app_name); extern appid_t is_excluded(const char *app_name, userid_t userid); -extern int check_caller_access_to_name(struct inode *parent_node, const char* name); +extern int check_caller_access_to_name(struct inode *parent_node, const struct qstr* name); extern int open_flags_to_access_mode(int open_flags); extern int packagelist_init(void); extern void packagelist_exit(void); @@ -477,7 +477,7 @@ struct limit_search { extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); -extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const char *name); +extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name); extern void drop_recursive(struct dentry *parent); extern void fixup_top_recursive(struct dentry *parent); extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); @@ -606,4 +606,17 @@ static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct dest->i_flags = src->i_flags; set_nlink(dest, src->i_nlink); } + +static inline bool str_case_eq(const char *s1, const char *s2) +{ + return !strcasecmp(s1, s2); +} + +static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) +{ + return q1->len == q2->len && str_case_eq(q1->name, q2->name); +} + +#define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) + #endif /* not _SDCARDFS_H_ */ From 915394464d84cc33a06a6af5e9eb955876a9ec37 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 16 Feb 2017 17:55:22 -0800 Subject: [PATCH 153/281] ANDROID: sdcardfs: Add missing path_put "ANDROID: sdcardfs: Add GID Derivation to sdcardfs" introduced an unbalanced pat_get, leading to storage space not being freed after deleting a file until rebooting. This adds the missing path_put. Signed-off-by: Daniel Rosenberg Bug: 34691169 Change-Id: Ia7ef97ec2eca2c555cc06b235715635afc87940e --- fs/sdcardfs/derived_perm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 35101ed01ebf..5ad69e6f6c33 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -236,6 +236,7 @@ void fixup_lower_ownership(struct dentry* dentry, const char *name) { if (error) pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n"); } + sdcardfs_put_lower_path(dentry, &path); } static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) { From 829ea28cc11d8460593a62ad4dfe7a696588f384 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 22 Feb 2017 14:41:58 -0800 Subject: [PATCH 154/281] ANDROID: sdcardfs: Don't bother deleting freelist There is no point deleting entries from dlist, as that is a temporary list on the stack from which contains only entries that are being deleted. Not all code paths set up dlist, so those that don't were performing invalid accesses in hash_del_rcu. As an additional means to prevent any other issue, we null out the list entries when we allocate from the cache. Signed-off-by: Daniel Rosenberg Bug: 35666680 Change-Id: Ibb1e28c08c3a600c29418d39ba1c0f3db3bf31e5 --- fs/sdcardfs/packagelist.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 221ad11cb516..21eb2d317e44 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -178,6 +178,8 @@ static struct hashtable_entry *alloc_hashtable_entry(const struct qstr *key, GFP_KERNEL); if (!ret) return NULL; + INIT_HLIST_NODE(&ret->dlist); + INIT_HLIST_NODE(&ret->hlist); if (!qstr_copy(key, &ret->key)) { kmem_cache_free(hashtable_entry_cachep, ret); @@ -326,7 +328,6 @@ static int insert_userid_exclude_entry(const struct qstr *key, userid_t value) static void free_hashtable_entry(struct hashtable_entry *entry) { kfree(entry->key.name); - hash_del_rcu(&entry->dlist); kmem_cache_free(hashtable_entry_cachep, entry); } From 60cc3cdce13fc5becfdad5cdd0edc7d9bf6a42bc Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Thu, 24 Nov 2016 13:23:10 +0000 Subject: [PATCH 155/281] mpi: Fix NULL ptr dereference in mpi_powm() [ver #3] commit f5527fffff3f002b0a6b376163613b82f69de073 upstream. This fixes CVE-2016-8650. If mpi_powm() is given a zero exponent, it wants to immediately return either 1 or 0, depending on the modulus. However, if the result was initalised with zero limb space, no limbs space is allocated and a NULL-pointer exception ensues. Fix this by allocating a minimal amount of limb space for the result when the 0-exponent case when the result is 1 and not touching the limb space when the result is 0. This affects the use of RSA keys and X.509 certificates that carry them. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] mpi_powm+0x32/0x7e6 PGD 0 Oops: 0002 [#1] SMP Modules linked in: CPU: 3 PID: 3014 Comm: keyctl Not tainted 4.9.0-rc6-fscache+ #278 Hardware name: ASUS All Series/H97-PLUS, BIOS 2306 10/09/2014 task: ffff8804011944c0 task.stack: ffff880401294000 RIP: 0010:[] [] mpi_powm+0x32/0x7e6 RSP: 0018:ffff880401297ad8 EFLAGS: 00010212 RAX: 0000000000000000 RBX: ffff88040868bec0 RCX: ffff88040868bba0 RDX: ffff88040868b260 RSI: ffff88040868bec0 RDI: ffff88040868bee0 RBP: ffff880401297ba8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000047 R11: ffffffff8183b210 R12: 0000000000000000 R13: ffff8804087c7600 R14: 000000000000001f R15: ffff880401297c50 FS: 00007f7a7918c700(0000) GS:ffff88041fb80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000401250000 CR4: 00000000001406e0 Stack: ffff88040868bec0 0000000000000020 ffff880401297b00 ffffffff81376cd4 0000000000000100 ffff880401297b10 ffffffff81376d12 ffff880401297b30 ffffffff81376f37 0000000000000100 0000000000000000 ffff880401297ba8 Call Trace: [] ? __sg_page_iter_next+0x43/0x66 [] ? sg_miter_get_next_page+0x1b/0x5d [] ? sg_miter_next+0x17/0xbd [] ? mpi_read_raw_from_sgl+0xf2/0x146 [] rsa_verify+0x9d/0xee [] ? pkcs1pad_sg_set_buf+0x2e/0xbb [] pkcs1pad_verify+0xc0/0xe1 [] public_key_verify_signature+0x1b0/0x228 [] x509_check_for_self_signed+0xa1/0xc4 [] x509_cert_parse+0x167/0x1a1 [] x509_key_preparse+0x21/0x1a1 [] asymmetric_key_preparse+0x34/0x61 [] key_create_or_update+0x145/0x399 [] SyS_add_key+0x154/0x19e [] do_syscall_64+0x80/0x191 [] entry_SYSCALL64_slow_path+0x25/0x25 Code: 56 41 55 41 54 53 48 81 ec a8 00 00 00 44 8b 71 04 8b 42 04 4c 8b 67 18 45 85 f6 89 45 80 0f 84 b4 06 00 00 85 c0 75 2f 41 ff ce <49> c7 04 24 01 00 00 00 b0 01 75 0b 48 8b 41 18 48 83 38 01 0f RIP [] mpi_powm+0x32/0x7e6 RSP CR2: 0000000000000000 ---[ end trace d82015255d4a5d8d ]--- Basically, this is a backport of a libgcrypt patch: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=patch;h=6e1adb05d290aeeb1c230c763970695f4a538526 Fixes: cdec9cb5167a ("crypto: GnuPG based MPI lib - source files (part 1)") Change-Id: I8d4e66b98449a975559865bd76905b8df51c8ca2 Signed-off-by: Andrey Ryabinin Signed-off-by: David Howells cc: Dmitry Kasatkin cc: linux-ima-devel@lists.sourceforge.net Signed-off-by: James Morris Signed-off-by: Jiri Slaby --- lib/mpi/mpi-pow.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c index 5464c8744ea9..e24388a863a7 100644 --- a/lib/mpi/mpi-pow.c +++ b/lib/mpi/mpi-pow.c @@ -64,8 +64,13 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) if (!esize) { /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 * depending on if MOD equals 1. */ - rp[0] = 1; res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; + if (res->nlimbs) { + if (mpi_resize(res, 1) < 0) + goto enomem; + rp = res->d; + rp[0] = 1; + } res->sign = 0; goto leave; } From d37d3fa550cdbd9569afe04cb2966fd4cefe63b8 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Mon, 28 Nov 2016 12:56:40 +0200 Subject: [PATCH 156/281] net/sched: pedit: make sure that offset is valid [ Upstream commit 95c2027bfeda21a28eb245121e6a249f38d0788e ] Add a validation function to make sure offset is valid: 1. Not below skb head (could happen when offset is negative). 2. Validate both 'offset' and 'at'. Change-Id: I804db37119972feee0d6b9c492d85d460f03a511 Signed-off-by: Amir Vadai Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby --- net/sched/act_pedit.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 7ed78c9e505c..3f385130e9c0 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -124,6 +124,17 @@ static int tcf_pedit_cleanup(struct tc_action *a, int bind) return 0; } +static bool offset_valid(struct sk_buff *skb, int offset) +{ + if (offset > 0 && offset > skb->len) + return false; + + if (offset < 0 && -offset > skb_headroom(skb)) + return false; + + return true; +} + static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { @@ -150,6 +161,11 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, if (tkey->offmask) { char *d, _d; + if (!offset_valid(skb, off + tkey->at)) { + pr_info("tc filter pedit 'at' offset %d out of bounds\n", + off + tkey->at); + goto bad; + } d = skb_header_pointer(skb, off + tkey->at, 1, &_d); if (!d) @@ -162,10 +178,10 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, " offset must be on 32 bit boundaries\n"); goto bad; } - if (offset > 0 && offset > skb->len) { - pr_info("tc filter pedit" - " offset %d can't exceed pkt length %d\n", - offset, skb->len); + + if (!offset_valid(skb, off + offset)) { + pr_info("tc filter pedit offset %d out of bounds\n", + offset); goto bad; } From 8566e21894c7d89c0e383173b7abc967ee634fb5 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 8 Feb 2017 10:28:24 +1100 Subject: [PATCH 157/281] ipc/shm: Fix shmat mmap nil-page protection The issue is described here, with a nice testcase: https://bugzilla.kernel.org/show_bug.cgi?id=192931 The problem is that shmat() calls do_mmap_pgoff() with MAP_FIXED, and the address rounded down to 0. For the regular mmap case, the protection mentioned above is that the kernel gets to generate the address -- arch_get_unmapped_area() will always check for MAP_FIXED and return that address. So by the time we do security_mmap_addr(0) things get funky for shmat(). The testcase itself shows that while a regular user crashes, root will not have a problem attaching a nil-page. There are two possible fixes to this. The first, and which this patch does, is to simply allow root to crash as well -- this is also regular mmap behavior, ie when hacking up the testcase and adding mmap(... |MAP_FIXED). While this approach is the safer option, the second alternative is to ignore SHM_RND if the rounded address is 0, thus only having MAP_SHARED flags. This makes the behavior of shmat() identical to the mmap() case. The downside of this is obviously user visible, but does make sense in that it maintains semantics after the round-down wrt 0 address and mmap. Passes shm related ltp tests. Change-Id: I47b065f965427409642892fb139d89fb5603b187 Link: http://lkml.kernel.org/r/1486050195-18629-1-git-send-email-dave@stgolabs.net Signed-off-by: Davidlohr Bueso Reported-by: Gareth Evans Cc: Manfred Spraul Cc: Michael Kerrisk Signed-off-by: Andrew Morton --- ipc/shm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index 6dc55af8a29b..ec4a4369b750 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1041,8 +1041,8 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) * "raddr" thing points to kernel space, and there has to be a wrapper around * this. */ -long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, - unsigned long shmlba) +long do_shmat(int shmid, char __user *shmaddr, int shmflg, + ulong *raddr, unsigned long shmlba) { struct shmid_kernel *shp; unsigned long addr; @@ -1063,8 +1063,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, goto out; else if ((addr = (ulong)shmaddr)) { if (addr & (shmlba - 1)) { - if (shmflg & SHM_RND) - addr &= ~(shmlba - 1); /* round down */ + /* + * Round down to the nearest multiple of shmlba. + * For sane do_mmap_pgoff() parameters, avoid + * round downs that trigger nil-page and MAP_FIXED. + */ + if ((shmflg & SHM_RND) && addr >= shmlba) + addr &= ~(shmlba - 1); else #ifndef __ARCH_FORCE_SHMLBA if (addr & ~PAGE_MASK) From 87d533b10a4058e9a056a0fb4bd1f0e2df3bf1f8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 3 Feb 2017 14:59:38 -0800 Subject: [PATCH 158/281] tcp: avoid infinite loop in tcp_splice_read() Splicing from TCP socket is vulnerable when a packet with URG flag is received and stored into receive queue. __tcp_splice_read() returns 0, and sk_wait_data() immediately returns since there is the problematic skb in queue. This is a nice way to burn cpu (aka infinite loop) and trigger soft lockups. Again, this gem was found by syzkaller tool. Change-Id: I2580dc9def1dc663d0f55012108285e0dc5db925 Fixes: 9c55e01c0cc8 ("[TCP]: Splice receive support.") Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Cc: Willy Tarreau Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 361bdb16b964..65dce7bac596 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -734,6 +734,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, ret = -EAGAIN; break; } + /* if __tcp_splice_read() got nothing while we have + * an skb in receive queue, we do not want to loop. + * This might happen with URG data. + */ + if (!skb_queue_empty(&sk->sk_receive_queue)) + break; sk_wait_data(sk, &timeo); if (signal_pending(current)) { ret = sock_intr_errno(timeo); From cacbf5d594e0c8a0a5be3b83b98be12aa8d94bd3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 24 Feb 2017 15:41:48 -0800 Subject: [PATCH 159/281] ANDROID: sdcardfs: implement vm_ops->page_mkwrite This comes from the wrapfs patch 3dfec0ffe5e2 Wrapfs: implement vm_ops->page_mkwrite Some file systems (e.g., ext4) require it. Reported by Ted Ts'o. Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 34133558 Change-Id: I1a389b2422c654a6d3046bb8ec3e20511aebfa8e --- fs/sdcardfs/mmap.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c index c807d7f18f8b..dd02a11f8545 100755 --- a/fs/sdcardfs/mmap.c +++ b/fs/sdcardfs/mmap.c @@ -48,6 +48,39 @@ static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return err; } +static int sdcardfs_page_mkwrite(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + int err = 0; + struct file *file, *lower_file; + const struct vm_operations_struct *lower_vm_ops; + struct vm_area_struct lower_vma; + + memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); + file = lower_vma.vm_file; + lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; + BUG_ON(!lower_vm_ops); + if (!lower_vm_ops->page_mkwrite) + goto out; + + lower_file = sdcardfs_lower_file(file); + /* + * XXX: vm_ops->page_mkwrite may be called in parallel. + * Because we have to resort to temporarily changing the + * vma->vm_file to point to the lower file, a concurrent + * invocation of sdcardfs_page_mkwrite could see a different + * value. In this workaround, we keep a different copy of the + * vma structure in our stack, so we never expose a different + * value of the vma->vm_file called to us, even temporarily. + * A better fix would be to change the calling semantics of + * ->page_mkwrite to take an explicit file pointer. + */ + lower_vma.vm_file = lower_file; + err = lower_vm_ops->page_mkwrite(&lower_vma, vmf); +out: + return err; +} + static ssize_t sdcardfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) @@ -79,4 +112,5 @@ const struct address_space_operations sdcardfs_aops = { const struct vm_operations_struct sdcardfs_vm_ops = { .fault = sdcardfs_fault, + .page_mkwrite = sdcardfs_page_mkwrite, }; From 72f6cfb10a5d67ce953bccea3f892e204cff3b7c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 24 Feb 2017 15:49:45 -0800 Subject: [PATCH 160/281] ANDROID: sdcardfs: support direct-IO (DIO) operations This comes from the wrapfs patch 2e346c83b26e Wrapfs: support direct-IO (DIO) operations Signed-off-by: Li Mengyang Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 34133558 Change-Id: I3fd779c510ab70d56b1d918f99c20421b524cdc4 --- fs/sdcardfs/mmap.c | 21 ++++----------------- fs/sdcardfs/sdcardfs.h | 1 + 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c index dd02a11f8545..9ec452391072 100755 --- a/fs/sdcardfs/mmap.c +++ b/fs/sdcardfs/mmap.c @@ -86,27 +86,14 @@ static ssize_t sdcardfs_direct_IO(int rw, struct kiocb *iocb, unsigned long nr_segs) { /* - * This function returns zero on purpose in order to support direct IO. - * __dentry_open checks a_ops->direct_IO and returns EINVAL if it is null. - * - * However, this function won't be called by certain file operations - * including generic fs functions. * reads and writes are delivered to - * the lower file systems and the direct IOs will be handled by them. - * - * NOTE: exceptionally, on the recent kernels (since Linux 3.8.x), - * swap_writepage invokes this function directly. + * This function should never be called directly. We need it + * to exist, to get past a check in open_check_o_direct(), + * which is called from do_last(). */ - printk(KERN_INFO "%s, operation is not supported\n", __func__); - return 0; + return -EINVAL; } -/* - * XXX: the default address_space_ops for sdcardfs is empty. We cannot set - * our inode->i_mapping->a_ops to NULL because too many code paths expect - * the a_ops vector to be non-NULL. - */ const struct address_space_operations sdcardfs_aops = { - /* empty on purpose */ .direct_IO = sdcardfs_direct_IO, }; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 71d6ff5d4565..fe121e81a24d 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include From 19dd0ad2971781fdea2f2320c0dfbc58ef6bfeb3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 11 Jan 2017 21:09:50 +0100 Subject: [PATCH 161/281] perf/core: Fix concurrent sys_perf_event_open() vs. 'move_group' race commit 321027c1fe77f892f4ea07846aeae08cefbbb290 upstream. Di Shen reported a race between two concurrent sys_perf_event_open() calls where both try and move the same pre-existing software group into a hardware context. The problem is exactly that described in commit: f63a8daa5812 ("perf: Fix event->ctx locking") ... where, while we wait for a ctx->mutex acquisition, the event->ctx relation can have changed under us. That very same commit failed to recognise sys_perf_event_context() as an external access vector to the events and thereby didn't apply the established locking rules correctly. So while one sys_perf_event_open() call is stuck waiting on mutex_lock_double(), the other (which owns said locks) moves the group about. So by the time the former sys_perf_event_open() acquires the locks, the context we've acquired is stale (and possibly dead). Apply the established locking rules as per perf_event_ctx_lock_nested() to the mutex_lock_double() for the 'move_group' case. This obviously means we need to validate state after we acquire the locks. Change-Id: Ia490bc004a059995162beff246210082bc941766 Reported-by: Di Shen (Keen Lab) Tested-by: John Dias Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kees Cook Cc: Linus Torvalds Cc: Min Chong Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: f63a8daa5812 ("perf: Fix event->ctx locking") Link: http://lkml.kernel.org/r/20170106131444.GZ3174@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar [bwh: Backported to 3.2: - Use ACCESS_ONCE() instead of READ_ONCE() - Test perf_event::group_flags instead of group_caps - Add the err_locked cleanup block, which we didn't need before - Adjust context] Signed-off-by: Ben Hutchings --- kernel/events/core.c | 61 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 94d4e09bced6..677f7b5478f0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6842,6 +6842,37 @@ static void mutex_lock_double(struct mutex *a, struct mutex *b) mutex_lock_nested(b, SINGLE_DEPTH_NESTING); } +/* + * Variation on perf_event_ctx_lock_nested(), except we take two context + * mutexes. + */ +static struct perf_event_context * +__perf_event_ctx_lock_double(struct perf_event *group_leader, + struct perf_event_context *ctx) +{ + struct perf_event_context *gctx; + +again: + rcu_read_lock(); + gctx = ACCESS_ONCE(group_leader->ctx); + if (!atomic_inc_not_zero(&gctx->refcount)) { + rcu_read_unlock(); + goto again; + } + rcu_read_unlock(); + + mutex_lock_double(&gctx->mutex, &ctx->mutex); + + if (group_leader->ctx != gctx) { + mutex_unlock(&ctx->mutex); + mutex_unlock(&gctx->mutex); + put_ctx(gctx); + goto again; + } + + return gctx; +} + /** * sys_perf_event_open - open a performance event, associate it to a task/cpu * @@ -7044,14 +7075,31 @@ SYSCALL_DEFINE5(perf_event_open, } if (move_group) { - gctx = group_leader->ctx; + gctx = __perf_event_ctx_lock_double(group_leader, ctx); + + /* + * Check if we raced against another sys_perf_event_open() call + * moving the software group underneath us. + */ + if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) { + /* + * If someone moved the group out from under us, check + * if this new event wound up on the same ctx, if so + * its the regular !move_group case, otherwise fail. + */ + if (gctx != ctx) { + err = -EINVAL; + goto err_locked; + } else { + perf_event_ctx_unlock(group_leader, gctx); + move_group = 0; + } + } /* * See perf_event_ctx_lock() for comments on the details * of swizzling perf_event::ctx. */ - mutex_lock_double(&gctx->mutex, &ctx->mutex); - perf_remove_from_context(group_leader, false); /* @@ -7093,7 +7141,7 @@ SYSCALL_DEFINE5(perf_event_open, perf_unpin_context(ctx); if (move_group) { - mutex_unlock(&gctx->mutex); + perf_event_ctx_unlock(group_leader, gctx); put_ctx(gctx); } mutex_unlock(&ctx->mutex); @@ -7124,6 +7172,11 @@ SYSCALL_DEFINE5(perf_event_open, fd_install(event_fd, event_file); return event_fd; +err_locked: + if (move_group) + perf_event_ctx_unlock(group_leader, gctx); + mutex_unlock(&ctx->mutex); + fput(event_file); err_context: perf_unpin_context(ctx); put_ctx(ctx); From 1742c6b4de2d3ae115276c17877b6d159e938f19 Mon Sep 17 00:00:00 2001 From: Manjeet Singh Date: Tue, 27 Dec 2016 17:48:37 +0530 Subject: [PATCH 162/281] qcacld-2.0: Add buf len check in wlan_hdd_cfg80211_testmode In __wlan_hdd_cfg80211_testmode API no checks are in place that ensure that buflen is smaller or equal the size of the stack variable hb_params. Hence, the vos_mem_copy() call can overflow stack memory. Add buf len check to avoid stack overflow CRs-Fixed: 1105085 Change-Id: I6af6a74cc38ebce3337120adcf7e9595f22d3d8c --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 7fb4537d8f43..f8582e297c68 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -19280,6 +19280,12 @@ static int __wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, void *data, int len (hb_params_temp->params.lphbTcpParamReq.timePeriodSec == 0)) return -EINVAL; + if (buf_len > sizeof(*hb_params)) { + hddLog(LOGE, FL("buf_len=%d exceeded hb_params size limit"), + buf_len); + return -ERANGE; + } + hb_params = (tSirLPHBReq *)vos_mem_malloc(sizeof(tSirLPHBReq)); if (NULL == hb_params) { From 41a972b70231c0eafa2c025333ad6d361acdf206 Mon Sep 17 00:00:00 2001 From: Karthikeyan Ramasubramanian Date: Thu, 15 Dec 2016 08:13:20 -0700 Subject: [PATCH 163/281] net: ipc_router: Register services only on client port Allowing services to be registered on a non-client port will cause either an existing service or a control port to be over-written. This will cause undefined functional behavior. Allow the services to be registered only on client ports. CRs-Fixed: 1101792 Change-Id: If6cfc75e9314204b7b44957f1598a8a2e1a45325 Signed-off-by: Karthikeyan Ramasubramanian --- net/ipc_router/ipc_router_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index b63ad0fc87a0..af1919d6be19 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -2503,6 +2503,9 @@ int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr, if (!port_ptr || !name) return -EINVAL; + if (port_ptr->type != CLIENT_PORT) + return -EINVAL; + if (name->addrtype != MSM_IPC_ADDR_NAME) return -EINVAL; From c24be1ab9aa886d01d9dfcdb8a9d52fa62325d97 Mon Sep 17 00:00:00 2001 From: Krishnankutty Kolathappilly Date: Mon, 14 Nov 2016 18:46:12 -0800 Subject: [PATCH 164/281] msm: camera: fix bound check of offset to avoid overread overwrite fix bound check of hw_cmd_p->offset in msm_jpeg_hw_exec_cmds to avoid overread overwrite. CRs-Fixed: 1088824 Change-Id: Ifaa4b5387d4285ddce16d8e745aa0500c64c568b Signed-off-by: Krishnankutty Kolathappilly --- drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index d67ab1119d46..9bc37a022f8e 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -501,7 +501,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, uint32_t data; while (m_cmds--) { - if (hw_cmd_p->offset > max_size) { + if (hw_cmd_p->offset >= max_size) { JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, __LINE__, hw_cmd_p->offset, max_size); return -EFAULT; From 25b3df22a0f725770b45915e118bd70c5eea9a10 Mon Sep 17 00:00:00 2001 From: guyang Date: Tue, 6 Dec 2016 18:30:38 +0800 Subject: [PATCH 165/281] msm: camera: sensor: Validate eeprom_name string length Validate eeprom_name string length before copying into the userspace buffer. If more data than required is copied, userspace has the access to some of kernel data which is not intended. CRs-Fixed: 1090007 Change-Id: Id40a287e0b1a93cc15d9b02c757fe9f347e285f2 Signed-off-by: Rajesh Bondugula Signed-off-by: VijayaKumar T M Signed-off-by: Yang Guang --- .../platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c | 11 +++++++++-- include/media/msm_cam_sensor.h | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index d869951dbc0d..d85528385d34 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -136,15 +136,22 @@ static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, struct msm_eeprom_cfg_data *cdata = (struct msm_eeprom_cfg_data *)argp; int rc = 0; + size_t length = 0; CDBG("%s E\n", __func__); switch (cdata->cfgtype) { case CFG_EEPROM_GET_INFO: CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); cdata->is_supported = e_ctrl->is_supported; + length = strlen(e_ctrl->eboard_info->eeprom_name) + 1; + if (length > MAX_EEPROM_NAME) { + pr_err("%s:%d invalid eeprom_name length %d\n", + __func__,__LINE__, (int)length); + rc = -EINVAL; + break; + } memcpy(cdata->cfg.eeprom_name, - e_ctrl->eboard_info->eeprom_name, - sizeof(cdata->cfg.eeprom_name)); + e_ctrl->eboard_info->eeprom_name, length); break; case CFG_EEPROM_GET_CAL_DATA: CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 50c0d51526ed..0d3c6db010ae 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -299,7 +299,7 @@ struct msm_eeprom_cfg_data { enum eeprom_cfg_type_t cfgtype; uint8_t is_supported; union { - char eeprom_name[MAX_SENSOR_NAME]; + char eeprom_name[MAX_EEPROM_NAME]; struct eeprom_get_t get_data; struct eeprom_read_t read_data; struct eeprom_write_t write_data; From 59699069986407fc8b6a83aa205c4f0b0e952dff Mon Sep 17 00:00:00 2001 From: Sanjay Singh Date: Mon, 28 Nov 2016 16:57:13 +0530 Subject: [PATCH 166/281] msm: vidc: WARN_ON() reveals fuction addresses There is a security vulnerability where function addresses are printed in kernel message if WARN_ON() is invoked implicitly. WARN_ON() call is made explicit to avoid this issue. Change-Id: If75581803adf62cb9bda3784ad1d4f4088e0d797 Signed-off-by: Sanjay Singh --- drivers/media/platform/msm/vidc/msm_vidc.c | 3 ++- drivers/media/platform/msm/vidc/venus_hfi.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 1c7f46954362..678ed4492fc6 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1408,7 +1408,8 @@ static void cleanup_instance(struct msm_vidc_inst *inst) debugfs_remove_recursive(inst->debugfs_root); mutex_lock(&inst->pending_getpropq.lock); - WARN_ON(!list_empty(&inst->pending_getpropq.list)); + WARN_ON(!list_empty(&inst->pending_getpropq.list) + && (msm_vidc_debug & VIDC_INFO)); mutex_unlock(&inst->pending_getpropq.lock); } } diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index b8485d9be5d0..e798a1320025 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -273,7 +273,7 @@ static int venus_hfi_acquire_regulator(struct regulator_info *rinfo) rinfo->name); } } - WARN_ON(!regulator_is_enabled(rinfo->regulator)); + WARN_ON(!regulator_is_enabled(rinfo->regulator) && (msm_vidc_debug & VIDC_INFO)); return rc; } @@ -3905,7 +3905,7 @@ static int venus_hfi_disable_regulator(struct regulator_info *rinfo) disable_regulator_failed: /* Bring attention to this issue */ - WARN_ON(1); + WARN_ON(msm_vidc_debug & VIDC_INFO); return rc; } From 450bd87cb590b475b56ae4c5a0d5ace311311cb5 Mon Sep 17 00:00:00 2001 From: Dennis Cagle Date: Thu, 5 Jan 2017 17:22:13 -0800 Subject: [PATCH 167/281] input: misc: fix heap overflow issue in hbtp_input.c Add the boundary check for ABS code before setting ABS params, to avoid heap overflow. Bug: 32341680 CRs-fixed: 1096301 Change-Id: I6aad9916c92d2f775632406374dbb803063148de Signed-off-by: Vevek Venkatesan Signed-off-by: Dennis Cagle --- drivers/input/misc/hbtp_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c index 0fc14022ddfe..166c74199650 100644 --- a/drivers/input/misc/hbtp_input.c +++ b/drivers/input/misc/hbtp_input.c @@ -129,9 +129,13 @@ static int hbtp_input_create_input_dev(struct hbtp_input_absinfo *absinfo) input_mt_init_slots(input_dev, HBTP_MAX_FINGER, 0); for (i = 0; i <= ABS_MT_LAST - ABS_MT_FIRST; i++) { abs = absinfo + i; - if (abs->active) - input_set_abs_params(input_dev, abs->code, + if (abs->active) { + if (abs->code >= 0 && abs->code < ABS_CNT) + input_set_abs_params(input_dev, abs->code, abs->minimum, abs->maximum, 0, 0); + else + pr_err("%s: ABS code out of bound\n", __func__); + } } error = input_register_device(input_dev); From a3950552f01fc21ab89c772200b7baa414ccbe67 Mon Sep 17 00:00:00 2001 From: Ariel Yin Date: Fri, 13 Jan 2017 15:05:54 -0800 Subject: [PATCH 168/281] ANDROID: ion: check for kref overflow Userspace can cause the kref to handles to increment arbitrarily high. Ensure it does not overflow. Signed-off-by: Daniel Rosenberg Bug: 31992382 Test: See bug for poc Change-Id: I6bff1df385742b1d836d43180dc87fadcea80782 --- drivers/staging/android/ion/ion.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 7ae0407237d7..6c9fb99f9fa9 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -16,6 +16,8 @@ * */ +#include +#include #include #include #include @@ -406,6 +408,15 @@ static void ion_handle_get(struct ion_handle *handle) kref_get(&handle->ref); } +/* Must hold the client lock */ +static struct ion_handle* ion_handle_get_check_overflow(struct ion_handle *handle) +{ + if (atomic_read(&handle->ref.refcount) + 1 == 0) + return ERR_PTR(-EOVERFLOW); + ion_handle_get(handle); + return handle; +} + static int ion_handle_put_nolock(struct ion_handle *handle) { int ret; @@ -451,9 +462,9 @@ static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, handle = idr_find(&client->idr, id); if (handle) - ion_handle_get(handle); + return ion_handle_get_check_overflow(handle); - return handle ? handle : ERR_PTR(-EINVAL); + return ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id(struct ion_client *client, @@ -1369,7 +1380,7 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) /* if a handle exists for this buffer just take a reference to it */ handle = ion_handle_lookup(client, buffer); if (!IS_ERR(handle)) { - ion_handle_get(handle); + handle = ion_handle_get_check_overflow(handle); mutex_unlock(&client->lock); goto end; } From bdbf9de2299f996349519e564952551dc34a52fc Mon Sep 17 00:00:00 2001 From: Ariel Yin Date: Tue, 17 Jan 2017 17:04:09 -0800 Subject: [PATCH 169/281] msm: cpp: Fix for integer overflow in cpp Due to integer overflow, the bound check in config frame function may pass and this may allow user to access invalid buffer. This fix takes care of proper bound and don't allow integer overflow. Bug: 32919951 CRs-Fixed: 1097709 Change-Id: I504ad591633afaba82268b5ee27a321691d75c80 Signed-off-by: Kumar Behera Signed-off-by: Biswajit Paul --- drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index ed401c50cb46..9a986f07dac9 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1579,7 +1579,7 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, unsigned long tnr_scratch_buffer0, tnr_scratch_buffer1; uint16_t num_stripes = 0; struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info; - int32_t stripe_base = 0; + uint32_t stripe_base = 0; int32_t in_fd; int32_t i = 0; @@ -1601,6 +1601,13 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, return -EINVAL; } + if (stripe_base == UINT_MAX || new_frame->num_strips > + (UINT_MAX - 1 - stripe_base) / 27) { + pr_err("Invalid frame message,num_strips %d is large\n", + new_frame->num_strips); + return -EINVAL; + } + in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, &new_frame->input_buffer_info, ((new_frame->input_buffer_info.identity >> 16) & 0xFFFF), From a566ff65160ae7a38a7e3f11c50b2ff0f02d0368 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 12 Jan 2017 22:09:16 -0700 Subject: [PATCH 170/281] net: rmnet_data: Fix incorrect netlink handling rmnet_data netlink handler currently does not check for the incoming process pid and instead just loops back the pid. A malicious root user could potentially send a message with source pid 0 and this could cause rmnet_data to loop the message back till an out of memory situation occurs. rmnet_data also does not check for the message length of the incoming netlink messages and instead casts the netlink message without checking for the boundary. Fix these two scenarios by adding the pid and message length checks respectively. Bug: 31252965 CRs-Fixed: 1098801 Change-Id: I172c1a7112e67e82959b397af7ddfd963d819bdc Signed-off-by: Subash Abhinov Kasiviswanathan --- net/rmnet_data/rmnet_data_config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c index 2119d6199c33..f2776356fdae 100644 --- a/net/rmnet_data/rmnet_data_config.c +++ b/net/rmnet_data/rmnet_data_config.c @@ -531,6 +531,11 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) nlmsg_header = (struct nlmsghdr *) skb->data; rmnet_header = (struct rmnet_nl_msg_s *) nlmsg_data(nlmsg_header); + if (!nlmsg_header->nlmsg_pid || + (nlmsg_header->nlmsg_len < sizeof(struct nlmsghdr) + + sizeof(struct rmnet_nl_msg_s))) + return; + LOGL("Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d", nlmsg_header->nlmsg_pid, nlmsg_header->nlmsg_seq, From f561f6f1e43a51159eed567adb34d26424f0e8ef Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 31 Oct 2016 15:23:19 -0700 Subject: [PATCH 171/281] msm: crypto: fix issues on digest buf and copy_from_user in qcedev.c Make the digest length not larger than the size of the buffer qcedev_areq.sha_op_req.digest; and use the checked variants of the copy_from/to_user() APIs to avoid small race window of their unchecked variants. Bug: 31750232 Change-Id: I3db0c20ac5fa47ed278f3d60368c406f472430c1 Signed-off-by: Zhen Kong Signed-off-by: Wei Wang --- drivers/crypto/msm/qcedev.c | 120 ++++++++---------------------------- 1 file changed, 27 insertions(+), 93 deletions(-) diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 09914b971138..3767393a037b 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -616,7 +616,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, while (len > 0) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) return -EFAULT; @@ -652,7 +652,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, /* Copy data from user src(s) */ user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[0].len)) { kzfree(k_buf_src); @@ -661,7 +661,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq, k_src += qcedev_areq->sha_op_req.data[0].len; for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); @@ -715,13 +715,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq, return -EINVAL; } - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) { struct qcedev_sha_op_req *saved_req; @@ -886,19 +879,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, total = qcedev_areq->sha_op_req.data_len; - /* verify address src(s) */ - for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.data[i].vaddr, - qcedev_areq->sha_op_req.data[i].len)) - return -EFAULT; - - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)qcedev_areq->sha_op_req.authkey, - qcedev_areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)qcedev_areq->sha_op_req.authkey, qcedev_areq->sha_op_req.authklen)) return -EFAULT; @@ -918,7 +899,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq, for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) { user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr; - if (user_src && __copy_from_user(k_src, (void __user *)user_src, + if (user_src && copy_from_user(k_src, (void __user *)user_src, qcedev_areq->sha_op_req.data[i].len)) { kzfree(k_buf_src); return -EFAULT; @@ -946,12 +927,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq, if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) { qcedev_sha_init(areq, handle); - /* Verify Source Address */ - if (!access_ok(VERIFY_READ, - (void __user *)areq->sha_op_req.authkey, - areq->sha_op_req.authklen)) - return -EFAULT; - if (__copy_from_user(&handle->sha_ctxt.authkey[0], + if (copy_from_user(&handle->sha_ctxt.authkey[0], (void __user *)areq->sha_op_req.authkey, areq->sha_op_req.authklen)) return -EFAULT; @@ -1164,7 +1140,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, byteoffset = areq->cipher_op_req.byteoffset; user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr; - if (user_src && __copy_from_user((k_align_src + byteoffset), + if (user_src && copy_from_user((k_align_src + byteoffset), (void __user *)user_src, areq->cipher_op_req.vbuf.src[0].len)) return -EFAULT; @@ -1174,7 +1150,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, for (i = 1; i < areq->cipher_op_req.entries; i++) { user_src = (void __user *)areq->cipher_op_req.vbuf.src[i].vaddr; - if (user_src && __copy_from_user(k_align_src, + if (user_src && copy_from_user(k_align_src, (void __user *)user_src, areq->cipher_op_req.vbuf.src[i].len)) { return -EFAULT; @@ -1206,7 +1182,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, while (creq->data_len > 0) { if (creq->vbuf.dst[dst_i].len <= creq->data_len) { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->vbuf.dst[dst_i].len)) @@ -1217,7 +1193,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, creq->data_len -= creq->vbuf.dst[dst_i].len; dst_i++; } else { - if (err == 0 && __copy_to_user( + if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), creq->data_len)) @@ -1549,36 +1525,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, __func__, total, req->data_len); goto error; } - /* Verify Source Address's */ - for (i = 0, total = 0; i < req->entries; i++) { - if (total < req->data_len) { - if (!access_ok(VERIFY_READ, - (void __user *)req->vbuf.src[i].vaddr, - req->vbuf.src[i].len)) { - pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.src[i].vaddr); - goto error; - } - total += req->vbuf.src[i].len; - } - } - - /* Verify Destination Address's */ - for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) { - if ((req->vbuf.dst[i].vaddr != 0) && - (total < req->data_len)) { - if (!access_ok(VERIFY_WRITE, - (void __user *)req->vbuf.dst[i].vaddr, - req->vbuf.dst[i].len)) { - pr_err("%s:DST WR_VERIFY err %d=0x%lx\n", - __func__, i, (uintptr_t) - req->vbuf.dst[i].vaddr); - goto error; - } - total += req->vbuf.dst[i].len; - } - } return 0; error: return -EINVAL; @@ -1675,11 +1621,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) switch (cmd) { case QCEDEV_IOCTL_ENC_REQ: case QCEDEV_IOCTL_DEC_REQ: - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.cipher_op_req, + if (copy_from_user(&qcedev_areq.cipher_op_req, (void __user *)arg, sizeof(struct qcedev_cipher_op_req))) return -EFAULT; @@ -1692,20 +1634,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle); if (err) return err; - if (__copy_to_user((void __user *)arg, + if (copy_to_user((void __user *)arg, &qcedev_areq.cipher_op_req, sizeof(struct qcedev_cipher_op_req))) - return -EFAULT; + return -EFAULT; break; case QCEDEV_IOCTL_SHA_INIT_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1715,9 +1654,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) err = qcedev_hash_init(&qcedev_areq, handle, &sg_src); if (err) return err; - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) - return -EFAULT; + return -EFAULT; } handle->sha_ctxt.init_done = true; break; @@ -1727,11 +1666,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_SHA_UPDATE_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1753,10 +1689,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return err; } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + return -EINVAL; + } memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } @@ -1768,11 +1709,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("%s Init was not called\n", __func__); return -EINVAL; } - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1786,7 +1723,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; handle->sha_ctxt.init_done = false; @@ -1795,11 +1732,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case QCEDEV_IOCTL_GET_SHA_REQ: { struct scatterlist sg_src; - if (!access_ok(VERIFY_WRITE, (void __user *)arg, - sizeof(struct qcedev_sha_op_req))) - return -EFAULT; - if (__copy_from_user(&qcedev_areq.sha_op_req, + if (copy_from_user(&qcedev_areq.sha_op_req, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1817,7 +1751,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); - if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, + if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; } From ff38f59c65de7c9cbcfd8b11defb4adc3ab95a1d Mon Sep 17 00:00:00 2001 From: Xiaoyu Ye Date: Mon, 19 Dec 2016 18:38:53 -0800 Subject: [PATCH 172/281] ASoC: msm: qdsp6v2: Add range checking in msm_dai_q6_set_channel_map Range checking is added to prevent buffer overflow that due to inputs can be set by user space. CRs-Fixed: 1098363 Change-Id: I057261291806240ee6d7b8106a5e83a7665e013d Signed-off-by: Xiaoyu Ye --- sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 7ce5fa413980..b4efcb4012e5 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1274,6 +1274,11 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai, pr_err("%s: rx slot not found\n", __func__); return -EINVAL; } + if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) { + pr_err("%s: invalid rx num %d\n", __func__, rx_num); + return -EINVAL; + } + for (i = 0; i < rx_num; i++) { dai_data->port_config.slim_sch.shared_ch_mapping[i] = rx_slot[i]; @@ -1304,6 +1309,11 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai, pr_err("%s: tx slot not found\n", __func__); return -EINVAL; } + if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) { + pr_err("%s: invalid tx num %d\n", __func__, tx_num); + return -EINVAL; + } + for (i = 0; i < tx_num; i++) { dai_data->port_config.slim_sch.shared_ch_mapping[i] = tx_slot[i]; From edac861b45306746a6db229cb4e8c706755cce19 Mon Sep 17 00:00:00 2001 From: Xiaoyu Ye Date: Tue, 20 Dec 2016 10:56:59 -0800 Subject: [PATCH 173/281] mfd: wcd9xxx: Add range checking in function wcd9xxx_init_slimslave Range checking is added to prevent buffer overflow. CRs-Fixed: 1098363 Change-Id: I5871a3a11ec5f5106a386bf149d7ec22605f3db8 Signed-off-by: Xiaoyu Ye --- drivers/mfd/wcd9xxx-slimslave.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c index 4076e93a4b0c..baf4be48f059 100644 --- a/drivers/mfd/wcd9xxx-slimslave.c +++ b/drivers/mfd/wcd9xxx-slimslave.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -87,6 +87,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la, goto err; } + if (!rx_num || rx_num > wcd9xxx->num_rx_port) { + pr_err("%s: invalid rx num %d\n", __func__, rx_num); + return -EINVAL; + } if (wcd9xxx->rx_chs) { wcd9xxx->num_rx_port = rx_num; for (i = 0; i < rx_num; i++) { @@ -109,6 +113,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la, wcd9xxx->num_rx_port); } + if (!tx_num || tx_num > wcd9xxx->num_tx_port) { + pr_err("%s: invalid tx num %d\n", __func__, tx_num); + return -EINVAL; + } if (wcd9xxx->tx_chs) { wcd9xxx->num_tx_port = tx_num; for (i = 0; i < tx_num; i++) { From c36799d0d0bb37a22dc6cba2c1d499f15dd29d85 Mon Sep 17 00:00:00 2001 From: yangdongdong Date: Sat, 8 Aug 2015 11:59:59 +0800 Subject: [PATCH 174/281] power: align wakeup_sources format This aligns every column of elements in wakeup_sources to conveniently check any specific column for suspicious power consumption wakeup source or for other easily human readable purpose. Signed-off-by: yangdongdong --- drivers/base/power/wakeup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 79715e7fa43e..2ecba8b8505f 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -842,7 +842,7 @@ static int print_wakeup_source_stats(struct seq_file *m, active_time = ktime_set(0, 0); } - ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t" + ret = seq_printf(m, "%-32s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t" "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n", ws->name, active_count, ws->event_count, ws->wakeup_count, ws->expire_count, @@ -863,7 +863,7 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused) { struct wakeup_source *ws; - seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" + seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t" "expire_count\tactive_since\ttotal_time\tmax_time\t" "last_change\tprevent_suspend_time\n"); From 8a4846b15d00b473ee7a83d8da225525a0efd359 Mon Sep 17 00:00:00 2001 From: Alberto97 Date: Thu, 23 Mar 2017 22:31:31 +0100 Subject: [PATCH 175/281] msm: mdss: mdss_set_rgb: Print a new line in pr_info Change-Id: Ic284421770b455222146416e51d0a181570bf319 --- drivers/video/msm/mdss/mdss_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 627496d3ffa8..94498dbea740 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -715,7 +715,7 @@ static ssize_t mdss_set_rgb(struct device *dev, if (b < 0 || b > 32768) return -EINVAL; - pr_info("%s: r=%d g=%d b=%d", __func__, r, g, b); + pr_info("%s: r=%d g=%d b=%d\n", __func__, r, g, b); memset(&pcc_cfg, 0, sizeof(struct mdp_pcc_cfg_data)); From 3d669d51a700505f5bd1b66e858aba30846652bf Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 1 Mar 2017 17:04:41 -0800 Subject: [PATCH 176/281] ANDROID: sdcardfs: Fix case insensitive lookup The previous case insensitive lookup relied on the entry being present in the dcache. This instead uses iterate_dir to find the correct case. Signed-off-by: Daniel Rosenberg to_find, &candidate)) { + memcpy(buf->name, name, namelen); + buf->name[namelen] = 0; + buf->found = true; + return 1; + } + return 0; +} + /* * Main driver function for sdcardfs's lookup. * @@ -241,27 +263,39 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, &lower_path); /* check for other cases */ if (err == -ENOENT) { - struct dentry *child; - struct dentry *match = NULL; - mutex_lock(&lower_dir_dentry->d_inode->i_mutex); - spin_lock(&lower_dir_dentry->d_lock); - list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) { - if (child && child->d_inode) { - if (qstr_case_eq(&child->d_name, name)) { - match = dget(child); - break; - } - } + struct file *file; + const struct cred *cred = current_cred(); + + struct sdcardfs_name_data buffer = { + .ctx.actor = sdcardfs_name_match, + .to_find = name, + .name = __getname(), + .found = false, + }; + + if (!buffer.name) { + err = -ENOMEM; + goto out; + } + file = dentry_open(lower_parent_path, O_RDONLY, cred); + if (IS_ERR(file)) { + err = PTR_ERR(file); + goto put_name; } - spin_unlock(&lower_dir_dentry->d_lock); - mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); - if (match) { + err = iterate_dir(file, &buffer.ctx); + fput(file); + if (err) + goto put_name; + + if (buffer.found) err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, - match->d_name.name, 0, + buffer.name, 0, &lower_path); - dput(match); - } + else + err = -ENOENT; +put_name: + __putname(buffer.name); } /* no error: handle positive dentries */ From 80f468ea4c1fa2dafbbbad63503563209d0fd476 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 2 Mar 2017 18:07:21 -0800 Subject: [PATCH 177/281] ANDROID: sdcardfs: rate limit warning print Signed-off-by: Daniel Rosenberg Bug: 35848445 Change-Id: Ida72ea0ece191b2ae4a8babae096b2451eb563f6 --- fs/sdcardfs/inode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 9ec16b8e4487..4382917942da 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -20,6 +20,7 @@ #include "sdcardfs.h" #include +#include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info) @@ -611,7 +612,7 @@ static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, static int sdcardfs_permission_wrn(struct inode *inode, int mask) { - WARN(1, "sdcardfs does not support permission. Use permission2.\n"); + WARN_RATELIMIT(1, "sdcardfs does not support permission. Use permission2.\n"); return -EINVAL; } @@ -696,7 +697,7 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia) { - WARN(1, "sdcardfs does not support setattr. User setattr2.\n"); + WARN_RATELIMIT(1, "sdcardfs does not support setattr. User setattr2.\n"); return -EINVAL; } From 3737fb913046a2cc2ad1569bf51a215f4238a3e7 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 2 Mar 2017 15:11:27 -0800 Subject: [PATCH 178/281] ANDROID: sdcardfs: Replace get/put with d_lock dput cannot be called with a spin_lock. Instead, we protect our accesses by holding the d_lock. Signed-off-by: Daniel Rosenberg Bug: 35643557 Change-Id: I22cf30856d75b5616cbb0c223724f5ab866b5114 --- fs/sdcardfs/derived_perm.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 5ad69e6f6c33..cdf31c95199e 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -254,40 +254,46 @@ static int needs_fixup(perm_t perm) { return 0; } -void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { +static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit, int depth) { struct dentry *child; struct sdcardfs_inode_info *info; - if (!dget(dentry)) - return; + + /* + * All paths will terminate their recursion on hitting PERM_ANDROID_OBB, + * PERM_ANDROID_MEDIA, or PERM_ANDROID_DATA. This happens at a depth of + * at most 3. + */ + WARN(depth > 3, "%s: Max expected depth exceeded!\n", __func__); + spin_lock_nested(&dentry->d_lock, depth); if (!dentry->d_inode) { - dput(dentry); + spin_unlock(&dentry->d_lock); return; } info = SDCARDFS_I(dentry->d_inode); if (needs_fixup(info->perm)) { - spin_lock(&dentry->d_lock); list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - dget(child); + spin_lock_nested(&child->d_lock, depth + 1); if (!(limit->flags & BY_NAME) || !strncasecmp(child->d_name.name, limit->name, limit->length)) { if (child->d_inode) { get_derived_permission(dentry, child); fixup_tmp_permissions(child->d_inode); - dput(child); + spin_unlock(&child->d_lock); break; } } - dput(child); + spin_unlock(&child->d_lock); } - spin_unlock(&dentry->d_lock); } else if (descendant_may_need_fixup(info, limit)) { - spin_lock(&dentry->d_lock); list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - fixup_perms_recursive(child, limit); + __fixup_perms_recursive(child, limit, depth + 1); } - spin_unlock(&dentry->d_lock); } - dput(dentry); + spin_unlock(&dentry->d_lock); +} + +void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { + __fixup_perms_recursive(dentry, limit, 0); } void drop_recursive(struct dentry *parent) { From 3f6b4851e8bad4db12efb968e7ddd0afc3f31219 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 8 Mar 2017 17:11:51 -0800 Subject: [PATCH 179/281] ANDROID: sdcardfs: Use spin_lock_nested Signed-off-by: Daniel Rosenberg Bug: 36007653 Change-Id: I805d5afec797669679853fb2bb993ee38e6276e4 --- fs/sdcardfs/dentry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index b2fa36f13e73..f03f16d3e69d 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -76,10 +76,10 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) if (dentry < lower_dentry) { spin_lock(&dentry->d_lock); - spin_lock(&lower_dentry->d_lock); + spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED); } else { spin_lock(&lower_dentry->d_lock); - spin_lock(&dentry->d_lock); + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); } if (dentry->d_name.len != lower_dentry->d_name.len) { From be450f6266204ca773cb5ac0ac681f968be7041b Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 8 Mar 2017 17:20:02 -0800 Subject: [PATCH 180/281] ANDROID: sdcardfs: Switch to internal case insensitive compare There were still a few places where we called into a case insensitive lookup that was not defined by sdcardfs. Moving them all to the same place will allow us to switch the implementation in the future. Additionally, the check in fixup_perms_recursive did not take into account the length of both strings, causing extraneous matches when the name we were looking for was a prefix of the child name. Signed-off-by: Daniel Rosenberg Change-Id: I45ce768cd782cb4ea1ae183772781387c590ecc2 --- fs/sdcardfs/dentry.c | 8 ++------ fs/sdcardfs/derived_perm.c | 2 +- fs/sdcardfs/packagelist.c | 6 ++---- fs/sdcardfs/sdcardfs.h | 7 +++++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index f03f16d3e69d..4e9d2249e129 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -82,11 +82,7 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); } - if (dentry->d_name.len != lower_dentry->d_name.len) { - __d_drop(dentry); - err = 0; - } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name, - dentry->d_name.len) != 0) { + if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) { __d_drop(dentry); err = 0; } @@ -167,7 +163,7 @@ static int sdcardfs_cmp_ci(const struct dentry *parent, } */ if (name->len == len) { - if (strncasecmp(name->name, str, len) == 0) + if (str_n_case_eq(name->name, str, len)) return 0; } return 1; diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index cdf31c95199e..f9232b1d97c6 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -274,7 +274,7 @@ static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search * if (needs_fixup(info->perm)) { list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { spin_lock_nested(&child->d_lock, depth + 1); - if (!(limit->flags & BY_NAME) || !strncasecmp(child->d_name.name, limit->name, limit->length)) { + if (!(limit->flags & BY_NAME) || qstr_case_eq(&child->d_name, &limit->name)) { if (child->d_inode) { get_derived_permission(dentry, child); fixup_tmp_permissions(child->d_inode); diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 21eb2d317e44..490dd97028fd 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -251,8 +251,7 @@ static void fixup_all_perms_name(const struct qstr *key) struct sdcardfs_sb_info *sbinfo; struct limit_search limit = { .flags = BY_NAME, - .name = key->name, - .length = key->len, + .name = QSTR_INIT(key->name, key->len), }; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { if (sbinfo_has_sdcard_magic(sbinfo)) @@ -265,8 +264,7 @@ static void fixup_all_perms_name_userid(const struct qstr *key, userid_t userid) struct sdcardfs_sb_info *sbinfo; struct limit_search limit = { .flags = BY_NAME | BY_USERID, - .name = key->name, - .length = key->len, + .name = QSTR_INIT(key->name, key->len), .userid = userid, }; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index fe121e81a24d..00bbfd6f8ddc 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -470,8 +470,7 @@ extern void packagelist_exit(void); #define BY_USERID (1 << 1) struct limit_search { unsigned int flags; - const char *name; - size_t length; + struct qstr name; userid_t userid; }; @@ -613,6 +612,10 @@ static inline bool str_case_eq(const char *s1, const char *s2) return !strcasecmp(s1, s2); } +static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) { + return !strncasecmp(s1, s2, len); +} + static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) { return q1->len == q2->len && str_case_eq(q1->name, q2->name); From 31c68158546c8192dfee7a4a910c45b8325f4616 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 8 Mar 2017 17:45:46 -0800 Subject: [PATCH 181/281] ANDROID: sdcardfs: Use d_invalidate instead of drop_recurisve drop_recursive did not properly remove stale dentries. Instead, we use the vfs's d_invalidate, which does the proper cleanup. Additionally, remove the no longer used drop_recursive, and fixup_top_recursive that that are no longer used. Signed-off-by: Daniel Rosenberg Change-Id: Ibff61b0c34b725b024a050169047a415bc90f0d8 --- fs/sdcardfs/derived_perm.c | 38 -------------------------------------- fs/sdcardfs/inode.c | 2 +- fs/sdcardfs/sdcardfs.h | 2 -- 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index f9232b1d97c6..4a3e9348bac7 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -296,44 +296,6 @@ void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { __fixup_perms_recursive(dentry, limit, 0); } -void drop_recursive(struct dentry *parent) { - struct dentry *dentry; - struct sdcardfs_inode_info *info; - if (!parent->d_inode) - return; - info = SDCARDFS_I(parent->d_inode); - spin_lock(&parent->d_lock); - list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { - if (dentry->d_inode) { - if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { - drop_recursive(dentry); - d_drop(dentry); - } - } - } - spin_unlock(&parent->d_lock); -} - -void fixup_top_recursive(struct dentry *parent) { - struct dentry *dentry; - struct sdcardfs_inode_info *info; - - if (!parent->d_inode) - return; - info = SDCARDFS_I(parent->d_inode); - spin_lock(&parent->d_lock); - list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) { - if (dentry->d_inode) { - if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { - get_derived_permission(parent, dentry); - fixup_tmp_permissions(dentry->d_inode); - fixup_top_recursive(dentry); - } - } - } - spin_unlock(&parent->d_lock); -} - /* main function for updating derived permission */ inline void update_derived_permission_lock(struct dentry *dentry) { diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 4382917942da..d7967cc6d383 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -528,7 +528,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name); fixup_tmp_permissions(old_dentry->d_inode); fixup_lower_ownership(old_dentry, new_dentry->d_name.name); - drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */ + d_invalidate(old_dentry); /* Can't fixup ownership recursively :( */ out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 00bbfd6f8ddc..2caee49aa8ec 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -478,8 +478,6 @@ extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t useri uid_t uid, bool under_android, struct inode *top); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name); -extern void drop_recursive(struct dentry *parent); -extern void fixup_top_recursive(struct dentry *parent); extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); extern void update_derived_permission_lock(struct dentry *dentry); From d78c925ff31943f714bd665c14088c6b6173741c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 18:12:16 -0800 Subject: [PATCH 182/281] ANDROID: sdcardfs: Get the blocksize from the lower fs This changes sdcardfs to be more in line with the getattr in wrapfs, which calls the lower fs's getattr to get the block size Signed-off-by: Daniel Rosenberg Bug: 34723223 Change-Id: I1c9e16604ba580a8cdefa17f02dcc489d7351aed --- fs/sdcardfs/inode.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index d7967cc6d383..79b5c67c8e01 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -868,9 +868,7 @@ static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode, struct k static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct dentry *lower_dentry; - struct inode *inode; - struct inode *lower_inode; + struct kstat lower_stat; struct path lower_path; struct dentry *parent; int err; @@ -885,16 +883,15 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, } dput(parent); - inode = dentry->d_inode; - sdcardfs_get_lower_path(dentry, &lower_path); - lower_dentry = lower_path.dentry; - lower_inode = sdcardfs_lower_inode(inode); - - sdcardfs_copy_and_fix_attrs(inode, lower_inode); - fsstack_copy_inode_size(inode, lower_inode); - - err = sdcardfs_fillattr(mnt, inode, stat); + err = vfs_getattr(&lower_path, &lower_stat); + if (err) + goto out; + sdcardfs_copy_and_fix_attrs(dentry->d_inode, + lower_path.dentry->d_inode); + err = sdcardfs_fillattr(mnt, dentry->d_inode, stat); + stat->blocks = lower_stat.blocks; +out: sdcardfs_put_lower_path(dentry, &lower_path); return err; } From 3a3083c4360ba8403b6f2082a451cc5bca9d625f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 20:59:18 -0800 Subject: [PATCH 183/281] ANDROID: sdcardfs: declare MODULE_ALIAS_FS From commit ee616b78aa87 ("Wrapfs: declare MODULE_ALIAS_FS") Signed-off-by: Daniel Rosenberg bug: 35766959 Change-Id: Ia4728ab49d065b1d2eb27825046f14b97c328cba --- fs/sdcardfs/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 8d16e4d16d96..ae62a994f818 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -432,6 +432,7 @@ static struct file_system_type sdcardfs_fs_type = { .kill_sb = sdcardfs_kill_sb, .fs_flags = 0, }; +MODULE_ALIAS_FS(SDCARDFS_NAME); static int __init init_sdcardfs_fs(void) { From a5e5955417cc96a0e7b2015373cf25478cfcdd92 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 10 Mar 2017 12:39:42 -0800 Subject: [PATCH 184/281] ANDROID: sdcardfs: Use case insensitive hash function Case insensitive comparisons don't help us much if we hash to different buckets... Signed-off-by: Daniel Rosenberg bug: 36004503 Change-Id: I91e00dbcd860a709cbd4f7fd7fc6d855779f3285 --- fs/sdcardfs/packagelist.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 490dd97028fd..89f23891498c 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -20,6 +20,7 @@ #include "sdcardfs.h" #include +#include #include #include #include @@ -44,10 +45,18 @@ static DEFINE_HASHTABLE(ext_to_groupid, 8); static struct kmem_cache *hashtable_entry_cachep; +static unsigned int full_name_case_hash(const unsigned char *name, unsigned int len) +{ + unsigned long hash = init_name_hash(); + while (len--) + hash = partial_name_hash(tolower(*name++), hash); + return end_name_hash(hash); +} + static void inline qstr_init(struct qstr *q, const char *name) { q->name = name; q->len = strlen(q->name); - q->hash = full_name_hash(q->name, q->len); + q->hash = full_name_case_hash(q->name, q->len); } static inline int qstr_copy(const struct qstr *src, struct qstr *dest) { From 7105210aba8dc3acaa1481116f717a6cc999105c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 10 Mar 2017 13:54:30 -0800 Subject: [PATCH 185/281] ANDROID: sdcardfs: move path_put outside of spinlock Signed-off-by: Daniel Rosenberg Bug: 35643557 Change-Id: Ib279ebd7dd4e5884d184d67696a93e34993bc1ef --- fs/sdcardfs/derived_perm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 4a3e9348bac7..f2c7a2ac3ca1 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -348,6 +348,8 @@ int is_obbpath_invalid(struct dentry *dent) struct sdcardfs_dentry_info *di = SDCARDFS_D(dent); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dent->d_sb); char *path_buf, *obbpath_s; + int need_put = 0; + struct path lower_path; /* check the base obbpath has been changed. * this routine can check an uninitialized obb dentry as well. @@ -374,10 +376,13 @@ int is_obbpath_invalid(struct dentry *dent) } //unlock_dir(lower_parent); - path_put(&di->lower_path); + pathcpy(&lower_path, &di->lower_path); + need_put = 1; } } spin_unlock(&di->lock); + if (need_put) + path_put(&lower_path); return ret; } From 0685ad8b510b60901cc36ad56d19760b9e975260 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 10 Mar 2017 18:58:25 -0800 Subject: [PATCH 186/281] ANDROID: sdcardfs: Remove uninformative prints At best these prints do not provide useful information, and at worst, some allow userspace to abuse the kernel log. Signed-off-by: Daniel Rosenberg Bug: 36138424 Change-Id: I812c57cc6a22b37262935ab77f48f3af4c36827e --- fs/sdcardfs/derived_perm.c | 1 - fs/sdcardfs/file.c | 3 --- fs/sdcardfs/inode.c | 24 +----------------------- fs/sdcardfs/lookup.c | 3 --- 4 files changed, 1 insertion(+), 30 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index f2c7a2ac3ca1..20d8ee89b65a 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -428,7 +428,6 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) if(!err) { /* the obbpath base has been found */ - printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n"); pathcpy(lower_path, &obbpath); } else { /* if the sbi->obbpath is not available, we can optionally diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index a9c82b7eadad..28acc77852ae 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -217,9 +217,6 @@ static int sdcardfs_open(struct inode *inode, struct file *file) } if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_err; } diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 79b5c67c8e01..42ffc0a6dd30 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -68,9 +68,6 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct fs_struct *copied_fs; if(!check_caller_access_to_name(dir, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } @@ -170,9 +167,6 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) const struct cred *saved_cred = NULL; if(!check_caller_access_to_name(dir, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } @@ -280,9 +274,6 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct qstr q_data = QSTR_LITERAL("data"); if(!check_caller_access_to_name(dir, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } @@ -392,9 +383,6 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) const struct cred *saved_cred = NULL; if(!check_caller_access_to_name(dir, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } @@ -481,9 +469,6 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, if(!check_caller_access_to_name(old_dir, &old_dentry->d_name) || !check_caller_access_to_name(new_dir, &new_dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " new_dentry: %s, task:%s\n", - __func__, new_dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } @@ -758,12 +743,8 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct if (!err) { /* check the Android group ID */ parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) err = -EACCES; - } dput(parent); } @@ -875,9 +856,6 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); dput(parent); return -EACCES; } diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 5db2b288e7cc..9f8dcc28b437 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -391,9 +391,6 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { ret = ERR_PTR(-EACCES); - printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); goto out_err; } From d394adcb6279a09bdfbc501a3f0ab191c9921e91 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 13 Mar 2017 13:53:54 -0700 Subject: [PATCH 187/281] ANDROID: sdcardfs: Use tabs instead of spaces in multiuser.h Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: Ic7801914a7dd377e270647f81070020e1f0bab9b --- fs/sdcardfs/multiuser.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index 52bc20080904..ca141ff40b49 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -29,21 +29,21 @@ typedef uid_t userid_t; typedef uid_t appid_t; static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) { - return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); + return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } static inline gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) { - if (app_id >= AID_APP_START && app_id <= AID_APP_END) { - return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START); - } else { - return -1; - } + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START); + } else { + return -1; + } } static inline gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id) { - if (app_id >= AID_APP_START && app_id <= AID_APP_END) { - return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START); - } else { - return -1; - } + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START); + } else { + return -1; + } } From d8ce982d41517e6595508325d331845e5fea9b50 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 13 Mar 2017 15:34:03 -0700 Subject: [PATCH 188/281] ANDROID: sdcardfs: Fix gid issue We were already calculating most of these values, and erroring out because the check was confused by this. Instead of recalculating, adjust it as needed. Signed-off-by: Daniel Rosenberg Bug: 36160015 Change-Id: I9caf3e2fd32ca2e37ff8ed71b1d392f1761bc9a9 --- fs/sdcardfs/derived_perm.c | 4 ++-- fs/sdcardfs/multiuser.h | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 20d8ee89b65a..1f3eb8b45298 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -204,13 +204,13 @@ void fixup_lower_ownership(struct dentry* dentry, const char *name) { break; case PERM_ANDROID_PACKAGE: if (info->d_uid != 0) - gid = multiuser_get_ext_gid(info->userid, info->d_uid); + gid = multiuser_get_ext_gid(info->d_uid); else gid = multiuser_get_uid(info->userid, uid); break; case PERM_ANDROID_PACKAGE_CACHE: if (info->d_uid != 0) - gid = multiuser_get_cache_gid(info->userid, info->d_uid); + gid = multiuser_get_cache_gid(info->d_uid); else gid = multiuser_get_uid(info->userid, uid); break; diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index ca141ff40b49..530bfad6b00e 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -32,18 +32,10 @@ static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) { return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } -static inline gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) { - if (app_id >= AID_APP_START && app_id <= AID_APP_END) { - return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START); - } else { - return -1; - } +static inline gid_t multiuser_get_cache_gid(uid_t uid) { + return uid - AID_APP_START + AID_CACHE_GID_START; } -static inline gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id) { - if (app_id >= AID_APP_START && app_id <= AID_APP_END) { - return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START); - } else { - return -1; - } +static inline gid_t multiuser_get_ext_gid(uid_t uid) { + return uid - AID_APP_START + AID_EXT_GID_START; } From 04e81a80761f75da7fc681dd21586d0a72c89edb Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 Mar 2017 16:28:27 -0700 Subject: [PATCH 189/281] ANDROID: sdcardfs: correct order of descriptors Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: Ia6d16b19c8c911f41231d2a12be0740057edfacf --- fs/sdcardfs/packagelist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 89f23891498c..4fe153861220 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -48,12 +48,14 @@ static struct kmem_cache *hashtable_entry_cachep; static unsigned int full_name_case_hash(const unsigned char *name, unsigned int len) { unsigned long hash = init_name_hash(); + while (len--) hash = partial_name_hash(tolower(*name++), hash); return end_name_hash(hash); } -static void inline qstr_init(struct qstr *q, const char *name) { +static inline void qstr_init(struct qstr *q, const char *name) +{ q->name = name; q->len = strlen(q->name); q->hash = full_name_case_hash(q->name, q->len); From 2d40a910ac5661cee54aa284cd310f381a2498aa Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 16 Mar 2017 17:42:58 -0700 Subject: [PATCH 190/281] ANDROID: sdcardfs: Fix formatting This fixes various spacing and bracket related issues pointed out by checkpatch. Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: I6e248833a7a04e3899f3ae9462d765cfcaa70c96 --- fs/sdcardfs/dentry.c | 13 +- fs/sdcardfs/derived_perm.c | 250 +++++++++++++++++++------------------ fs/sdcardfs/file.c | 5 +- fs/sdcardfs/inode.c | 52 ++++---- fs/sdcardfs/lookup.c | 28 +++-- fs/sdcardfs/main.c | 34 +++-- fs/sdcardfs/multiuser.h | 9 +- fs/sdcardfs/packagelist.c | 42 ++++--- fs/sdcardfs/sdcardfs.h | 109 ++++++++-------- fs/sdcardfs/super.c | 29 +++-- 10 files changed, 312 insertions(+), 259 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 4e9d2249e129..3a213c75420f 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -46,7 +46,8 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) spin_unlock(&dentry->d_lock); /* check uninitialized obb_dentry and - * whether the base obbpath has been changed or not */ + * whether the base obbpath has been changed or not + */ if (is_obbpath_invalid(dentry)) { d_drop(dentry); return 0; @@ -106,12 +107,10 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) static void sdcardfs_d_release(struct dentry *dentry) { /* release and reset the lower paths */ - if(has_graft_path(dentry)) { + if (has_graft_path(dentry)) sdcardfs_put_reset_orig_path(dentry); - } sdcardfs_put_reset_lower_path(dentry); free_dentry_private_data(dentry); - return; } static int sdcardfs_hash_ci(const struct dentry *dentry, @@ -169,14 +168,16 @@ static int sdcardfs_cmp_ci(const struct dentry *parent, return 1; } -static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) { +static void sdcardfs_canonical_path(const struct path *path, + struct path *actual_path) +{ sdcardfs_get_real_lower(path->dentry, actual_path); } const struct dentry_operations sdcardfs_ci_dops = { .d_revalidate = sdcardfs_d_revalidate, .d_release = sdcardfs_d_release, - .d_hash = sdcardfs_hash_ci, + .d_hash = sdcardfs_hash_ci, .d_compare = sdcardfs_cmp_ci, .d_canonical_path = sdcardfs_canonical_path, }; diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 1f3eb8b45298..8d5c1fdcdfe3 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -37,7 +37,8 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) /* helper function for derived state */ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, - uid_t uid, bool under_android, struct inode *top) + uid_t uid, bool under_android, + struct inode *top) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); @@ -50,11 +51,14 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, set_top(info, top); } -/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ -void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name) +/* While renaming, there is a point where we want the path from dentry, + * but the name from newdentry + */ +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, + const struct qstr *name) { struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); - struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); appid_t appid; struct qstr q_Android = QSTR_LITERAL("Android"); struct qstr q_data = QSTR_LITERAL("data"); @@ -77,58 +81,57 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, co return; /* Derive custom permissions based on parent and current node */ switch (parent_info->perm) { - case PERM_INHERIT: - case PERM_ANDROID_PACKAGE_CACHE: - /* Already inherited above */ - break; - case PERM_PRE_ROOT: - /* Legacy internal layout places users at top level */ - info->perm = PERM_ROOT; - info->userid = simple_strtoul(name->name, NULL, 10); + case PERM_INHERIT: + case PERM_ANDROID_PACKAGE_CACHE: + /* Already inherited above */ + break; + case PERM_PRE_ROOT: + /* Legacy internal layout places users at top level */ + info->perm = PERM_ROOT; + info->userid = simple_strtoul(name->name, NULL, 10); + set_top(info, &info->vfs_inode); + break; + case PERM_ROOT: + /* Assume masked off by default. */ + if (qstr_case_eq(name, &q_Android)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID; + info->under_android = true; set_top(info, &info->vfs_inode); - break; - case PERM_ROOT: - /* Assume masked off by default. */ - if (qstr_case_eq(name, &q_Android)) { - /* App-specific directories inside; let anyone traverse */ - info->perm = PERM_ANDROID; - info->under_android = true; - set_top(info, &info->vfs_inode); - } - break; - case PERM_ANDROID: - if (qstr_case_eq(name, &q_data)) { - /* App-specific directories inside; let anyone traverse */ - info->perm = PERM_ANDROID_DATA; - set_top(info, &info->vfs_inode); - } else if (qstr_case_eq(name, &q_obb)) { - /* App-specific directories inside; let anyone traverse */ - info->perm = PERM_ANDROID_OBB; - info->under_obb = true; - set_top(info, &info->vfs_inode); - /* Single OBB directory is always shared */ - } else if (qstr_case_eq(name, &q_media)) { - /* App-specific directories inside; let anyone traverse */ - info->perm = PERM_ANDROID_MEDIA; - set_top(info, &info->vfs_inode); - } - break; - case PERM_ANDROID_OBB: - case PERM_ANDROID_DATA: - case PERM_ANDROID_MEDIA: - info->perm = PERM_ANDROID_PACKAGE; - appid = get_appid(name->name); - if (appid != 0 && !is_excluded(name->name, parent_info->userid)) { - info->d_uid = multiuser_get_uid(parent_info->userid, appid); - } + } + break; + case PERM_ANDROID: + if (qstr_case_eq(name, &q_data)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_DATA; set_top(info, &info->vfs_inode); - break; - case PERM_ANDROID_PACKAGE: - if (qstr_case_eq(name, &q_cache)) { - info->perm = PERM_ANDROID_PACKAGE_CACHE; - info->under_cache = true; - } - break; + } else if (qstr_case_eq(name, &q_obb)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_OBB; + info->under_obb = true; + set_top(info, &info->vfs_inode); + /* Single OBB directory is always shared */ + } else if (qstr_case_eq(name, &q_media)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_MEDIA; + set_top(info, &info->vfs_inode); + } + break; + case PERM_ANDROID_OBB: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + info->perm = PERM_ANDROID_PACKAGE; + appid = get_appid(name->name); + if (appid != 0 && !is_excluded(name->name, parent_info->userid)) + info->d_uid = multiuser_get_uid(parent_info->userid, appid); + set_top(info, &info->vfs_inode); + break; + case PERM_ANDROID_PACKAGE: + if (qstr_case_eq(name, &q_cache)) { + info->perm = PERM_ANDROID_PACKAGE_CACHE; + info->under_cache = true; + } + break; } } @@ -137,7 +140,8 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry) get_derived_permission_new(parent, dentry, &dentry->d_name); } -static appid_t get_type(const char *name) { +static appid_t get_type(const char *name) +{ const char *ext = strrchr(name, '.'); appid_t id; @@ -149,7 +153,8 @@ static appid_t get_type(const char *name) { return AID_MEDIA_RW; } -void fixup_lower_ownership(struct dentry* dentry, const char *name) { +void fixup_lower_ownership(struct dentry *dentry, const char *name) +{ struct path path; struct inode *inode; int error; @@ -174,49 +179,49 @@ void fixup_lower_ownership(struct dentry* dentry, const char *name) { } switch (perm) { - case PERM_ROOT: - case PERM_ANDROID: - case PERM_ANDROID_DATA: - case PERM_ANDROID_MEDIA: - case PERM_ANDROID_PACKAGE: - case PERM_ANDROID_PACKAGE_CACHE: - uid = multiuser_get_uid(info->userid, uid); - break; - case PERM_ANDROID_OBB: - uid = AID_MEDIA_OBB; - break; - case PERM_PRE_ROOT: - default: - break; + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + case PERM_ANDROID_PACKAGE: + case PERM_ANDROID_PACKAGE_CACHE: + uid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_OBB: + uid = AID_MEDIA_OBB; + break; + case PERM_PRE_ROOT: + default: + break; } switch (perm) { - case PERM_ROOT: - case PERM_ANDROID: - case PERM_ANDROID_DATA: - case PERM_ANDROID_MEDIA: - if (S_ISDIR(dentry->d_inode->i_mode)) - gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); - else - gid = multiuser_get_uid(info->userid, get_type(name)); - break; - case PERM_ANDROID_OBB: - gid = AID_MEDIA_OBB; - break; - case PERM_ANDROID_PACKAGE: - if (info->d_uid != 0) - gid = multiuser_get_ext_gid(info->d_uid); - else - gid = multiuser_get_uid(info->userid, uid); - break; - case PERM_ANDROID_PACKAGE_CACHE: - if (info->d_uid != 0) - gid = multiuser_get_cache_gid(info->d_uid); - else - gid = multiuser_get_uid(info->userid, uid); - break; - case PERM_PRE_ROOT: - default: - break; + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + if (S_ISDIR(dentry->d_inode->i_mode)) + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); + else + gid = multiuser_get_uid(info->userid, get_type(name)); + break; + case PERM_ANDROID_OBB: + gid = AID_MEDIA_OBB; + break; + case PERM_ANDROID_PACKAGE: + if (info->d_uid != 0) + gid = multiuser_get_ext_gid(info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_PACKAGE_CACHE: + if (info->d_uid != 0) + gid = multiuser_get_cache_gid(info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_PRE_ROOT: + default: + break; } sdcardfs_get_lower_path(dentry, &path); @@ -239,22 +244,25 @@ void fixup_lower_ownership(struct dentry* dentry, const char *name) { sdcardfs_put_lower_path(dentry, &path); } -static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) { +static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) +{ if (info->perm == PERM_ROOT) - return (limit->flags & BY_USERID)?info->userid == limit->userid:1; + return (limit->flags & BY_USERID) ? info->userid == limit->userid : 1; if (info->perm == PERM_PRE_ROOT || info->perm == PERM_ANDROID) return 1; return 0; } -static int needs_fixup(perm_t perm) { +static int needs_fixup(perm_t perm) +{ if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB || perm == PERM_ANDROID_MEDIA) return 1; return 0; } -static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit, int depth) { +static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit, int depth) +{ struct dentry *child; struct sdcardfs_inode_info *info; @@ -284,15 +292,16 @@ static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search * } spin_unlock(&child->d_lock); } - } else if (descendant_may_need_fixup(info, limit)) { + } else if (descendant_may_need_fixup(info, limit)) { list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - __fixup_perms_recursive(child, limit, depth + 1); + __fixup_perms_recursive(child, limit, depth + 1); } } spin_unlock(&dentry->d_lock); } -void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { +void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) +{ __fixup_perms_recursive(dentry, limit, 0); } @@ -301,7 +310,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) { struct dentry *parent; - if(!dentry || !dentry->d_inode) { + if (!dentry || !dentry->d_inode) { printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__); return; } @@ -309,11 +318,11 @@ inline void update_derived_permission_lock(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ - if(IS_ROOT(dentry)) { + if (IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { parent = dget_parent(dentry); - if(parent) { + if (parent) { get_derived_permission(parent, dentry); dput(parent); } @@ -325,15 +334,15 @@ int need_graft_path(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); - struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct qstr obb = QSTR_LITERAL("obb"); - if(parent_info->perm == PERM_ANDROID && + if (parent_info->perm == PERM_ANDROID && qstr_case_eq(&dentry->d_name, &obb)) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ - if(!(sbi->options.multiuser == false + if (!(sbi->options.multiuser == false && parent_info->userid == 0)) { ret = 1; } @@ -353,17 +362,18 @@ int is_obbpath_invalid(struct dentry *dent) /* check the base obbpath has been changed. * this routine can check an uninitialized obb dentry as well. - * regarding the uninitialized obb, refer to the sdcardfs_mkdir() */ + * regarding the uninitialized obb, refer to the sdcardfs_mkdir() + */ spin_lock(&di->lock); - if(di->orig_path.dentry) { - if(!di->lower_path.dentry) { + if (di->orig_path.dentry) { + if (!di->lower_path.dentry) { ret = 1; } else { path_get(&di->lower_path); //lower_parent = lock_parent(lower_path->dentry); path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); - if(!path_buf) { + if (!path_buf) { ret = 1; printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__); } else { @@ -390,13 +400,13 @@ int is_base_obbpath(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); - struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct qstr q_obb = QSTR_LITERAL("obb"); spin_lock(&SDCARDFS_D(dentry)->lock); if (sbi->options.multiuser) { - if(parent_info->perm == PERM_PRE_ROOT && + if (parent_info->perm == PERM_PRE_ROOT && qstr_case_eq(&dentry->d_name, &q_obb)) { ret = 1; } @@ -411,7 +421,8 @@ int is_base_obbpath(struct dentry *dentry) /* The lower_path will be stored to the dentry's orig_path * and the base obbpath will be copyed to the lower_path variable. * if an error returned, there's no change in the lower_path - * returns: -ERRNO if error (0: no error) */ + * returns: -ERRNO if error (0: no error) + */ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) { int err = 0; @@ -426,7 +437,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) err = kern_path(sbi->obbpath_s, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &obbpath); - if(!err) { + if (!err) { /* the obbpath base has been found */ pathcpy(lower_path, &obbpath); } else { @@ -434,7 +445,8 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) * setup the lower_path with its orig_path. * but, the current implementation just returns an error * because the sdcard daemon also regards this case as - * a lookup fail. */ + * a lookup fail. + */ printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); } return err; diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 28acc77852ae..ab78bb854c9f 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -216,7 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } - if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { err = -EACCES; goto out_err; } @@ -249,9 +249,8 @@ static int sdcardfs_open(struct inode *inode, struct file *file) if (err) kfree(SDCARDFS_F(file)); - else { + else sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode)); - } out_revert_cred: REVERT_CRED(saved_cred); diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 42ffc0a6dd30..c2f2dd929154 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -23,10 +23,10 @@ #include /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ -const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info) +const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info) { - struct cred * cred; - const struct cred * old_cred; + struct cred *cred; + const struct cred *old_cred; uid_t uid; cred = prepare_creds(); @@ -46,9 +46,9 @@ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs } /* Do not directly use this function, use REVERT_CRED() instead. */ -void revert_fsids(const struct cred * old_cred) +void revert_fsids(const struct cred *old_cred) { - const struct cred * cur_cred; + const struct cred *cur_cred; cur_cred = current->cred; revert_creds(old_cred); @@ -67,7 +67,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, struct fs_struct *saved_fs; struct fs_struct *copied_fs; - if(!check_caller_access_to_name(dir, &dentry->d_name)) { + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } @@ -166,7 +166,7 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) struct path lower_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(dir, &dentry->d_name)) { + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } @@ -240,13 +240,14 @@ static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, } #endif -static int touch(char *abs_path, mode_t mode) { +static int touch(char *abs_path, mode_t mode) +{ struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode); + if (IS_ERR(filp)) { if (PTR_ERR(filp) == -EEXIST) { return 0; - } - else { + } else { printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n", abs_path, PTR_ERR(filp)); return PTR_ERR(filp); @@ -273,7 +274,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct qstr q_obb = QSTR_LITERAL("obb"); struct qstr q_data = QSTR_LITERAL("data"); - if(!check_caller_access_to_name(dir, &dentry->d_name)) { + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } @@ -315,19 +316,21 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } /* if it is a local obb dentry, setup it with the base obbpath */ - if(need_graft_path(dentry)) { + if (need_graft_path(dentry)) { err = setup_obb_dentry(dentry, &lower_path); - if(err) { + if (err) { /* if the sbi->obbpath is not available, the lower_path won't be * changed by setup_obb_dentry() but the lower path is saved to * its orig_path. this dentry will be revalidated later. - * but now, the lower_path should be NULL */ + * but now, the lower_path should be NULL + */ sdcardfs_put_reset_lower_path(dentry); /* the newly created lower path which saved to its orig_path or * the lower_path is the base obbpath. - * therefore, an additional path_get is required */ + * therefore, an additional path_get is required + */ path_get(&lower_path); } else make_nomedia_in_obb = 1; @@ -382,7 +385,7 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) struct path lower_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(dir, &dentry->d_name)) { + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } @@ -391,7 +394,8 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry - * the dentry on the original path should be deleted. */ + * the dentry on the original path should be deleted. + */ sdcardfs_get_real_lower(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -467,7 +471,7 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct path lower_old_path, lower_new_path; const struct cred *saved_cred = NULL; - if(!check_caller_access_to_name(old_dir, &old_dentry->d_name) || + if (!check_caller_access_to_name(old_dir, &old_dentry->d_name) || !check_caller_access_to_name(new_dir, &new_dentry->d_name)) { err = -EACCES; goto out_eacces; @@ -668,6 +672,7 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma * we check it with AID_MEDIA_RW permission */ struct inode *lower_inode; + OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); lower_inode = sdcardfs_lower_inode(inode); @@ -736,14 +741,15 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); /* Allow touch updating timestamps. A previous permission check ensures - * we have write access. Changes to mode, owner, and group are ignored*/ + * we have write access. Changes to mode, owner, and group are ignored + */ ia->ia_valid |= ATTR_FORCE; err = inode_change_ok(&tmp, ia); if (!err) { /* check the Android group ID */ parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) + if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) err = -EACCES; dput(parent); } @@ -822,10 +828,12 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct return err; } -static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode, struct kstat *stat) +static int sdcardfs_fillattr(struct vfsmount *mnt, + struct inode *inode, struct kstat *stat) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); struct inode *top = grab_top(info); + if (!top) return -EINVAL; @@ -855,7 +863,7 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, int err; parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { dput(parent); return -EACCES; } diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 9f8dcc28b437..832d1b886b49 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -73,6 +73,7 @@ static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void * { struct inode *current_lower_inode = sdcardfs_lower_inode(inode); userid_t current_userid = SDCARDFS_I(inode)->userid; + if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode && current_userid == ((struct inode_data *)candidate_data)->id) return 1; /* found a match */ @@ -102,7 +103,7 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u * instead. */ lower_inode->i_ino, /* hashval */ - sdcardfs_inode_test, /* inode comparison function */ + sdcardfs_inode_test, /* inode comparison function */ sdcardfs_inode_set, /* inode init function */ &data); /* data passed to test+set fxns */ if (!inode) { @@ -302,23 +303,26 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, if (!err) { /* check if the dentry is an obb dentry * if true, the lower_inode must be replaced with - * the inode of the graft path */ + * the inode of the graft path + */ - if(need_graft_path(dentry)) { + if (need_graft_path(dentry)) { /* setup_obb_dentry() - * The lower_path will be stored to the dentry's orig_path + * The lower_path will be stored to the dentry's orig_path * and the base obbpath will be copyed to the lower_path variable. * if an error returned, there's no change in the lower_path - * returns: -ERRNO if error (0: no error) */ + * returns: -ERRNO if error (0: no error) + */ err = setup_obb_dentry(dentry, &lower_path); - if(err) { + if (err) { /* if the sbi->obbpath is not available, we can optionally * setup the lower_path with its orig_path. * but, the current implementation just returns an error * because the sdcard daemon also regards this case as - * a lookup fail. */ + * a lookup fail. + */ printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); sdcardfs_put_reset_orig_path(dentry); goto out; @@ -370,9 +374,9 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, /* * On success: - * fills dentry object appropriate values and returns NULL. + * fills dentry object appropriate values and returns NULL. * On fail (== error) - * returns error ptr + * returns error ptr * * @dir : Parent inode. It is locked (dir->i_mutex) * @dentry : Target dentry to lookup. we should set each of fields. @@ -389,10 +393,10 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, parent = dget_parent(dentry); - if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { ret = ERR_PTR(-EACCES); goto out_err; - } + } /* save current_cred and override it */ OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); @@ -408,9 +412,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid); if (IS_ERR(ret)) - { goto out; - } if (ret) dentry = ret; if (dentry->d_inode) { diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index ae62a994f818..4a04c91ab456 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -72,6 +72,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, while ((p = strsep(&options, ",")) != NULL) { int token; + if (!*p) continue; @@ -148,6 +149,7 @@ int parse_options_remount(struct super_block *sb, char *options, int silent, while ((p = strsep(&options, ",")) != NULL) { int token; + if (!*p) continue; @@ -223,8 +225,8 @@ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) #endif DEFINE_MUTEX(sdcardfs_super_list_lock); -LIST_HEAD(sdcardfs_super_list); EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock); +LIST_HEAD(sdcardfs_super_list); EXPORT_SYMBOL_GPL(sdcardfs_super_list); /* @@ -328,14 +330,15 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* setup permission policy */ sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); - if(sb_info->options.multiuser) { - setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + if (sb_info->options.multiuser) { + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, + sb_info->options.fs_user_id, AID_ROOT, + false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); - /*err = prepare_dir(sb_info->obbpath_s, - sb_info->options.fs_low_uid, - sb_info->options.fs_low_gid, 00755);*/ } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, + sb_info->options.fs_user_id, AID_ROOT, + false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fixup_tmp_permissions(sb->s_root->d_inode); @@ -368,8 +371,10 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* A feature which supports mount_nodev() with options */ static struct dentry *mount_nodev_with_options(struct vfsmount *mnt, - struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct vfsmount *, struct super_block *, const char *, void *, int)) + struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + int (*fill_super)(struct vfsmount *, struct super_block *, + const char *, void *, int)) { int error; @@ -401,19 +406,22 @@ static struct dentry *sdcardfs_mount(struct vfsmount *mnt, raw_data, sdcardfs_read_super); } -static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, int flags, - const char *dev_name, void *raw_data) +static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data) { WARN(1, "sdcardfs does not support mount. Use mount2.\n"); return ERR_PTR(-EINVAL); } -void *sdcardfs_alloc_mnt_data(void) { +void *sdcardfs_alloc_mnt_data(void) +{ return kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); } -void sdcardfs_kill_sb(struct super_block *sb) { +void sdcardfs_kill_sb(struct super_block *sb) +{ struct sdcardfs_sb_info *sbi; + if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { sbi = SDCARDFS_SB(sb); mutex_lock(&sdcardfs_super_list_lock); diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index 530bfad6b00e..2e89b5872314 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -28,14 +28,17 @@ typedef uid_t userid_t; typedef uid_t appid_t; -static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) { +static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) +{ return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } -static inline gid_t multiuser_get_cache_gid(uid_t uid) { +static inline gid_t multiuser_get_cache_gid(uid_t uid) +{ return uid - AID_APP_START + AID_CACHE_GID_START; } -static inline gid_t multiuser_get_ext_gid(uid_t uid) { +static inline gid_t multiuser_get_ext_gid(uid_t uid) +{ return uid - AID_APP_START + AID_EXT_GID_START; } diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 4fe153861220..e5a56c94e404 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -61,7 +61,8 @@ static inline void qstr_init(struct qstr *q, const char *name) q->hash = full_name_case_hash(q->name, q->len); } -static inline int qstr_copy(const struct qstr *src, struct qstr *dest) { +static inline int qstr_copy(const struct qstr *src, struct qstr *dest) +{ dest->name = kstrdup(src->name, GFP_KERNEL); dest->hash_len = src->hash_len; return !!dest->name; @@ -89,6 +90,7 @@ static appid_t __get_appid(const struct qstr *key) appid_t get_appid(const char *key) { struct qstr q; + qstr_init(&q, key); return __get_appid(&q); } @@ -114,6 +116,7 @@ static appid_t __get_ext_gid(const struct qstr *key) appid_t get_ext_gid(const char *key) { struct qstr q; + qstr_init(&q, key); return __get_ext_gid(&q); } @@ -138,14 +141,17 @@ static appid_t __is_excluded(const struct qstr *app_name, userid_t user) appid_t is_excluded(const char *key, userid_t user) { struct qstr q; + qstr_init(&q, key); return __is_excluded(&q, user); } /* Kernel has already enforced everything we returned through * derive_permissions_locked(), so this is used to lock down access - * even further, such as enforcing that apps hold sdcard_rw. */ -int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name) { + * even further, such as enforcing that apps hold sdcard_rw. + */ +int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name) +{ struct qstr q_autorun = QSTR_LITERAL("autorun.inf"); struct qstr q__android_secure = QSTR_LITERAL(".android_secure"); struct qstr q_android_secure = QSTR_LITERAL("android_secure"); @@ -160,26 +166,26 @@ int check_caller_access_to_name(struct inode *parent_node, const struct qstr *na } /* Root always has access; access for any other UIDs should always - * be controlled through packages.list. */ - if (current_fsuid() == 0) { + * be controlled through packages.list. + */ + if (current_fsuid() == 0) return 1; - } /* No extra permissions to enforce */ return 1; } /* This function is used when file opening. The open flags must be - * checked before calling check_caller_access_to_name() */ -int open_flags_to_access_mode(int open_flags) { - if((open_flags & O_ACCMODE) == O_RDONLY) { + * checked before calling check_caller_access_to_name() + */ +int open_flags_to_access_mode(int open_flags) +{ + if ((open_flags & O_ACCMODE) == O_RDONLY) return 0; /* R_OK */ - } else if ((open_flags & O_ACCMODE) == O_WRONLY) { + if ((open_flags & O_ACCMODE) == O_WRONLY) return 1; /* W_OK */ - } else { - /* Probably O_RDRW, but treat as default to be safe */ + /* Probably O_RDRW, but treat as default to be safe */ return 1; /* R_OK | W_OK */ - } } static struct hashtable_entry *alloc_hashtable_entry(const struct qstr *key, @@ -371,7 +377,6 @@ static void remove_packagelist_entry(const struct qstr *key) remove_packagelist_entry_locked(key); fixup_all_perms_name(key); mutex_unlock(&sdcardfs_super_list_lock); - return; } static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) @@ -394,7 +399,6 @@ static void remove_ext_gid_entry(const struct qstr *key, gid_t group) mutex_lock(&sdcardfs_super_list_lock); remove_ext_gid_entry_locked(key, group); mutex_unlock(&sdcardfs_super_list_lock); - return; } static void remove_userid_all_entry_locked(userid_t userid) @@ -422,7 +426,6 @@ static void remove_userid_all_entry(userid_t userid) remove_userid_all_entry_locked(userid); fixup_all_perms_userid(userid); mutex_unlock(&sdcardfs_super_list_lock); - return; } static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t userid) @@ -447,7 +450,6 @@ static void remove_userid_exclude_entry(const struct qstr *key, userid_t userid) remove_userid_exclude_entry_locked(key, userid); fixup_all_perms_name_userid(key, userid); mutex_unlock(&sdcardfs_super_list_lock); - return; } static void packagelist_destroy(void) @@ -456,6 +458,7 @@ static void packagelist_destroy(void) struct hlist_node *h_t; HLIST_HEAD(free_list); int i; + mutex_lock(&sdcardfs_super_list_lock); hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { hash_del_rcu(&hash_cur->hlist); @@ -644,6 +647,7 @@ static struct config_item *extension_details_make_item(struct config_group *grou struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL); const char *tmp; int ret; + if (!extension_details) return ERR_PTR(-ENOMEM); @@ -698,6 +702,7 @@ static struct config_group *extensions_make_group(struct config_group *group, co static void extensions_drop_group(struct config_group *group, struct config_item *item) { struct extensions_value *value = to_extensions_value(item); + printk(KERN_INFO "sdcardfs: No longer mapping any files to gid %d\n", value->num); kfree(value); } @@ -851,6 +856,7 @@ static int configfs_sdcardfs_init(void) { int ret, i; struct configfs_subsystem *subsys = &sdcardfs_packages.subsystem; + for (i = 0; sd_default_groups[i]; i++) { config_group_init(sd_default_groups[i]); } @@ -881,7 +887,7 @@ int packagelist_init(void) } configfs_sdcardfs_init(); - return 0; + return 0; } void packagelist_exit(void) diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 2caee49aa8ec..b09584cb9a9c 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -87,11 +87,11 @@ } while (0) /* OVERRIDE_CRED() and REVERT_CRED() - * OVERRID_CRED() - * backup original task->cred - * and modifies task->cred->fsuid/fsgid to specified value. + * OVERRIDE_CRED() + * backup original task->cred + * and modifies task->cred->fsuid/fsgid to specified value. * REVERT_CRED() - * restore original task->cred->fsuid/fsgid. + * restore original task->cred->fsuid/fsgid. * These two macro should be used in pair, and OVERRIDE_CRED() should be * placed at the beginning of a function, right after variable declaration. */ @@ -114,27 +114,29 @@ /* Android 5.0 support */ /* Permission mode for a specific node. Controls how file permissions - * are derived for children nodes. */ + * are derived for children nodes. + */ typedef enum { - /* Nothing special; this node should just inherit from its parent. */ - PERM_INHERIT, - /* This node is one level above a normal root; used for legacy layouts - * which use the first level to represent user_id. */ - PERM_PRE_ROOT, - /* This node is "/" */ - PERM_ROOT, - /* This node is "/Android" */ - PERM_ANDROID, - /* This node is "/Android/data" */ - PERM_ANDROID_DATA, - /* This node is "/Android/obb" */ - PERM_ANDROID_OBB, - /* This node is "/Android/media" */ - PERM_ANDROID_MEDIA, - /* This node is "/Android/[data|media|obb]/[package]" */ - PERM_ANDROID_PACKAGE, - /* This node is "/Android/[data|media|obb]/[package]/cache" */ - PERM_ANDROID_PACKAGE_CACHE, + /* Nothing special; this node should just inherit from its parent. */ + PERM_INHERIT, + /* This node is one level above a normal root; used for legacy layouts + * which use the first level to represent user_id. + */ + PERM_PRE_ROOT, + /* This node is "/" */ + PERM_ROOT, + /* This node is "/Android" */ + PERM_ANDROID, + /* This node is "/Android/data" */ + PERM_ANDROID_DATA, + /* This node is "/Android/obb" */ + PERM_ANDROID_OBB, + /* This node is "/Android/media" */ + PERM_ANDROID_MEDIA, + /* This node is "/Android/[data|media|obb]/[package]" */ + PERM_ANDROID_PACKAGE, + /* This node is "/Android/[data|media|obb]/[package]/cache" */ + PERM_ANDROID_PACKAGE_CACHE, } perm_t; struct sdcardfs_sb_info; @@ -142,9 +144,9 @@ struct sdcardfs_mount_options; struct sdcardfs_inode_info; /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ -const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info); +const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_info *info); /* Do not directly use this function, use REVERT_CRED() instead. */ -void revert_fsids(const struct cred * old_cred); +void revert_fsids(const struct cred *old_cred); /* operations vectors defined in specific files */ extern const struct file_operations sdcardfs_main_fops; @@ -221,7 +223,8 @@ struct sdcardfs_sb_info { struct super_block *sb; struct super_block *lower_sb; /* derived perm policy : some of options have been added - * to sdcardfs_mount_options (Android 4.4 support) */ + * to sdcardfs_mount_options (Android 4.4 support) + */ struct sdcardfs_mount_options options; spinlock_t lock; /* protects obbpath */ char *obbpath_s; @@ -332,7 +335,7 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ { \ struct path pname; \ spin_lock(&SDCARDFS_D(dent)->lock); \ - if(SDCARDFS_D(dent)->pname.dentry) { \ + if (SDCARDFS_D(dent)->pname.dentry) { \ pathcpy(&pname, &SDCARDFS_D(dent)->pname); \ SDCARDFS_D(dent)->pname.dentry = NULL; \ SDCARDFS_D(dent)->pname.mnt = NULL; \ @@ -348,17 +351,17 @@ SDCARDFS_DENT_FUNC(orig_path) static inline bool sbinfo_has_sdcard_magic(struct sdcardfs_sb_info *sbinfo) { - return sbinfo && sbinfo->sb && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC; + return sbinfo && sbinfo->sb && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC; } /* grab a refererence if we aren't linking to ourself */ static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top) { struct inode *old_top = NULL; + BUG_ON(IS_ERR_OR_NULL(top)); - if (info->top && info->top != &info->vfs_inode) { + if (info->top && info->top != &info->vfs_inode) old_top = info->top; - } if (top != &info->vfs_inode) igrab(top); info->top = top; @@ -368,11 +371,11 @@ static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top) static inline struct inode *grab_top(struct sdcardfs_inode_info *info) { struct inode *top = info->top; - if (top) { + + if (top) return igrab(top); - } else { + else return NULL; - } } static inline void release_top(struct sdcardfs_inode_info *info) @@ -380,21 +383,24 @@ static inline void release_top(struct sdcardfs_inode_info *info) iput(info->top); } -static inline int get_gid(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { +static inline int get_gid(struct vfsmount *mnt, struct sdcardfs_inode_info *info) +{ struct sdcardfs_vfsmount_options *opts = mnt->data; - if (opts->gid == AID_SDCARD_RW) { + if (opts->gid == AID_SDCARD_RW) /* As an optimization, certain trusted system components only run * as owner but operate across all users. Since we're now handing * out the sdcard_rw GID only to trusted apps, we're okay relaxing * the user boundary enforcement for the default view. The UIDs - * assigned to app directories are still multiuser aware. */ + * assigned to app directories are still multiuser aware. + */ return AID_SDCARD_RW; - } else { + else return multiuser_get_uid(info->userid, opts->gid); - } } -static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { + +static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *info) +{ int owner_mode; int filtered_mode; struct sdcardfs_vfsmount_options *opts = mnt->data; @@ -403,17 +409,18 @@ static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *inf if (info->perm == PERM_PRE_ROOT) { /* Top of multi-user view should always be visible to ensure - * secondary users can traverse inside. */ + * secondary users can traverse inside. + */ visible_mode = 0711; } else if (info->under_android) { /* Block "other" access to Android directories, since only apps * belonging to a specific user should be in there; we still - * leave +x open for the default view. */ - if (opts->gid == AID_SDCARD_RW) { + * leave +x open for the default view. + */ + if (opts->gid == AID_SDCARD_RW) visible_mode = visible_mode & ~0006; - } else { + else visible_mode = visible_mode & ~0007; - } } owner_mode = info->lower_inode->i_mode & 0700; filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6)); @@ -438,7 +445,7 @@ static inline void sdcardfs_get_real_lower(const struct dentry *dent, /* in case of a local obb dentry * the orig_path should be returned */ - if(has_graft_path(dent)) + if (has_graft_path(dent)) sdcardfs_get_orig_path(dent, real_lower); else sdcardfs_get_lower_path(dent, real_lower); @@ -447,7 +454,7 @@ static inline void sdcardfs_get_real_lower(const struct dentry *dent, static inline void sdcardfs_put_real_lower(const struct dentry *dent, struct path *real_lower) { - if(has_graft_path(dent)) + if (has_graft_path(dent)) sdcardfs_put_orig_path(dent, real_lower); else sdcardfs_put_lower_path(dent, real_lower); @@ -460,7 +467,7 @@ extern struct list_head sdcardfs_super_list; extern appid_t get_appid(const char *app_name); extern appid_t get_ext_gid(const char *app_name); extern appid_t is_excluded(const char *app_name, userid_t userid); -extern int check_caller_access_to_name(struct inode *parent_node, const struct qstr* name); +extern int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name); extern int open_flags_to_access_mode(int open_flags); extern int packagelist_init(void); extern void packagelist_exit(void); @@ -481,7 +488,7 @@ extern void get_derived_permission_new(struct dentry *parent, struct dentry *den extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); extern void update_derived_permission_lock(struct dentry *dentry); -void fixup_lower_ownership(struct dentry* dentry, const char *name); +void fixup_lower_ownership(struct dentry *dentry, const char *name); extern int need_graft_path(struct dentry *dentry); extern int is_base_obbpath(struct dentry *dentry); extern int is_obbpath_invalid(struct dentry *dentry); @@ -491,6 +498,7 @@ extern int setup_obb_dentry(struct dentry *dentry, struct path *lower_path); static inline struct dentry *lock_parent(struct dentry *dentry) { struct dentry *dir = dget_parent(dentry); + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); return dir; } @@ -610,7 +618,8 @@ static inline bool str_case_eq(const char *s1, const char *s2) return !strcasecmp(s1, s2); } -static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) { +static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) +{ return !strncasecmp(s1, s2, len); } diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index edda32b68dc0..a4629f20812e 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -36,7 +36,7 @@ static void sdcardfs_put_super(struct super_block *sb) if (!spd) return; - if(spd->obbpath_s) { + if (spd->obbpath_s) { kfree(spd->obbpath_s); path_put(&spd->obbpath); } @@ -125,29 +125,33 @@ static int sdcardfs_remount_fs2(struct vfsmount *mnt, struct super_block *sb, * SILENT, but anything else left over is an error. */ if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT | MS_REMOUNT)) != 0) { - printk(KERN_ERR - "sdcardfs: remount flags 0x%x unsupported\n", *flags); + pr_err("sdcardfs: remount flags 0x%x unsupported\n", *flags); err = -EINVAL; } - printk(KERN_INFO "Remount options were %s for vfsmnt %p.\n", options, mnt); + pr_info("Remount options were %s for vfsmnt %p.\n", options, mnt); err = parse_options_remount(sb, options, *flags & ~MS_SILENT, mnt->data); return err; } -static void* sdcardfs_clone_mnt_data(void *data) { - struct sdcardfs_vfsmount_options* opt = kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); - struct sdcardfs_vfsmount_options* old = data; - if(!opt) return NULL; +static void *sdcardfs_clone_mnt_data(void *data) +{ + struct sdcardfs_vfsmount_options *opt = kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); + struct sdcardfs_vfsmount_options *old = data; + + if (!opt) + return NULL; opt->gid = old->gid; opt->mask = old->mask; return opt; } -static void sdcardfs_copy_mnt_data(void *data, void *newdata) { - struct sdcardfs_vfsmount_options* old = data; - struct sdcardfs_vfsmount_options* new = newdata; +static void sdcardfs_copy_mnt_data(void *data, void *newdata) +{ + struct sdcardfs_vfsmount_options *old = data; + struct sdcardfs_vfsmount_options *new = newdata; + old->gid = new->gid; old->mask = new->mask; } @@ -235,7 +239,8 @@ static void sdcardfs_umount_begin(struct super_block *sb) lower_sb->s_op->umount_begin(lower_sb); } -static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, struct dentry *root) +static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, + struct dentry *root) { struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb); struct sdcardfs_mount_options *opts = &sbi->options; From 489c07660e80943260a3d269644e7052557daff4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 16 Mar 2017 19:33:35 -0700 Subject: [PATCH 191/281] ANDROID: sdcardfs: Fix style issues with comments Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: I8791ef7eac527645ecb9407908e7e5ece35b8f80 --- fs/sdcardfs/dentry.c | 16 +--------------- fs/sdcardfs/derived_perm.c | 9 +++------ fs/sdcardfs/main.c | 2 +- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index 3a213c75420f..f58ba5908ff6 100755 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -127,12 +127,10 @@ static int sdcardfs_hash_ci(const struct dentry *dentry, unsigned long hash; name = qstr->name; - //len = vfat_striptail_len(qstr); len = qstr->len; hash = init_name_hash(); while (len--) - //hash = partial_name_hash(nls_tolower(t, *name++), hash); hash = partial_name_hash(tolower(*name++), hash); qstr->hash = end_name_hash(hash); @@ -147,20 +145,8 @@ static int sdcardfs_cmp_ci(const struct dentry *parent, const struct dentry *dentry, const struct inode *inode, unsigned int len, const char *str, const struct qstr *name) { - /* This function is copy of vfat_cmpi */ - // FIXME Should we support national language? - //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; - //unsigned int alen, blen; + /* FIXME Should we support national language? */ - /* A filename cannot end in '.' or we treat it like it has none */ - /* - alen = vfat_striptail_len(name); - blen = __vfat_striptail_len(len, str); - if (alen == blen) { - if (nls_strnicmp(t, name->name, str, alen) == 0) - return 0; - } - */ if (name->len == len) { if (str_n_case_eq(name->name, str, len)) return 0; diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 8d5c1fdcdfe3..2da612e39fa6 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -318,9 +318,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ - if (IS_ROOT(dentry)) { - //setup_default_pre_root_state(dentry->d_inode); - } else { + if (!IS_ROOT(dentry)) { parent = dget_parent(dentry); if (parent) { get_derived_permission(parent, dentry); @@ -370,7 +368,6 @@ int is_obbpath_invalid(struct dentry *dent) ret = 1; } else { path_get(&di->lower_path); - //lower_parent = lock_parent(lower_path->dentry); path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); if (!path_buf) { @@ -385,7 +382,6 @@ int is_obbpath_invalid(struct dentry *dent) kfree(path_buf); } - //unlock_dir(lower_parent); pathcpy(&lower_path, &di->lower_path); need_put = 1; } @@ -431,7 +427,8 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) /* A local obb dentry must have its own orig_path to support rmdir * and mkdir of itself. Usually, we expect that the sbi->obbpath - * is avaiable on this stage. */ + * is avaiable on this stage. + */ sdcardfs_set_orig_path(dentry, lower_path); err = kern_path(sbi->obbpath_s, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 4a04c91ab456..c2159accc4e9 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -29,7 +29,7 @@ enum { Opt_gid, Opt_debug, Opt_mask, - Opt_multiuser, // May need? + Opt_multiuser, Opt_userid, Opt_reserved_mb, Opt_err, From a38c37445dad314423083a844601d9d60e7c8608 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 Mar 2017 16:29:13 -0700 Subject: [PATCH 192/281] ANDROID: sdcardfs: remove unneeded null check As pointed out by checkpatch, these functions already handle null inputs, so the checks are not needed. Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: I189342f032dfcefee36b27648bb512488ad61d20 --- fs/sdcardfs/lookup.c | 3 +-- fs/sdcardfs/packagelist.c | 3 +-- fs/sdcardfs/super.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 832d1b886b49..9b35b829931d 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -36,8 +36,7 @@ int sdcardfs_init_dentry_cache(void) void sdcardfs_destroy_dentry_cache(void) { - if (sdcardfs_dentry_cachep) - kmem_cache_destroy(sdcardfs_dentry_cachep); + kmem_cache_destroy(sdcardfs_dentry_cachep); } void free_dentry_private_data(struct dentry *dentry) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index e5a56c94e404..a3fd6967daaf 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -894,6 +894,5 @@ void packagelist_exit(void) { configfs_sdcardfs_exit(); packagelist_destroy(); - if (hashtable_entry_cachep) - kmem_cache_destroy(hashtable_entry_cachep); + kmem_cache_destroy(hashtable_entry_cachep); } diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index a4629f20812e..7d3c331379f5 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -222,8 +222,7 @@ int sdcardfs_init_inode_cache(void) /* sdcardfs inode cache destructor */ void sdcardfs_destroy_inode_cache(void) { - if (sdcardfs_inode_cachep) - kmem_cache_destroy(sdcardfs_inode_cachep); + kmem_cache_destroy(sdcardfs_inode_cachep); } /* From 014bf25c54016b36dcf6e2c5bc6e17db11be9166 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 16 Mar 2017 17:46:13 -0700 Subject: [PATCH 193/281] ANDROID: sdcardfs: Use pr_[...] instead of printk Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: Ibc635ec865750530d32b87067779f681fe58a003 --- fs/sdcardfs/derived_perm.c | 6 ++--- fs/sdcardfs/file.c | 9 ++++---- fs/sdcardfs/inode.c | 8 +++---- fs/sdcardfs/lookup.c | 2 +- fs/sdcardfs/main.c | 45 +++++++++++++++++--------------------- fs/sdcardfs/packagelist.c | 16 +++++++------- fs/sdcardfs/sdcardfs.h | 2 +- fs/sdcardfs/super.c | 5 ++--- 8 files changed, 43 insertions(+), 50 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 2da612e39fa6..78f0d2e29c7d 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -311,7 +311,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) struct dentry *parent; if (!dentry || !dentry->d_inode) { - printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__); + pr_err("sdcardfs: %s: invalid dentry\n", __func__); return; } /* FIXME: @@ -372,7 +372,7 @@ int is_obbpath_invalid(struct dentry *dent) path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); if (!path_buf) { ret = 1; - printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__); + pr_err("sdcardfs: fail to allocate path_buf in %s.\n", __func__); } else { obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); if (d_unhashed(di->lower_path.dentry) || @@ -444,7 +444,7 @@ int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) * because the sdcard daemon also regards this case as * a lookup fail. */ - printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); + pr_info("sdcardfs: the sbi->obbpath is not available\n"); } return err; } diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index ab78bb854c9f..42f66f2425be 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -65,7 +65,7 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, /* check disk space */ if (!check_min_free_space(dentry, count, 0)) { - printk(KERN_INFO "No minimum free space.\n"); + pr_err("No minimum free space.\n"); return -ENOSPC; } @@ -160,8 +160,7 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) lower_file = sdcardfs_lower_file(file); if (willwrite && !lower_file->f_mapping->a_ops->writepage) { err = -EINVAL; - printk(KERN_ERR "sdcardfs: lower file system does not " - "support writeable mmap\n"); + pr_err("sdcardfs: lower file system does not support writeable mmap\n"); goto out; } @@ -173,14 +172,14 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) if (!SDCARDFS_F(file)->lower_vm_ops) { err = lower_file->f_op->mmap(lower_file, vma); if (err) { - printk(KERN_ERR "sdcardfs: lower mmap failed %d\n", err); + pr_err("sdcardfs: lower mmap failed %d\n", err); goto out; } saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ err = do_munmap(current->mm, vma->vm_start, vma->vm_end - vma->vm_start); if (err) { - printk(KERN_ERR "sdcardfs: do_munmap failed %d\n", err); + pr_err("sdcardfs: do_munmap failed %d\n", err); goto out; } } diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index c2f2dd929154..71694c0e9f14 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -248,7 +248,7 @@ static int touch(char *abs_path, mode_t mode) if (PTR_ERR(filp) == -EEXIST) { return 0; } else { - printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n", + pr_err("sdcardfs: failed to open(%s): %ld\n", abs_path, PTR_ERR(filp)); return PTR_ERR(filp); } @@ -284,7 +284,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* check disk space */ if (!check_min_free_space(dentry, 0, 1)) { - printk(KERN_INFO "sdcardfs: No minimum free space.\n"); + pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; goto out_revert; } @@ -360,7 +360,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode set_fs_pwd(current->fs, &lower_path); touch_err = touch(".nomedia", 0664); if (touch_err) { - printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n", + pr_err("sdcardfs: failed to create .nomedia in %s: %d\n", lower_path.dentry->d_name.name, touch_err); goto out; } @@ -654,7 +654,7 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma release_top(SDCARDFS_I(inode)); tmp.i_sb = inode->i_sb; if (IS_POSIXACL(inode)) - printk(KERN_WARNING "%s: This may be undefined behavior... \n", __func__); + pr_warn("%s: This may be undefined behavior...\n", __func__); err = generic_permission(&tmp, mask); /* XXX * Original sdcardfs code calls inode_permission(lower_inode,.. ) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 9b35b829931d..be0a731ff7c3 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -322,7 +322,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, * because the sdcard daemon also regards this case as * a lookup fail. */ - printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); + pr_info("sdcardfs: base obbpath is not available\n"); sdcardfs_put_reset_orig_path(dentry); goto out; } diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index c2159accc4e9..fe5eb9397a6f 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -117,19 +117,17 @@ static int parse_options(struct super_block *sb, char *options, int silent, break; /* unknown option */ default: - if (!silent) { - printk( KERN_ERR "Unrecognized mount option \"%s\" " - "or missing value", p); - } + if (!silent) + pr_err("Unrecognized mount option \"%s\" or missing value", p); return -EINVAL; } } if (*debug) { - printk( KERN_INFO "sdcardfs : options - debug:%d\n", *debug); - printk( KERN_INFO "sdcardfs : options - uid:%d\n", + pr_info("sdcardfs : options - debug:%d\n", *debug); + pr_info("sdcardfs : options - uid:%d\n", opts->fs_low_uid); - printk( KERN_INFO "sdcardfs : options - gid:%d\n", + pr_info("sdcardfs : options - gid:%d\n", opts->fs_low_gid); } @@ -175,22 +173,20 @@ int parse_options_remount(struct super_block *sb, char *options, int silent, case Opt_fsuid: case Opt_fsgid: case Opt_reserved_mb: - printk( KERN_WARNING "Option \"%s\" can't be changed during remount\n", p); + pr_warn("Option \"%s\" can't be changed during remount\n", p); break; /* unknown option */ default: - if (!silent) { - printk( KERN_ERR "Unrecognized mount option \"%s\" " - "or missing value", p); - } + if (!silent) + pr_err("Unrecognized mount option \"%s\" or missing value", p); return -EINVAL; } } if (debug) { - printk( KERN_INFO "sdcardfs : options - debug:%d\n", debug); - printk( KERN_INFO "sdcardfs : options - gid:%d\n", vfsopts->gid); - printk( KERN_INFO "sdcardfs : options - mask:%d\n", vfsopts->mask); + pr_info("sdcardfs : options - debug:%d\n", debug); + pr_info("sdcardfs : options - gid:%d\n", vfsopts->gid); + pr_info("sdcardfs : options - mask:%d\n", vfsopts->mask); } return 0; @@ -244,31 +240,30 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, struct sdcardfs_vfsmount_options *mnt_opt = mnt->data; struct inode *inode; - printk(KERN_INFO "sdcardfs version 2.0\n"); + pr_info("sdcardfs version 2.0\n"); if (!dev_name) { - printk(KERN_ERR - "sdcardfs: read_super: missing dev_name argument\n"); + pr_err("sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } - printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); - printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); - printk(KERN_INFO "sdcardfs: mnt -> %p\n", mnt); + pr_info("sdcardfs: dev_name -> %s\n", dev_name); + pr_info("sdcardfs: options -> %s\n", (char *)raw_data); + pr_info("sdcardfs: mnt -> %p\n", mnt); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { - printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name); + pr_err("sdcardfs: error accessing lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { - printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); + pr_crit("sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } @@ -277,7 +272,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* parse options */ err = parse_options(sb, raw_data, silent, &debug, mnt_opt, &sb_info->options); if (err) { - printk(KERN_ERR "sdcardfs: invalid options\n"); + pr_err("sdcardfs: invalid options\n"); goto out_freesbi; } @@ -347,7 +342,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, mutex_unlock(&sdcardfs_super_list_lock); if (!silent) - printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", + pr_info("sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; /* all is well */ diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index a3fd6967daaf..7f8c9e247f21 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -472,7 +472,7 @@ static void packagelist_destroy(void) hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) free_hashtable_entry(hash_cur); mutex_unlock(&sdcardfs_super_list_lock); - printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); + pr_info("sdcardfs: destroyed packagelist pkgld\n"); } struct package_details { @@ -568,7 +568,8 @@ static ssize_t package_details_clear_userid_store(struct package_details *packag static void package_details_release(struct config_item *item) { struct package_details *package_details = to_package_details(item); - printk(KERN_INFO "sdcardfs: removing %s\n", package_details->name.name); + + pr_info("sdcardfs: removing %s\n", package_details->name.name); remove_packagelist_entry(&package_details->name); kfree(package_details->name.name); kfree(package_details); @@ -625,7 +626,7 @@ static void extension_details_release(struct config_item *item) { struct extension_details *extension_details = to_extension_details(item); - printk(KERN_INFO "sdcardfs: No longer mapping %s files to gid %d\n", + pr_info("sdcardfs: No longer mapping %s files to gid %d\n", extension_details->name.name, extension_details->num); remove_ext_gid_entry(&extension_details->name, extension_details->num); kfree(extension_details->name.name); @@ -703,7 +704,7 @@ static void extensions_drop_group(struct config_group *group, struct config_item { struct extensions_value *value = to_extensions_value(item); - printk(KERN_INFO "sdcardfs: No longer mapping any files to gid %d\n", value->num); + pr_info("sdcardfs: No longer mapping any files to gid %d\n", value->num); kfree(value); } @@ -857,14 +858,13 @@ static int configfs_sdcardfs_init(void) int ret, i; struct configfs_subsystem *subsys = &sdcardfs_packages.subsystem; - for (i = 0; sd_default_groups[i]; i++) { + for (i = 0; sd_default_groups[i]; i++) config_group_init(sd_default_groups[i]); - } config_group_init(&subsys->su_group); mutex_init(&subsys->su_mutex); ret = configfs_register_subsystem(subsys); if (ret) { - printk(KERN_ERR "Error %d while registering subsystem %s\n", + pr_err("Error %d while registering subsystem %s\n", ret, subsys->su_group.cg_item.ci_namebuf); } @@ -882,7 +882,7 @@ int packagelist_init(void) kmem_cache_create("packagelist_hashtable_entry", sizeof(struct hashtable_entry), 0, 0, NULL); if (!hashtable_entry_cachep) { - printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); + pr_err("sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); return -ENOMEM; } diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index b09584cb9a9c..53fcd23f467f 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -53,7 +53,7 @@ #define SDCARDFS_ROOT_INO 1 /* useful for tracking code reachability */ -#define UDBG printk(KERN_DEFAULT "DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__) +#define UDBG pr_default("DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__) #define SDCARDFS_DIRENT_SIZE 256 diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 7d3c331379f5..67b4ae24337a 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -64,7 +64,7 @@ static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf) if (sbi->options.reserved_mb) { /* Invalid statfs informations. */ if (buf->f_bsize == 0) { - printk(KERN_ERR "Returned block size is zero.\n"); + pr_err("Returned block size is zero.\n"); return -EINVAL; } @@ -100,8 +100,7 @@ static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options * SILENT, but anything else left over is an error. */ if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT)) != 0) { - printk(KERN_ERR - "sdcardfs: remount flags 0x%x unsupported\n", *flags); + pr_err("sdcardfs: remount flags 0x%x unsupported\n", *flags); err = -EINVAL; } From 5d72cf5799bd96c5b50df1940b5815a05fc4e6fe Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 16 Mar 2017 19:32:59 -0700 Subject: [PATCH 194/281] ANDROID: sdcardfs: Use to kstrout Switch from deprecated simple_strtoul to kstrout Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: If18bd133b4d2877f71e58b58fc31371ff6613ed5 --- fs/sdcardfs/derived_perm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 78f0d2e29c7d..668b83f1c1db 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -60,6 +60,8 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); appid_t appid; + unsigned long user_num; + int err; struct qstr q_Android = QSTR_LITERAL("Android"); struct qstr q_data = QSTR_LITERAL("data"); struct qstr q_obb = QSTR_LITERAL("obb"); @@ -88,7 +90,11 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ info->perm = PERM_ROOT; - info->userid = simple_strtoul(name->name, NULL, 10); + err = kstrtoul(name->name, 10, &user_num); + if (err) + info->userid = 0; + else + info->userid = user_num; set_top(info, &info->vfs_inode); break; case PERM_ROOT: From d58121d8193799a761d4a56c65ceb1b7f68311ca Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 Mar 2017 17:27:40 -0700 Subject: [PATCH 195/281] ANDROID: sdcardfs: Use seq_puts over seq_printf Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: I3795ec61ce61e324738815b1ce3b0e09b25d723f --- fs/sdcardfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 67b4ae24337a..a3393e959c63 100755 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -251,7 +251,7 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, if (vfsopts->gid != 0) seq_printf(m, ",gid=%u", vfsopts->gid); if (opts->multiuser) - seq_printf(m, ",multiuser"); + seq_puts(m, ",multiuser"); if (vfsopts->mask) seq_printf(m, ",mask=%u", vfsopts->mask); if (opts->fs_user_id) From 8e915a2e6ce2926607c64ab18d0f02834d102562 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 21 Mar 2017 19:11:38 -0700 Subject: [PATCH 196/281] ANDROID: sdcardfs: Fix style issues in macros Signed-off-by: Daniel Rosenberg Bug: 35331000 Change-Id: I89c4035029dc2236081a7685c55cac595d9e7ebf --- fs/sdcardfs/packagelist.c | 4 ++-- fs/sdcardfs/sdcardfs.h | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 7f8c9e247f21..27205cdb8cad 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -488,7 +488,7 @@ static inline struct package_details *to_package_details(struct config_item *ite CONFIGFS_ATTR_STRUCT(package_details); #define PACKAGE_DETAILS_ATTR(_name, _mode, _show, _store) \ struct package_details_attribute package_details_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) -#define PACKAGE_DETAILS_ATTRIBUTE(name) &package_details_attr_##name.attr +#define PACKAGE_DETAILS_ATTRIBUTE(name) (&package_details_attr_##name.attr) static ssize_t package_details_appid_show(struct package_details *package_details, char *page) @@ -738,7 +738,7 @@ CONFIGFS_ATTR_STRUCT(packages); #define PACKAGES_ATTR(_name, _mode, _show, _store) \ struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) #define PACKAGES_ATTR_RO(_name, _show) \ -struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR_RO(_name, _show); +struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR_RO(_name, _show) static struct config_item *packages_make_item(struct config_group *group, const char *name) { diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 53fcd23f467f..41483adc852a 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -96,21 +96,21 @@ * placed at the beginning of a function, right after variable declaration. */ #define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \ - saved_cred = override_fsids(sdcardfs_sbi, info); \ - if (!saved_cred) { return -ENOMEM; } + do { \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ + if (!saved_cred) \ + return -ENOMEM; \ + } while (0) #define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \ - saved_cred = override_fsids(sdcardfs_sbi, info); \ - if (!saved_cred) { return ERR_PTR(-ENOMEM); } + do { \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ + if (!saved_cred) \ + return ERR_PTR(-ENOMEM); \ + } while (0) #define REVERT_CRED(saved_cred) revert_fsids(saved_cred) -#define DEBUG_CRED() \ - printk("KAKJAGI: %s:%d fsuid %d fsgid %d\n", \ - __FUNCTION__, __LINE__, \ - (int)current->cred->fsuid, \ - (int)current->cred->fsgid); - /* Android 5.0 support */ /* Permission mode for a specific node. Controls how file permissions From 979acff8bebe3a7570719667b10663a89cb8fe6d Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 14 Feb 2017 20:47:17 -0800 Subject: [PATCH 197/281] ANDROID: sdcardfs: Fix incorrect hash This adds back the hash calculation removed as part of the previous patch, as it is in fact necessary. Signed-off-by: Daniel Rosenberg Bug: 35307857 Change-Id: Ie607332bcf2c5d2efdf924e4060ef3f576bf25dc --- fs/sdcardfs/lookup.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index be0a731ff7c3..c2f29d95f06f 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -243,6 +243,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct dentry *lower_dentry; const struct qstr *name; struct path lower_path; + struct qstr dname; struct sdcardfs_sb_info *sbi; sbi = SDCARDFS_SB(dentry->d_sb); @@ -343,11 +344,14 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, goto out; /* instatiate a new negative dentry */ - lower_dentry = d_lookup(lower_dir_dentry, name); + dname.name = name->name; + dname.len = name->len; + dname.hash = full_name_hash(dname.name, dname.len); + lower_dentry = d_lookup(lower_dir_dentry, &dname); if (lower_dentry) goto setup_lower; - lower_dentry = d_alloc(lower_dir_dentry, name); + lower_dentry = d_alloc(lower_dir_dentry, &dname); if (!lower_dentry) { err = -ENOMEM; goto out; From 3e4bc8c63fd2b67e34e5aa42496b819e5bf395f3 Mon Sep 17 00:00:00 2001 From: Alberto97 Date: Tue, 28 Mar 2017 15:47:56 +0200 Subject: [PATCH 198/281] harpia: Enable CONFIG_INET_DIAG_DESTROY Change-Id: Ic8c2cbc35ef1b335b3006ce35387c7634629862d --- arch/arm/configs/harpia_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/harpia_defconfig b/arch/arm/configs/harpia_defconfig index 4a9c0a6b5bd0..6f553fe6b200 100644 --- a/arch/arm/configs/harpia_defconfig +++ b/arch/arm/configs/harpia_defconfig @@ -696,7 +696,7 @@ CONFIG_INET_LRO=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set -# CONFIG_INET_DIAG_DESTROY is not set +CONFIG_INET_DIAG_DESTROY=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" From c70c3bc2a5ff319aa9a54a292ceefd19010eea36 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 Jul 2016 14:26:24 -0400 Subject: [PATCH 199/281] UPSTREAM: udp: properly support MSG_PEEK with truncated buffers commit 197c949e7798fbf28cfadc69d9ca0c2abbf93191 upstream. Backport of this upstream commit into stable kernels : 89c22d8c3b27 ("net: Fix skb csum races when peeking") exposed a bug in udp stack vs MSG_PEEK support, when user provides a buffer smaller than skb payload. In this case, skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); returns -EFAULT. This bug does not happen in upstream kernels since Al Viro did a great job to replace this into : skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg); This variant is safe vs short buffers. For the time being, instead reverting Herbert Xu patch and add back skb->ip_summed invalid changes, simply store the result of udp_lib_checksum_complete() so that we avoid computing the checksum a second time, and avoid the problematic skb_copy_and_csum_datagram_iovec() call. This patch can be applied on recent kernels as it avoids a double checksumming, then backported to stable kernels as a bug fix. Signed-off-by: Eric Dumazet Acked-by: Herbert Xu Signed-off-by: David S. Miller [ luis: backported to 3.16: adjusted context ] Signed-off-by: Luis Henriques Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau (cherry picked from commit 98f57e42cab062608cf3dce2b8eecbb2a0780ac4) Bug: 32813456 Change-Id: I1687be975563a9456ca3ea74bbc01d18d845ebdf --- net/ipv4/udp.c | 6 ++++-- net/ipv6/udp.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0a36567807dc..80f09a3ca922 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1209,6 +1209,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; bool slow; if (flags & MSG_ERRQUEUE) @@ -1234,11 +1235,12 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 19beecacb0ac..62ab2047218a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -370,6 +370,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); + bool checksum_valid = false; int is_udp4; bool slow; @@ -401,11 +402,12 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, */ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) + checksum_valid = !udp_lib_checksum_complete(skb); + if (!checksum_valid) goto csum_copy_err; } - if (skb_csum_unnecessary(skb)) + if (checksum_valid || skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); else { From 3ae1eb3c7ebb0dc9bb2a221878ec62b05a0e4e63 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Thu, 19 Jan 2017 14:59:44 -0800 Subject: [PATCH 200/281] crypto: msm: check integer overflow on total data len in qcedev.c qcedev_vbuf_ablk_cipher will calculate total data length. It starts with the value of "areq->cipher_op_req.byteoffset", which is controlled by the user. Make change to check if this total data length has integer overflow issue in qcedev_check_cipher_params. Change-Id: Ice42dca6d47eb8febfe8a34e566c69e4799fab57 Signed-off-by: Zhen Kong --- drivers/crypto/msm/qcedev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 3767393a037b..1941594101f2 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1463,6 +1463,15 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, pr_err("%s: Invalid byte offset\n", __func__); goto error; } + total = req->byteoffset; + for (i = 0; i < req->entries; i++) { + if (total > U32_MAX - req->vbuf.src[i].len) { + pr_err("%s:Integer overflow on total src len\n", + __func__); + goto error; + } + total += req->vbuf.src[i].len; + } } if (req->data_len < req->byteoffset) { @@ -1498,7 +1507,7 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, } } /* Check for sum of all dst length is equal to data_len */ - for (i = 0; i < req->entries; i++) { + for (i = 0, total = 0; i < req->entries; i++) { if (req->vbuf.dst[i].len >= U32_MAX - total) { pr_err("%s: Integer overflow on total req dst vbuf length\n", __func__); From 0ebd4520e9f04c53fa1c3d7a7352550b13e7108b Mon Sep 17 00:00:00 2001 From: Shalini Krishnamoorthi Date: Thu, 30 Jun 2016 14:00:04 -0700 Subject: [PATCH 201/281] msm: mdss: Correct the format specifiers in sscanf function In many parts of the code the sscanf function was getting an unsigned integer with a wrong format specifier. Changed the format specifiers appropriately. Single variable sscanf were replaced by kstrtouint at reported places. CRs-Fixed: 1024872 Change-Id: I03ce718b0456d437d31d701586965d0aa7443b51 Signed-off-by: Shalini Krishnamoorthi --- drivers/video/msm/mdss/mdss_debug.c | 6 +++--- drivers/video/msm/mdss/mdss_mdp.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c index 67ec0bfc54ae..1368edd7e1e1 100644 --- a/drivers/video/msm/mdss/mdss_debug.c +++ b/drivers/video/msm/mdss/mdss_debug.c @@ -309,11 +309,11 @@ static ssize_t mdss_debug_factor_write(struct file *file, if (strnchr(buf, count, '/')) { /* Parsing buf as fraction */ - if (sscanf(buf, "%d/%d", &numer, &denom) != 2) + if (sscanf(buf, "%u/%u", &numer, &denom) != 2) return -EFAULT; } else { /* Parsing buf as percentage */ - if (sscanf(buf, "%d", &numer) != 1) + if (kstrtouint(buf, 0, &numer)) return -EFAULT; denom = 100; } @@ -620,7 +620,7 @@ static ssize_t mdss_debug_perf_bw_limit_write(struct file *file, if (strnchr(buf, count, ' ')) { /* Parsing buf */ - if (sscanf(buf, "%d %d", &mode, &val) != 2) + if (sscanf(buf, "%u %u", &mode, &val) != 2) return -EFAULT; } diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c index 632ffb7dad19..27a28f3b0acb 100644 --- a/drivers/video/msm/mdss/mdss_mdp.c +++ b/drivers/video/msm/mdss/mdss_mdp.c @@ -1440,7 +1440,7 @@ static ssize_t mdss_mdp_store_max_limit_bw(struct device *dev, struct mdss_data_type *mdata = dev_get_drvdata(dev); u32 data = 0; - if (1 != sscanf(buf, "%d", &data)) { + if (kstrtouint(buf, 0, &data)) { pr_info("Not able scan to bw_mode_bitmap\n"); } else { mdata->bw_mode_bitmap = data; From 66fb1ebb6d197d2a92ded8fe86be1b335c3229c1 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Thu, 26 Nov 2015 10:11:07 +0530 Subject: [PATCH 202/281] avtimer: update ioctl call to query avtimer current avtimer ioctl uses deprecated logic to query avtimer. Use the updated API to query avtimer to avoid wrong timestamp values when query using ioctl interface. Change-Id: I16e4373226903b6121c911ed9f2ca31851de80e5 Signed-off-by: Laxminath Kasam --- drivers/platform/msm/avtimer.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index 0a5aece5ab68..d6b6fc061104 100644 --- a/drivers/platform/msm/avtimer.c +++ b/drivers/platform/msm/avtimer.c @@ -306,7 +306,8 @@ int avcs_core_query_timer(uint64_t *avtimer_tick) | avtimer_lsw; res = do_div(avtimer_tick_temp, avtimer.clk_div); *avtimer_tick = avtimer_tick_temp; - pr_debug("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n", __func__, + pr_debug_ratelimited("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n", + __func__, avtimer_msw, avtimer_lsw, *avtimer_tick); return 0; } @@ -331,21 +332,11 @@ static long avtimer_ioctl(struct file *file, unsigned int ioctl_num, switch (ioctl_num) { case IOCTL_GET_AVTIMER_TICK: { - uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0; - uint32_t avtimer_msw_2nd = 0; uint64_t avtimer_tick; - do { - avtimer_msw_1st = ioread32(avtimer.p_avtimer_msw); - avtimer_lsw = ioread32(avtimer.p_avtimer_lsw); - avtimer_msw_2nd = ioread32(avtimer.p_avtimer_msw); - } while (avtimer_msw_1st != avtimer_msw_2nd); - - avtimer_lsw = avtimer_lsw/avtimer.clk_div; - avtimer_tick = - ((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw; - - pr_debug("%s: AV Timer tick: msw: %x, lsw: %x time %llx\n", - __func__, avtimer_msw_1st, avtimer_lsw, avtimer_tick); + + avcs_core_query_timer(&avtimer_tick); + pr_debug_ratelimited("%s: AV Timer tick: time %llx\n", + __func__, avtimer_tick); if (copy_to_user((void *) ioctl_param, &avtimer_tick, sizeof(avtimer_tick))) { pr_err("copy_to_user failed\n"); From bc0db5d753e05d3adeba7b8bf2962ec25b712335 Mon Sep 17 00:00:00 2001 From: Xiaoyu Ye Date: Wed, 7 Dec 2016 16:35:07 -0800 Subject: [PATCH 203/281] drivers: soc: qcom: Add error handling in function avtimer_ioctl Error handling is added to prevent garbage value being passed to user space by the uninitialized local variable avtimer_tick. CRs-Fixed: 1097878 Change-Id: I3f895deaae3acf329088cf8135859cc41e781763 Signed-off-by: Xiaoyu Ye --- drivers/platform/msm/avtimer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index d6b6fc061104..a2ef12fa840d 100644 --- a/drivers/platform/msm/avtimer.c +++ b/drivers/platform/msm/avtimer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -332,9 +332,17 @@ static long avtimer_ioctl(struct file *file, unsigned int ioctl_num, switch (ioctl_num) { case IOCTL_GET_AVTIMER_TICK: { - uint64_t avtimer_tick; + uint64_t avtimer_tick = 0; + int rc; + + rc = avcs_core_query_timer(&avtimer_tick); + + if (rc) { + pr_err("%s: Error: Invalid AV Timer tick, rc = %d\n", + __func__, rc); + return rc; + } - avcs_core_query_timer(&avtimer_tick); pr_debug_ratelimited("%s: AV Timer tick: time %llx\n", __func__, avtimer_tick); if (copy_to_user((void *) ioctl_param, &avtimer_tick, From 3f9da2592236ac947c0b22bd6e67561e599b5c3e Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Wed, 8 Feb 2017 15:33:48 -0800 Subject: [PATCH 204/281] sdcardfs: limit stacking depth Limit filesystem stacking to prevent stack overflow. Bug: 32761463 Change-Id: I8b1462b9c0d6c7f00cf110724ffb17e7f307c51e Signed-off-by: Andrew Chant --- fs/sdcardfs/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index fe5eb9397a6f..4031e4b2ee70 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -281,6 +281,13 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); + sb->s_stack_depth = lower_sb->s_stack_depth + 1; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("sdcardfs: maximum fs stacking depth exceeded\n"); + err = -EINVAL; + goto out_sput; + } + /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; From ae3d4db11bce286862228c6d23833a054be72686 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 10 Feb 2017 10:54:56 -0800 Subject: [PATCH 205/281] ANDROID: ion: Protect kref from userspace manipulation This separates the kref for ion handles into two components. Userspace requests through the ioctl will hold at most one reference to the internally used kref. All additional requests will increment a separate counter, and the original reference is only put once that counter hits 0. This protects the kernel from a poorly behaving userspace. Bug: 34276203 Change-Id: Ibc36bc4405788ed0fea7337b541cad3be2b934c0 Signed-off-by: Daniel Rosenberg --- drivers/staging/android/ion/ion.c | 83 ++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 6c9fb99f9fa9..f8161016d137 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -113,6 +113,7 @@ struct ion_client { */ struct ion_handle { struct kref ref; + unsigned int user_ref_count; struct ion_client *client; struct ion_buffer *buffer; struct rb_node node; @@ -438,6 +439,48 @@ int ion_handle_put(struct ion_handle *handle) return ret; } +/* Must hold the client lock */ +static void user_ion_handle_get(struct ion_handle *handle) +{ + if (handle->user_ref_count++ == 0) + kref_get(&handle->ref); +} + +/* Must hold the client lock */ +static struct ion_handle *user_ion_handle_get_check_overflow(struct ion_handle *handle) +{ + if (handle->user_ref_count + 1 == 0) + return ERR_PTR(-EOVERFLOW); + user_ion_handle_get(handle); + return handle; +} + +/* passes a kref to the user ref count. + * We know we're holding a kref to the object before and + * after this call, so no need to reverify handle. */ +static struct ion_handle *pass_to_user(struct ion_handle *handle) +{ + struct ion_client *client = handle->client; + struct ion_handle *ret; + + mutex_lock(&client->lock); + ret = user_ion_handle_get_check_overflow(handle); + ion_handle_put_nolock(handle); + mutex_unlock(&client->lock); + return ret; +} + +/* Must hold the client lock */ +static int user_ion_handle_put_nolock(struct ion_handle *handle) +{ + int ret; + + if (--handle->user_ref_count == 0) + ret = ion_handle_put_nolock(handle); + + return ret; +} + static struct ion_handle *ion_handle_lookup(struct ion_client *client, struct ion_buffer *buffer) { @@ -654,6 +697,25 @@ static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle ion_handle_put_nolock(handle); } +/* Must hold the client lock */ +static void user_ion_free_nolock(struct ion_client *client, struct ion_handle *handle) +{ + bool valid_handle; + + BUG_ON(client != handle->client); + + valid_handle = ion_handle_validate(client, handle); + if (!valid_handle) { + WARN(1, "%s: invalid handle passed to free.\n", __func__); + return; + } + if (handle->user_ref_count == 0) { + WARN(1, "%s: User does not have access!\n", __func__); + return; + } + user_ion_handle_put_nolock(handle); +} + void ion_free(struct ion_client *client, struct ion_handle *handle) { BUG_ON(client != handle->client); @@ -1476,7 +1538,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) data.allocation.flags, true); if (IS_ERR(handle)) return PTR_ERR(handle); - + pass_to_user(handle); data.allocation.handle = handle->id; cleanup_handle = handle; @@ -1492,7 +1554,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&client->lock); return PTR_ERR(handle); } - ion_free_nolock(client, handle); + user_ion_free_nolock(client, handle); ion_handle_put_nolock(handle); mutex_unlock(&client->lock); break; @@ -1515,10 +1577,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ion_handle *handle; handle = ion_import_dma_buf(client, data.fd.fd); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { ret = PTR_ERR(handle); - else - data.handle.handle = handle->id; + } else { + handle = pass_to_user(handle); + if (IS_ERR(handle)) + ret = PTR_ERR(handle); + else + data.handle.handle = handle->id; + } break; } case ION_IOC_SYNC: @@ -1550,8 +1617,10 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (dir & _IOC_READ) { if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { if (cleanup_handle) { - ion_free(client, cleanup_handle); - ion_handle_put(cleanup_handle); + mutex_lock(&client->lock); + user_ion_free_nolock(client, cleanup_handle); + ion_handle_put_nolock(cleanup_handle); + mutex_unlock(&client->lock); } return -EFAULT; } From 994240159bf04214a933fb41efec2232cd917572 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 24 Oct 2014 00:14:39 +0200 Subject: [PATCH 206/281] BACKPORT: fs: limit filesystem stacking depth Add a simple read-only counter to super_block that indicates how deep this is in the stack of filesystems. Previously ecryptfs was the only stackable filesystem and it explicitly disallowed multiple layers of itself. Overlayfs, however, can be stacked recursively and also may be stacked on top of ecryptfs or vice versa. To limit the kernel stack usage we must limit the depth of the filesystem stack. Initially the limit is set to 2. Signed-off-by: Miklos Szeredi (cherry picked from commit 69c433ed2ecd2d3264efd7afec4439524b319121) Bug: 32761463 Change-Id: I69b2fba2112db2ece09a1bf61a44f8fc4db00820 --- fs/ecryptfs/main.c | 7 +++++++ include/linux/fs.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 2743d7805d7d..7422dc4b2738 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -574,6 +574,13 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = ECRYPTFS_SUPER_MAGIC; + s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; + + rc = -EINVAL; + if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("eCryptfs: maximum fs stacking depth exceeded\n"); + goto out_free; + } inode = ecryptfs_get_inode(path.dentry->d_inode, s); rc = PTR_ERR(inode); diff --git a/include/linux/fs.h b/include/linux/fs.h index 3e7961ccc8f8..c3685a7013f7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -251,6 +251,12 @@ struct iattr { */ #include +/* + * Maximum number of layers of fs stack. Needs to be limited to + * prevent kernel stack overflow + */ +#define FILESYSTEM_MAX_STACK_DEPTH 2 + /** * enum positive_aop_returns - aop return codes with specific semantics * @@ -1330,6 +1336,11 @@ struct super_block { /* Being remounted read-only */ int s_readonly_remount; + + /* + * Indicates how deep in a filesystem stack this SB is + */ + int s_stack_depth; }; /* superblock cache pruning functions */ From 7019cbe46803e176f3ed59761cf3a343189df8b7 Mon Sep 17 00:00:00 2001 From: Jim Lin Date: Fri, 13 Jan 2017 16:07:58 +0800 Subject: [PATCH 207/281] FROMLIST: CHROMIUM: usb: gadget: configfs: Fix KASAN use-after-free When gadget is disconnected, running sequence is like this. . android_work: sent uevent USB_STATE=DISCONNECTED . Call trace: usb_string_copy+0xd0/0x128 gadget_config_name_configuration_store+0x4 gadget_config_name_attr_store+0x40/0x50 configfs_write_file+0x198/0x1f4 vfs_write+0x100/0x220 SyS_write+0x58/0xa8 . configfs_composite_unbind . configfs_composite_bind In configfs_composite_bind, it has "cn->strings.s = cn->configuration;" When usb_string_copy is invoked. it would allocate memory, copy input string, release previous pointed memory space, and use new allocated memory. When gadget is connected, host sends down request to get information. Call trace: usb_gadget_get_string+0xec/0x168 lookup_string+0x64/0x98 composite_setup+0xa34/0x1ee8 android_setup+0xb4/0x140 If gadget is disconnected and connected quickly, in the failed case, cn->configuration memory has been released by usb_string_copy kfree but configfs_composite_bind hasn't been run in time to assign new allocated "cn->configuration" pointer to "cn->strings.s". When "strlen(s->s) of usb_gadget_get_string is being executed, the dangling memory is accessed, "BUG: KASAN: use-after-free" error occurs. BUG=chrome-os-partner:58412 TEST=After smaug device was connected to ubuntu PC host, detached and attached type-C cable quickly several times without seeing "BUG: KASAN: use-after-free in usb_gadget_get_string". Bug: 31614969 Change-Id: I58240ee7c55ae8f8fb8597d14f09c5ac07abb032 Signed-off-by: Jim Lin Signed-off-by: Siqi Lin (am from https://chromium-review.googlesource.com/#/c/428059/3) --- drivers/usb/gadget/configfs.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 80e7f75a56c7..5a65722d16d6 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -87,21 +87,28 @@ struct gadget_config_name { struct list_head list; }; +#define MAX_USB_STRING_LEN 126 +#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1) + static int usb_string_copy(const char *s, char **s_copy) { int ret; char *str; char *copy = *s_copy; ret = strlen(s); - if (ret > 126) + if (ret > MAX_USB_STRING_LEN) return -EOVERFLOW; - str = kstrdup(s, GFP_KERNEL); - if (!str) - return -ENOMEM; + if (copy) { + str = copy; + } else { + str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL); + if (!str) + return -ENOMEM; + } + strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN); if (str[ret - 1] == '\n') str[ret - 1] = '\0'; - kfree(copy); *s_copy = str; return 0; } From 38660792f95702ed8a05a2fb1aa2f6e70729d89d Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Tue, 3 Jan 2017 14:46:23 -0800 Subject: [PATCH 208/281] ASoC: msm: qdsp6v2: Fix out-of-bounds access in put functions Add out of bounds check in routing put functions for the mux value before accessing the texts pointer of soc_enum struct with mux as index. CRs-fixed: 1097569 Change-Id: Ib9ef8d398f0765754b0f79666963fac043b66077 Signed-off-by: Karthikeyan Mani --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index a48b48618354..bdf72e32e62b 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1519,8 +1519,14 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, int ec_ref_port_id; struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + int mux = ucontrol->value.enumerated.item[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + if (mux >= e->max) { + pr_err("%s: Invalid mux value %d\n", __func__, mux); + return -EINVAL; + } + mutex_lock(&routing_lock); switch (ucontrol->value.integer.value[0]) { case 0: @@ -1642,6 +1648,11 @@ static int msm_routing_ext_ec_put(struct snd_kcontrol *kcontrol, __func__, msm_route_ext_ec_ref, ucontrol->value.integer.value[0]); + if (mux >= e->max) { + pr_err("%s: Invalid mux value %d\n", __func__, mux); + return -EINVAL; + } + mutex_lock(&routing_lock); switch (ucontrol->value.integer.value[0]) { case EC_PORT_ID_PRIMARY_MI2S_TX: From 28eb82a4802db01d9770da896a629e58779e879d Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Sat, 26 Dec 2015 06:00:48 +0100 Subject: [PATCH 209/281] UPSTREAM: seccomp: always propagate NO_NEW_PRIVS on tsync Before this patch, a process with some permissive seccomp filter that was applied by root without NO_NEW_PRIVS was able to add more filters to itself without setting NO_NEW_PRIVS by setting the new filter from a throwaway thread with NO_NEW_PRIVS. Signed-off-by: Jann Horn Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Bug: 36656103 (cherry-picked from commit 103502a35cfce0710909da874f092cb44823ca03) Signed-off-by: Paul Lawrence Change-Id: I5abd7daab9172f1dfd53e11706b7c7f331f2f4f1 --- kernel/seccomp.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 83f418b0c34a..9cdc92ec1707 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -338,24 +338,24 @@ static inline void seccomp_sync_threads(void) put_seccomp_filter(thread); smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); + + /* + * Don't let an unprivileged task work around + * the no_new_privs restriction by creating + * a thread that sets it up, enters seccomp, + * then dies. + */ + if (task_no_new_privs(caller)) + task_set_no_new_privs(thread); + /* * Opt the other thread into seccomp if needed. * As threads are considered to be trust-realm * equivalent (see ptrace_may_access), it is safe to * allow one thread to transition the other. */ - if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) { - /* - * Don't let an unprivileged task work around - * the no_new_privs restriction by creating - * a thread that sets it up, enters seccomp, - * then dies. - */ - if (task_no_new_privs(caller)) - task_set_no_new_privs(thread); - + if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); - } } } From 822ed81cc137eae62a6c16aea09e8e3d69cb73aa Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 15 Jul 2013 19:10:12 +0200 Subject: [PATCH 210/281] BACKPORT: HID: input: generic hidinput_input_event handler The hidinput_input_event() callback converts input events written from userspace into HID reports and sends them to the device. We currently implement this in every HID transport driver, even though most of them do the same. This provides a generic hidinput_input_event() implementation which is mostly copied from usbhid. It uses a delayed worker to allow multiple LED events to be collected into a single output event. We use the custom ->request() transport driver callback to allow drivers to adjust the outgoing report and handle the request asynchronously. If no custom ->request() callback is available, we fall back to the generic raw output report handler (which is synchronous). Drivers can still provide custom hidinput_input_event() handlers (see logitech-dj) if the generic implementation doesn't fit their needs. Conflicts: drivers/hid/hid-input.c Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina Signed-off-by: Michael Wright Change-Id: Iccb0b1de6460f6854b3d55d4008cc1d744472a06 --- drivers/hid/hid-input.c | 77 ++++++++++++++++++++++++++++++++++++++++- drivers/hid/uhid.c | 25 ------------- include/linux/hid.h | 1 + 3 files changed, 77 insertions(+), 26 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 0f9950e8239a..c02f4350c33c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1161,6 +1161,69 @@ unsigned int hidinput_count_leds(struct hid_device *hid) } EXPORT_SYMBOL_GPL(hidinput_count_leds); +static void hidinput_led_worker(struct work_struct *work) +{ + struct hid_device *hid = container_of(work, struct hid_device, + led_work); + struct hid_field *field; + struct hid_report *report; + int len; + __u8 *buf; + + field = hidinput_get_led_field(hid); + if (!field) + return; + + /* + * field->report is accessed unlocked regarding HID core. So there might + * be another incoming SET-LED request from user-space, which changes + * the LED state while we assemble our outgoing buffer. However, this + * doesn't matter as hid_output_report() correctly converts it into a + * boolean value no matter what information is currently set on the LED + * field (even garbage). So the remote device will always get a valid + * request. + * And in case we send a wrong value, a next led worker is spawned + * for every SET-LED request so the following worker will send the + * correct value, guaranteed! + */ + + report = field->report; + + len = ((report->size - 1) >> 3) + 1 + (report->id > 0); + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return; + + hid_output_report(report, buf); + /* synchronous output report */ + hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT); + kfree(buf); +} + +static int hidinput_input_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct hid_field *field; + int offset; + + if (type == EV_FF) + return input_ff_event(dev, type, code, value); + + if (type != EV_LED) + return -1; + + if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { + hid_warn(dev, "event field not found\n"); + return -1; + } + + hid_set_field(field, offset, value); + + schedule_work(&hid->led_work); + return 0; +} + static int hidinput_open(struct input_dev *dev) { struct hid_device *hid = input_get_drvdata(dev); @@ -1212,7 +1275,12 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) } input_set_drvdata(input_dev, hid); - input_dev->event = hid->ll_driver->hidinput_input_event; + if(hid->ll_driver->hidinput_input_event) { + input_dev->event = + hid->ll_driver->hidinput_input_event; + } else if (hid->hid_output_raw_report) { + input_dev->event = hidinput_input_event; + } input_dev->open = hidinput_open; input_dev->close = hidinput_close; input_dev->setkeycode = hidinput_setkeycode; @@ -1307,6 +1375,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) int i, j, k; INIT_LIST_HEAD(&hid->inputs); + INIT_WORK(&hid->led_work, hidinput_led_worker); if (!force) { for (i = 0; i < hid->maxcollection; i++) { @@ -1410,6 +1479,12 @@ void hidinput_disconnect(struct hid_device *hid) input_unregister_device(hidinput->input); kfree(hidinput); } + + /* led_work is spawned by input_dev callbacks, but doesn't access the + * parent input_dev at all. Once all input devices are removed, we + * know that led_work will never get restarted, so we can cancel it + * synchronously and are safe. */ + cancel_work_sync(&hid->led_work); } EXPORT_SYMBOL_GPL(hidinput_disconnect); diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 0bb3bb889b71..cedc6da93c19 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -116,30 +116,6 @@ static void uhid_hid_close(struct hid_device *hid) uhid_queue_event(uhid, UHID_CLOSE); } -static int uhid_hid_input(struct input_dev *input, unsigned int type, - unsigned int code, int value) -{ - struct hid_device *hid = input_get_drvdata(input); - struct uhid_device *uhid = hid->driver_data; - unsigned long flags; - struct uhid_event *ev; - - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) - return -ENOMEM; - - ev->type = UHID_OUTPUT_EV; - ev->u.output_ev.type = type; - ev->u.output_ev.code = code; - ev->u.output_ev.value = value; - - spin_lock_irqsave(&uhid->qlock, flags); - uhid_queue(uhid, ev); - spin_unlock_irqrestore(&uhid->qlock, flags); - - return 0; -} - static int uhid_hid_parse(struct hid_device *hid) { struct uhid_device *uhid = hid->driver_data; @@ -273,7 +249,6 @@ static struct hid_ll_driver uhid_hid_driver = { .stop = uhid_hid_stop, .open = uhid_hid_open, .close = uhid_hid_close, - .hidinput_input_event = uhid_hid_input, .parse = uhid_hid_parse, }; diff --git a/include/linux/hid.h b/include/linux/hid.h index 40e9c9d76d1e..254d56c002b3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -458,6 +458,7 @@ struct hid_device { /* device report descriptor */ enum hid_type type; /* device type (mouse, kbd, ...) */ unsigned country; /* HID country */ struct hid_report_enum report_enum[HID_REPORT_TYPES]; + struct work_struct led_work; /* delayed LED worker */ struct semaphore driver_lock; /* protects the current driver, except during input */ struct semaphore driver_input_lock; /* protects the current driver */ From 535e856f244a34598600047f0353d491e8e12eee Mon Sep 17 00:00:00 2001 From: SaidiReddy Yenuga Date: Tue, 30 Aug 2016 15:34:43 +0530 Subject: [PATCH 211/281] wlan: send RSSI info correctly to CNE The commit of change Id I3e50fdc2f648ace1b6c260e3d579d93d8e546446 removed the support for iw_set_priv. revert the changes for RSSI. Change-Id: I6a5e4501fa9c11710cd9fbc823b97a3e43a9adc0 CRs-Fixed: 1059770 --- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 392 +++++++++++++++++- 1 file changed, 391 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index a1510f0cea39..965fb53ba5f8 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -3775,6 +3775,69 @@ static int iw_get_linkspeed_priv(struct net_device *dev, return ret; } +/* + * Support for the RSSI & RSSI-APPROX private commands + * Per the WiFi framework the response must be of the form + * " rssi " + * unless we are not associated, in which case the response is + * "OK" + */ +static int iw_get_rssi(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + char *cmd = extra; + int len = wrqu->data.length; + v_S7_t s7Rssi = 0; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length; + VOS_STATUS vosStatus; + int rc; + + if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) || + (0 == ssidlen) || (ssidlen >= len)) + { + /* we are not connected or our SSID is too long + so we cannot report an rssi */ + rc = scnprintf(cmd, len, "OK"); + } + else + { + /* we are connected with a valid SSID + so we can write the SSID into the return buffer + (note that it is not NUL-terminated) */ + memcpy(cmd, pHddStaCtx->conn_info.SSID.SSID.ssId, ssidlen ); + + vosStatus = wlan_hdd_get_rssi(pAdapter, &s7Rssi); + + if (VOS_STATUS_SUCCESS == vosStatus) + { + /* append the rssi to the ssid in the format required by + the WiFI Framework */ + rc = scnprintf(&cmd[ssidlen], len - ssidlen, " rssi %d", s7Rssi); + rc += ssidlen; + } + else + { + rc = -1; + } + } + + /* verify that we wrote a valid response */ + if ((rc < 0) || (rc >= len)) + { + // encoding or length error? + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to encode RSSI, got [%s]", + __func__, cmd); + return -EIO; + } + + /* a value is being successfully returned */ + return rc; +} + /* * Support for SoftAP channel range private command */ @@ -4213,6 +4276,333 @@ void* wlan_hdd_change_country_code_callback(void *pAdapter) return NULL; } +static int __iw_set_priv(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter; + char *cmd = NULL; + int cmd_len = wrqu->data.length; + int rc = 0, ret = 0; + VOS_STATUS vos_status = VOS_STATUS_SUCCESS; + + hdd_context_t *pHddCtx; + + ENTER(); + + pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (NULL == pAdapter) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "mem_alloc_copy_from_user_helper fail"); + return -EINVAL; + } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + rc = wlan_hdd_validate_context(pHddCtx); + if (0 != rc) + { + return rc; + } + + cmd = mem_alloc_copy_from_user_helper(wrqu->data.pointer, + wrqu->data.length); + if (NULL == cmd) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + if (ioctl_debug) + { + pr_info("%s: req [%s] len [%d]\n", __func__, cmd, cmd_len); + } + + hddLog(VOS_TRACE_LEVEL_INFO_MED, + "%s: ***Received %s cmd from Wi-Fi GUI***", __func__, cmd); + + if (strncmp(cmd, "CSCAN", 5) == 0 ) + { + if (eHAL_STATUS_SUCCESS != iw_set_cscan(dev, info, wrqu, cmd)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: Error in iw_set_scan!", __func__); + rc = -EINVAL; + } + } + else if( strcasecmp(cmd, "start") == 0 ) { + + hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "Start command"); + /*Exit from Deep sleep or standby if we get the driver START cmd from android GUI*/ + + vos_status = wlan_hdd_exit_lowpower(pHddCtx, pAdapter); + if (vos_status == VOS_STATUS_SUCCESS) + { + union iwreq_data wrqu; + char buf[10]; + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlcpy(buf, "START", sizeof(buf)); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); + } + else + { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: START CMD Status %d", __func__, vos_status); + rc = -EIO; + } + goto done; + } + else if( strcasecmp(cmd, "stop") == 0 ) + { + union iwreq_data wrqu; + char buf[10]; + + hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "Stop command"); + + wlan_hdd_enter_lowpower(pHddCtx); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlcpy(buf, "STOP", sizeof(buf)); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); + goto done; + } + else if (strcasecmp(cmd, "macaddr") == 0) + { + ret = snprintf(cmd, cmd_len, "Macaddr = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes)); + } + else if (strcasecmp(cmd, "scan-active") == 0) + { + hddLog(LOG1, + FL("making default scan to active")); + pHddCtx->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + ret = snprintf(cmd, cmd_len, "OK"); + } + else if (strcasecmp(cmd, "scan-passive") == 0) + { + hddLog(LOG1, + FL("making default scan to passive")); + pHddCtx->scan_info.scan_mode = eSIR_PASSIVE_SCAN; + ret = snprintf(cmd, cmd_len, "OK"); + } + else if( strcasecmp(cmd, "scan-mode") == 0 ) + { + ret = snprintf(cmd, cmd_len, "ScanMode = %u", pHddCtx->scan_info.scan_mode); + } + else if( strcasecmp(cmd, "linkspeed") == 0 ) + { + ret = iw_get_linkspeed(dev, info, wrqu, cmd); + } + else if( strncasecmp(cmd, "rssi", 4) == 0 ) + { + ret = iw_get_rssi(dev, info, wrqu, cmd); + } + else if( strncasecmp(cmd, "powermode", 9) == 0 ) { + int mode; + char *ptr; + + if (9 < cmd_len) + { + ptr = (char*)(cmd + 9); + + }else{ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "CMD LENGTH %d is not correct",cmd_len); + kfree(cmd); + return -EINVAL; + } + + if (1 != sscanf(ptr,"%d",&mode)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "powermode input %s is not correct",ptr); + kfree(cmd); + return -EIO; + } + + wlan_hdd_enter_bmps(pAdapter, mode); + /*TODO:Set the power mode*/ + } + else if (strncasecmp(cmd, "getpower", 8) == 0 ) { + v_U32_t pmc_state; + v_U16_t value; + + pmc_state = pmcGetPmcState(WLAN_HDD_GET_HAL_CTX(pAdapter)); + if(pmc_state == BMPS) { + value = DRIVER_POWER_MODE_AUTO; + } + else { + value = DRIVER_POWER_MODE_ACTIVE; + } + ret = snprintf(cmd, cmd_len, "powermode = %u", value); + } + else if( strncasecmp(cmd, "btcoexmode", 10) == 0 ) { + hddLog( VOS_TRACE_LEVEL_INFO, "btcoexmode"); + /*TODO: set the btcoexmode*/ + } + else if( strcasecmp(cmd, "btcoexstat") == 0 ) { + + hddLog(VOS_TRACE_LEVEL_INFO, "BtCoex Status"); + /*TODO: Return the btcoex status*/ + } + else if( strcasecmp(cmd, "rxfilter-start") == 0 ) { + + hddLog(VOS_TRACE_LEVEL_INFO, "Rx Data Filter Start command"); + + /*TODO: Enable Rx data Filter*/ + } + else if( strcasecmp(cmd, "rxfilter-stop") == 0 ) { + + hddLog(VOS_TRACE_LEVEL_INFO, "Rx Data Filter Stop command"); + + /*TODO: Disable Rx data Filter*/ + } + else if( strcasecmp(cmd, "rxfilter-statistics") == 0 ) { + + hddLog( VOS_TRACE_LEVEL_INFO, "Rx Data Filter Statistics command"); + /*TODO: rxfilter-statistics*/ + } + else if( strncasecmp(cmd, "rxfilter-add", 12) == 0 ) { + + hddLog( VOS_TRACE_LEVEL_INFO, "rxfilter-add"); + /*TODO: rxfilter-add*/ + } + else if( strncasecmp(cmd, "rxfilter-remove",15) == 0 ) { + + hddLog( VOS_TRACE_LEVEL_INFO, "rxfilter-remove"); + /*TODO: rxfilter-remove*/ + } +#ifdef FEATURE_WLAN_SCAN_PNO + else if( strncasecmp(cmd, "pnosetup", 8) == 0 ) { + hddLog( VOS_TRACE_LEVEL_INFO, "pnosetup"); + /*TODO: support pnosetup*/ + } + else if( strncasecmp(cmd, "pnoforce", 8) == 0 ) { + hddLog( VOS_TRACE_LEVEL_INFO, "pnoforce"); + /*TODO: support pnoforce*/ + } + else if( strncasecmp(cmd, "pno",3) == 0 ) { + + hddLog( VOS_TRACE_LEVEL_INFO, "pno"); + vos_status = iw_set_pno(dev, info, wrqu, cmd, 3); + kfree(cmd); + return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; + } + else if( strncasecmp(cmd, "rssifilter",10) == 0 ) { + hddLog( VOS_TRACE_LEVEL_INFO, "rssifilter"); + vos_status = iw_set_rssi_filter(dev, info, wrqu, cmd, 10); + kfree(cmd); + return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; + } +#endif /*FEATURE_WLAN_SCAN_PNO*/ + else if( strncasecmp(cmd, "powerparams",11) == 0 ) { + hddLog( VOS_TRACE_LEVEL_INFO, "powerparams"); + vos_status = iw_set_power_params(dev, info, wrqu, cmd, 11); + kfree(cmd); + return (vos_status == VOS_STATUS_SUCCESS) ? 0 : -EINVAL; + } + else if( 0 == strncasecmp(cmd, "CONFIG-TX-TRACKING", 18) ) { + tSirTxPerTrackingParam tTxPerTrackingParam; + char *ptr; + + if (18 < cmd_len) + { + ptr = (char*)(cmd + 18); + }else{ + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "CMD LENGTH %d is not correct",cmd_len); + kfree(cmd); + return -EINVAL; + } + + if (4 != sscanf(ptr,"%hhu %hhu %hhu %u", + &(tTxPerTrackingParam.ucTxPerTrackingEnable), + &(tTxPerTrackingParam.ucTxPerTrackingPeriod), + &(tTxPerTrackingParam.ucTxPerTrackingRatio), + &(tTxPerTrackingParam.uTxPerTrackingWatermark))) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "CONFIG-TX-TRACKING %s input is not correct",ptr); + kfree(cmd); + return -EIO; + } + + // parameters checking + // period has to be larger than 0 + if (0 == tTxPerTrackingParam.ucTxPerTrackingPeriod) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Period input is not correct"); + kfree(cmd); + return -EIO; + } + + // use default value 5 is the input is not reasonable. in unit of 10% + if ((tTxPerTrackingParam.ucTxPerTrackingRatio > TX_PER_TRACKING_MAX_RATIO) || (0 == tTxPerTrackingParam.ucTxPerTrackingRatio)) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Ratio input is not good. use default 5"); + tTxPerTrackingParam.ucTxPerTrackingRatio = TX_PER_TRACKING_DEFAULT_RATIO; + } + + // default is 5 + if (0 == tTxPerTrackingParam.uTxPerTrackingWatermark) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Tx Packet number input is not good. use default 5"); + tTxPerTrackingParam.uTxPerTrackingWatermark = TX_PER_TRACKING_DEFAULT_WATERMARK; + } + + if (eHAL_STATUS_SUCCESS != + sme_SetTxPerTracking(pHddCtx->hHal, + hdd_tx_per_hit_cb, + (void*)pAdapter, &tTxPerTrackingParam)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Set Tx PER Tracking Failed!"); + rc = -EIO; + } + } + else { + hddLog( VOS_TRACE_LEVEL_WARN, "%s: Unsupported GUI command %s", + __func__, cmd); + } +done: + /* many of the commands write information back into the command + string using snprintf(). check the return value here in one + place */ + if ((ret < 0) || (ret >= cmd_len)) + { + /* there was an encoding error or overflow */ + rc = -EINVAL; + } + else if (ret > 0) + { + if (copy_to_user(wrqu->data.pointer, cmd, ret)) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + kfree(cmd); + return -EFAULT; + } + wrqu->data.length = ret; + } + + if (ioctl_debug) + { + pr_info("%s: rsp [%s] len [%d] status %d\n", + __func__, cmd, wrqu->data.length, rc); + } + kfree(cmd); + EXIT(); + return rc; +} + +static int iw_set_priv(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + vos_ssr_protect(__func__); + ret = __iw_set_priv(dev, info, wrqu, extra); + vos_ssr_unprotect(__func__); + + return ret; +} + static int __iw_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -10450,7 +10840,7 @@ static const iw_handler we_handler[] = (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL, /* SIOCSIWRANGE */ (iw_handler) iw_get_range, /* SIOCGIWRANGE */ - (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) iw_set_priv, /* SIOCSIWPRIV */ (iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCSIWSTATS */ (iw_handler) NULL, /* SIOCGIWSTATS */ From d2a016b80cdd2662e01cee0dd1882788b61a5d50 Mon Sep 17 00:00:00 2001 From: Nishank Aggarwal Date: Thu, 16 Feb 2017 12:00:19 +0530 Subject: [PATCH 212/281] wlan: Fix P2P scan faliure by updating channel list properly The new_index used in the function csrScanCopyRequest() is not updated because of use of pass by value for new_index. The channel list is not updated, and thus p2p scan fails. Fix is to use pass by refenrence for new_index to get updated channel list in csrScanCopyRequest(). Change-Id: I7fba9e0701a01b8e49d4fd94477582761c833674 CRs-Fixed: 2007630 --- drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 8 ++++---- drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index e0bec48c8ede..947489cd87e0 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -6885,7 +6885,7 @@ eHalStatus csrScanCopyRequest(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, tCs } else csrValidateScanChannels(pMac, pDstReq, pSrcReq, - new_index, ch144_support); + &new_index, ch144_support); pDstReq->ChannelInfo.numOfChannels = new_index; #ifdef FEATURE_WLAN_LFR if ( ( ( eCSR_SCAN_HO_BG_SCAN == @@ -9365,7 +9365,7 @@ void UpdateCCKMTSF(tANI_U32 *timeStamp0, tANI_U32 *timeStamp1, tANI_U32 *incr) #endif void csrValidateScanChannels(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, - tCsrScanRequest *pSrcReq, int new_index, tANI_U8 ch144_support) + tCsrScanRequest *pSrcReq, tANI_U32 *new_index, tANI_U8 ch144_support) { int index; @@ -9416,9 +9416,9 @@ void csrValidateScanChannels(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, continue; } - pDstReq->ChannelInfo.ChannelList[new_index] = + pDstReq->ChannelInfo.ChannelList[*new_index] = pSrcReq->ChannelInfo.ChannelList[index]; - new_index++; + (*new_index)++; } } } diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h index f5de46939da5..e0cc7313497c 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h +++ b/drivers/staging/prima/CORE/SME/src/csr/csrInsideApi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1104,6 +1104,6 @@ void csr_remove_bssid_from_scan_list(tpAniSirGlobal pMac, eHalStatus csrSetHT2040Mode(tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U8 cbMode); #endif void csrValidateScanChannels(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, - tCsrScanRequest *pSrcReq, int new_index, tANI_U8 ch144_support); + tCsrScanRequest *pSrcReq, tANI_U32 *new_index, tANI_U8 ch144_support); #endif From a55286af93cf0b2e788cdbfe05a94e5dbbd0fcd3 Mon Sep 17 00:00:00 2001 From: Nishank Aggarwal Date: Fri, 10 Feb 2017 15:48:13 +0530 Subject: [PATCH 213/281] wlan: Fix buffer overflow in WLANSAP_Set_WPARSNIes() qcacld-2.0 to prima propagation Currently In WLANSAP_Set_WPARSNIes() the parameter WPARSNIEsLen is user-controllable and never validates which uses as the length for a memory copy. This enables user-space applications to corrupt heap memory and potentially crash the kernel. Fix is to validate the WPARSNIes length to its max before use as the length for a memory copy. Change-Id: I7aff731aeae22bfd84beb955439a799abef37f68 CRs-Fixed: 1102648 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index 33f7d5039c74..c0c5c145d505 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -4180,6 +4180,14 @@ static int __iw_set_ap_genie(struct net_device *dev, return 0; } + if (wrqu->data.length > DOT11F_IE_RSN_MAX_LEN) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: WPARSN Ie input length is more than max[%d]", __func__, + wrqu->data.length); + return -EINVAL; + } + switch (genie[0]) { case DOT11F_EID_WPA: From b659e245b9dcbcd75430ff046c36e31392ee840c Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Fri, 3 Feb 2017 17:24:17 +0530 Subject: [PATCH 214/281] wlan: SAP: During SSR, don't check for logp in progress In SAP mode, during SSR, observing unnecessary debug logs due to logp in progress check. Also due to this check traffic monitor timer is not restarted. Don't check for logp in progress flag during SSR to avoid unnecessary debug logs and to restart traffic monitor timer cleanly. Change-Id: Id115fb8a4b482d68c0fde0f57fc286864470f9a9 CRs-Fixed: 2002150 --- .../prima/CORE/HDD/inc/wlan_hdd_hostapd.h | 4 +- .../CORE/HDD/inc/wlan_hdd_softap_tx_rx.h | 11 ++--- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 2 +- .../prima/CORE/HDD/src/wlan_hdd_hostapd.c | 42 ++++++++++++------- .../prima/CORE/HDD/src/wlan_hdd_main.c | 8 ++-- .../CORE/HDD/src/wlan_hdd_softap_tx_rx.c | 32 +++++++------- 6 files changed, 59 insertions(+), 40 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h index 5529887d076d..ed52105fc372 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h @@ -108,7 +108,7 @@ hdd_change_ch_avoidance_status(hdd_context_t *hdd_ctx, VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCallback); -VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ); +VOS_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter, bool re_init); void hdd_set_ap_ops( struct net_device *pWlanHostapdDev ); int hdd_hostapd_stop (struct net_device *dev); void hdd_restart_softap (hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); @@ -118,6 +118,6 @@ void hdd_hostapd_ch_avoid_cb(void *pAdapter, void *indParam); int hdd_del_all_sta(hdd_adapter_t *pAdapter); void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter); -void hdd_sap_destroy_events(hdd_adapter_t *adapter); +void hdd_sap_destroy_timers(hdd_adapter_t *adapter); #endif // end #if !defined( WLAN_HDD_HOSTAPD_H ) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h index d7c23ec8bb71..a41cc1cfdeda 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_softap_tx_rx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -114,7 +114,7 @@ extern struct net_device_stats* hdd_softap_stats(struct net_device *dev); @return : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ -extern VOS_STATUS hdd_softap_init_tx_rx( hdd_adapter_t *pAdapter ); +extern VOS_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter, bool re_init); /**============================================================================ @brief hdd_softap_deinit_tx_rx() - Deinit function to clean up Tx/RX @@ -124,7 +124,8 @@ extern VOS_STATUS hdd_softap_init_tx_rx( hdd_adapter_t *pAdapter ); @return : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ -extern VOS_STATUS hdd_softap_deinit_tx_rx( hdd_adapter_t *pAdapter ); +extern VOS_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter, + bool re_init); /**============================================================================ @brief hdd_softap_init_tx_rx_sta() - Init function to initialize a station in Tx/RX @@ -332,7 +333,7 @@ extern VOS_STATUS hdd_softap_GetConnectedStaId( hdd_adapter_t *pAdapter, v_U8_t @return : VOS_STATUS_E_FAILURE if any errors encountered ========================================================================== */ -VOS_STATUS hdd_start_trafficMonitor( hdd_adapter_t *pAdapter ); +VOS_STATUS hdd_start_trafficMonitor(hdd_adapter_t *pAdapter, bool re_init); /**========================================================================== @@ -344,6 +345,6 @@ VOS_STATUS hdd_start_trafficMonitor( hdd_adapter_t *pAdapter ); @return : VOS_STATUS_E_FAILURE if any errors encountered ========================================================================== */ -VOS_STATUS hdd_stop_trafficMonitor( hdd_adapter_t *pAdapter ); +VOS_STATUS hdd_stop_trafficMonitor( hdd_adapter_t *pAdapter, bool re_init); #endif // end #if !defined( WLAN_HDD_SOFTAP_TX_RX_H ) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index f8582e297c68..f55a1f46e3c9 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -10582,7 +10582,7 @@ int __wlan_hdd_cfg80211_change_iface( struct wiphy *wiphy, return -EINVAL; } } - status = hdd_init_ap_mode(pAdapter); + status = hdd_init_ap_mode(pAdapter, false); if(status != VOS_STATUS_SUCCESS) { hddLog(VOS_TRACE_LEVEL_FATAL, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index c0c5c145d505..b960f9561d77 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -2575,7 +2575,7 @@ static int __iw_softap_set_trafficmonitor(struct net_device *dev, if (TRUE == *isSetTrafficMon) { pHddCtx->cfg_ini->enableTrafficMonitor= TRUE; - if (VOS_STATUS_SUCCESS != hdd_start_trafficMonitor(pAdapter)) + if (VOS_STATUS_SUCCESS != hdd_start_trafficMonitor(pAdapter, false)) { VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR, "%s: failed to Start Traffic Monitor timer ", __func__ ); @@ -2585,7 +2585,7 @@ static int __iw_softap_set_trafficmonitor(struct net_device *dev, else if (FALSE == *isSetTrafficMon) { pHddCtx->cfg_ini->enableTrafficMonitor= FALSE; - if (VOS_STATUS_SUCCESS != hdd_stop_trafficMonitor(pAdapter)) + if (VOS_STATUS_SUCCESS != hdd_stop_trafficMonitor(pAdapter, false)) { VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR, "%s: failed to Stop Traffic Monitor timer ", __func__ ); @@ -4678,7 +4678,7 @@ void hdd_set_ap_ops( struct net_device *pWlanHostapdDev ) #endif } -VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ) +VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter, bool re_init) { hdd_hostapd_state_t * phostapdBuf; struct net_device *dev = pAdapter->dev; @@ -4689,7 +4689,7 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ) v_U16_t unsafeChannelCount; #endif /* FEATURE_WLAN_CH_AVOID */ - if (pHddCtx->isLogpInProgress) { + if (pHddCtx->isLogpInProgress && !re_init) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s:LOGP in Progress. Ignore!!!",__func__); status = VOS_STATUS_E_FAILURE; @@ -4742,7 +4742,7 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ) dev->wireless_handlers = (struct iw_handler_def *)& hostapd_handler_def; //Initialize the data path module - status = hdd_softap_init_tx_rx(pAdapter); + status = hdd_softap_init_tx_rx(pAdapter, re_init); if ( !VOS_IS_STATUS_SUCCESS( status )) { hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_softap_init_tx_rx failed", __func__); @@ -4762,7 +4762,7 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ) return status; error_wmm_init: - hdd_softap_deinit_tx_rx( pAdapter ); + hdd_softap_deinit_tx_rx(pAdapter, re_init); EXIT(); return status; } @@ -4858,7 +4858,7 @@ VOS_STATUS hdd_unregister_hostapd(hdd_adapter_t *pAdapter, tANI_U8 rtnl_held) { ENTER(); - hdd_softap_deinit_tx_rx(pAdapter); + hdd_softap_deinit_tx_rx(pAdapter, false); /* if we are being called during driver unload, then the dev has already been invalidated. if we are being called at other times, then we can @@ -4898,7 +4898,9 @@ void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter) ENTER(); hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (0 != wlan_hdd_validate_context(hdd_ctx)) { + if (NULL == hdd_ctx || NULL == hdd_ctx->cfg_ini) { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: HDD context is Null", __func__); return; } @@ -4948,21 +4950,24 @@ void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter) } /** - * hdd_sap_destroy_events() - Destroy sap evets + * hdd_sap_destroy_timers() - Destroy sap timers * @adapter: sap adapter context * * Return: nothing */ -void hdd_sap_destroy_events(hdd_adapter_t *adapter) +void hdd_sap_destroy_timers(hdd_adapter_t *adapter) { hdd_context_t *hdd_ctx; v_CONTEXT_t vos_ctx; ptSapContext sap_ctx; + VOS_STATUS status = VOS_STATUS_E_FAILURE; ENTER(); hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (0 != wlan_hdd_validate_context(hdd_ctx)) { + if (NULL == hdd_ctx || NULL == hdd_ctx->cfg_ini) { + VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: HDD context is Null", __func__); return; } @@ -4979,7 +4984,16 @@ void hdd_sap_destroy_events(hdd_adapter_t *adapter) return; } - if (!VOS_IS_STATUS_SUCCESS(vos_lock_destroy(&sap_ctx->SapGlobalLock))) - VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, - FL("WLANSAP_Stop failed destroy lock")); + if (VOS_TIMER_STATE_RUNNING == sap_ctx->sap_HT2040_timer.state) { + status = vos_timer_stop(&sap_ctx->sap_HT2040_timer); + if (!VOS_IS_STATUS_SUCCESS(status)) + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + FL("Failed to Stop HT20/40 timer")); + } + + status = vos_timer_destroy(&sap_ctx->sap_HT2040_timer); + if (!VOS_IS_STATUS_SUCCESS(status)) + VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, + FL("Failed to Destroy HT20/40 timer")); + } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index c76d7c83c559..9d79eb2184c8 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -8685,7 +8685,7 @@ hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type, pAdapter->device_mode = session_type; hdd_initialize_adapter_common(pAdapter); - status = hdd_init_ap_mode(pAdapter); + status = hdd_init_ap_mode(pAdapter, false); if( VOS_STATUS_SUCCESS != status ) goto err_free_netdev; @@ -9444,8 +9444,8 @@ VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx ) vos_flush_work(&pHddCtx->sap_start_work); hdd_sap_indicate_disconnect_for_sta(pAdapter); hdd_cleanup_actionframe(pHddCtx, pAdapter); - hdd_softap_deinit_tx_rx(pAdapter); - hdd_sap_destroy_events(pAdapter); + hdd_softap_deinit_tx_rx(pAdapter, true); + hdd_sap_destroy_timers(pAdapter); } else { netif_carrier_off(pAdapter->dev); } @@ -9669,7 +9669,7 @@ VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx ) case WLAN_HDD_SOFTAP: if (pHddCtx->cfg_ini->sap_internal_restart) { - hdd_init_ap_mode(pAdapter); + hdd_init_ap_mode(pAdapter, true); status = hdd_sta_id_hash_attach(pAdapter); if (VOS_STATUS_SUCCESS != status) { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index b6cf6360d7dc..5a3f1de674bc 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -141,17 +141,19 @@ void hdd_softap_traffic_monitor_timeout_handler( void *pUsrData ) return; } -VOS_STATUS hdd_start_trafficMonitor( hdd_adapter_t *pAdapter ) +VOS_STATUS hdd_start_trafficMonitor( hdd_adapter_t *pAdapter, bool re_init) { hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); VOS_STATUS status = VOS_STATUS_SUCCESS; ENTER(); - status = wlan_hdd_validate_context(pHddCtx); - if (0 != status) - { - return status; + + if (!re_init) { + status = wlan_hdd_validate_context(pHddCtx); + if (-ENODEV == status) { + return status; + } } if ((pHddCtx->cfg_ini->enableTrafficMonitor) && @@ -182,16 +184,18 @@ VOS_STATUS hdd_start_trafficMonitor( hdd_adapter_t *pAdapter ) return status; } -VOS_STATUS hdd_stop_trafficMonitor( hdd_adapter_t *pAdapter ) +VOS_STATUS hdd_stop_trafficMonitor( hdd_adapter_t *pAdapter, bool re_init) { hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); VOS_STATUS status = VOS_STATUS_SUCCESS; ENTER(); - status = wlan_hdd_validate_context(pHddCtx); - if (-ENODEV == status) - { - return status; + + if (!re_init){ + status = wlan_hdd_validate_context(pHddCtx); + if (-ENODEV == status) { + return status; + } } if (pHddCtx->traffic_monitor.isInitialized) @@ -849,7 +853,7 @@ struct net_device_stats* hdd_softap_stats(struct net_device *dev) @return : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ -VOS_STATUS hdd_softap_init_tx_rx( hdd_adapter_t *pAdapter ) +VOS_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter, bool re_init) { VOS_STATUS status = VOS_STATUS_SUCCESS; v_SINT_t i = -1; @@ -901,7 +905,7 @@ VOS_STATUS hdd_softap_init_tx_rx( hdd_adapter_t *pAdapter ) /* Update the AC weights suitable for SoftAP mode of operation */ WLANTL_SetACWeights((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pACWeights); - if (VOS_STATUS_SUCCESS != hdd_start_trafficMonitor(pAdapter)) + if (VOS_STATUS_SUCCESS != hdd_start_trafficMonitor(pAdapter, re_init)) { VOS_TRACE( VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_ERROR, "%s: failed to start Traffic Monito timer ", __func__ ); @@ -918,11 +922,11 @@ VOS_STATUS hdd_softap_init_tx_rx( hdd_adapter_t *pAdapter ) @return : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ -VOS_STATUS hdd_softap_deinit_tx_rx( hdd_adapter_t *pAdapter ) +VOS_STATUS hdd_softap_deinit_tx_rx( hdd_adapter_t *pAdapter, bool re_init) { VOS_STATUS status = VOS_STATUS_SUCCESS; - if (VOS_STATUS_SUCCESS != hdd_stop_trafficMonitor(pAdapter)) + if (VOS_STATUS_SUCCESS != hdd_stop_trafficMonitor(pAdapter, re_init)) { VOS_TRACE( VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_ERROR, "%s: Fail to Stop Traffic Monito timer", __func__ ); From 5a57f62e1de5b0e749aa57449f7501cc36860152 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Fri, 3 Feb 2017 21:42:08 +0530 Subject: [PATCH 215/281] wlan: On SSR, update SAP operating band, start and end channels During SSR(re-init) update SAP start channel, end channel and operating band with cfg values, so that SAP beacons on user intended channel range. Change-Id: Ic1a958cd63f3f28a91e898e964dddbf15d43e479 CRs-Fixed: 2002147 --- .../staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c index b960f9561d77..ffe7cbae158b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c @@ -4684,6 +4684,7 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter, bool re_init) struct net_device *dev = pAdapter->dev; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); VOS_STATUS status; + hdd_config_t *ini_cfg; #ifdef FEATURE_WLAN_CH_AVOID v_U16_t unsafeChannelList[NUM_20MHZ_RF_CHANNELS]; v_U16_t unsafeChannelCount; @@ -4759,6 +4760,17 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter, bool re_init) set_bit(WMM_INIT_DONE, &pAdapter->event_flags); + ini_cfg = pHddCtx->cfg_ini; + if (re_init && ini_cfg) { + hddLog(VOS_TRACE_LEVEL_INFO, FL("start_ch: %d end_ch:%d op_band:%d"), + ini_cfg->apStartChannelNum, ini_cfg->apEndChannelNum, + ini_cfg->apOperatingBand); + WLANSAP_SetChannelRange(WLAN_HDD_GET_HAL_CTX(pAdapter), + ini_cfg->apStartChannelNum, + ini_cfg->apEndChannelNum, + ini_cfg->apOperatingBand); + } + return status; error_wmm_init: From 7f2244ae9b3d3c97c40e258338bfdadb618dd239 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Tue, 1 Nov 2016 16:16:58 +0530 Subject: [PATCH 216/281] prima: Wait for clear filter request's response from firmware Presently, after sending clear filter request to firmware, Host is not waiting for response, leading DHCP packets to be dropped at firmware level, if DHCP packets are sent before processing clear filter request. After sending clear filter request, wait for response from firmware. Change-Id: Idd51d60357a5f3a9ae5dea81f188a8f403ea0ea5 CRs-Fixed: 1083987 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 4 + .../prima/CORE/HDD/src/wlan_hdd_wext.c | 77 +++++++++++++++++-- drivers/staging/prima/CORE/MAC/inc/sirApi.h | 3 + .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 25 +++++- 4 files changed, 100 insertions(+), 9 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 85447484704e..317d0a24cef0 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -131,6 +131,9 @@ /** Maximum time(ms) to wait for tdls initiator to start direct communication **/ #define WAIT_TIME_TDLS_INITIATOR 600 +/**Maximum time(ms) to wait for clear packet req to complete **/ +#define PKT_FILTER_TIMEOUT 300 + /* Maximum time to get linux regulatory entry settings */ #ifdef CONFIG_ENABLE_LINUX_REG #define LINUX_REG_WAIT_TIME 300 @@ -297,6 +300,7 @@ extern spinlock_t hdd_context_lock; #define GET_FRAME_LOG_MAGIC 0x464c4f47 //FLOG #define MON_MODE_MSG_MAGIC 0x51436B3A //MON_MODE #define ANTENNA_CONTEXT_MAGIC 0x414E544E //ANTN +#define CLEAR_FILTER_MAGIC 0x52349732 //CLEAR FILTER #define MON_MODE_MSG_TIMEOUT 5000 #define MON_MODE_START 1 #define MON_MODE_STOP 0 diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 965fb53ba5f8..69d087431aac 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -416,8 +416,7 @@ int hdd_validate_mcc_config(hdd_adapter_t *pAdapter, v_UINT_t staId, v_UINT_t arg1, v_UINT_t arg2, v_UINT_t arg3); #ifdef WLAN_FEATURE_PACKET_FILTERING -int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, - v_U8_t sessionId); +int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest); #endif static int get_fwr_memdump(struct net_device *, struct iw_request_info *, @@ -8988,12 +8987,56 @@ static int iw_set_keepalive_params(struct net_device *dev, } #ifdef WLAN_FEATURE_PACKET_FILTERING -int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, - tANI_U8 sessionId) +/**----------------------------------------------------------------- + + \brief hdd_pkt_filter_done - callback to be executed on completion + successful/failure) for clear filter request. + + \return - None + + --------------------------------------------------------------------------*/ +static void hdd_pkt_filter_done(void *data, v_U32_t status) { + struct statsContext *cbCtx = (struct statsContext *)data; + + + hddLog(VOS_TRACE_LEVEL_INFO, + FL("Pkt Filter Clear Status : %d"), status); + + if (data == NULL) + { + hddLog(VOS_TRACE_LEVEL_ERROR, FL("invalid context")); + return; + } + + spin_lock(&hdd_context_lock); + if (cbCtx->magic != CLEAR_FILTER_MAGIC) + { + spin_unlock(&hdd_context_lock); + hddLog(VOS_TRACE_LEVEL_ERROR, FL("invalid context, magic %x"), cbCtx->magic); + if (ioctl_debug) + { + pr_info("%s: Invalid context, magic [%08x]\n", + __func__, cbCtx->magic); + } + return; + } + + complete(&cbCtx->completion); + spin_unlock(&hdd_context_lock); +} + +int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); tSirRcvPktFilterCfgType packetFilterSetReq = {0}; tSirRcvFltPktClearParam packetFilterClrReq = {0}; - int i=0; + struct statsContext cbCtx; + int i=0, status; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; if (pHddCtx->cfg_ini->disablePacketFilter) { @@ -9061,7 +9104,7 @@ int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, pRequest->paramsData[i].dataMask[4], pRequest->paramsData[i].dataMask[5]); } - if (eHAL_STATUS_SUCCESS != sme_ReceiveFilterSetFilter(pHddCtx->hHal, &packetFilterSetReq, sessionId)) + if (eHAL_STATUS_SUCCESS != sme_ReceiveFilterSetFilter(pHddCtx->hHal, &packetFilterSetReq, pAdapter->sessionId)) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failure to execute Set Filter", __func__); @@ -9074,13 +9117,31 @@ int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest, hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Clear Packet Filter Request for Id: %d", __func__, pRequest->filterId); + + init_completion(&cbCtx.completion); + cbCtx.magic = CLEAR_FILTER_MAGIC; + cbCtx.pAdapter = pAdapter; + packetFilterClrReq.cbCtx = &cbCtx; packetFilterClrReq.filterId = pRequest->filterId; - if (eHAL_STATUS_SUCCESS != sme_ReceiveFilterClearFilter(pHddCtx->hHal, &packetFilterClrReq, sessionId)) + packetFilterClrReq.pktFilterCallback = hdd_pkt_filter_done; + if (eHAL_STATUS_SUCCESS != sme_ReceiveFilterClearFilter(pHddCtx->hHal, &packetFilterClrReq, pAdapter->sessionId)) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failure to execute Clear Filter", __func__); return -EINVAL; } + + status = wait_for_completion_interruptible_timeout(&cbCtx.completion, + msecs_to_jiffies(PKT_FILTER_TIMEOUT)); + spin_lock(&hdd_context_lock); + cbCtx.magic = 0; + spin_unlock(&hdd_context_lock); + if (0 >= status) + { + hddLog(LOGE, FL("failure waiting for pkt_filter_comp_var %d"), + status); + return -EINVAL; + } break; default : @@ -9410,7 +9471,7 @@ static int __iw_set_packet_filter_params(struct net_device *dev, return -ENOMEM; } - ret = wlan_hdd_set_filter(WLAN_HDD_GET_CTX(pAdapter), pRequest, pAdapter->sessionId); + ret = wlan_hdd_set_filter(pAdapter, pRequest); kfree(pRequest); EXIT(); diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 86892bec8428..3539665ae83d 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -3792,6 +3792,7 @@ typedef struct typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp); typedef void ( *tGetFrameLogCallback) (void *pContext); typedef void(*RssiMonitorReqCb)(void *rssiMonitorCbContext, VOS_STATUS status); +typedef void(*pktFilterReqCb)(void *data, tANI_U32 status); typedef struct sAniGetFrameLogReq { @@ -4233,6 +4234,8 @@ typedef struct sSirRcvFltPktClearParam tANI_U8 filterId; tSirMacAddr selfMacAddr; tSirMacAddr bssId; + pktFilterReqCb pktFilterCallback; + void *cbCtx; }tSirRcvFltPktClearParam, *tpSirRcvFltPktClearParam; // diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 555defd1ec4b..d6df4091f01c 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -19398,6 +19398,8 @@ void WDA_ReceiveFilterClearFilterRespCallback( void * pUserData) { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tSirRcvFltPktClearParam *pktClearParam; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "<------ %s " ,__func__); /* WDA_VOS_ASSERT(NULL != pWdaParams); */ @@ -19408,7 +19410,14 @@ void WDA_ReceiveFilterClearFilterRespCallback( VOS_ASSERT(0) ; return ; } - + + pktClearParam = (tSirRcvFltPktClearParam *)pWdaParams->wdaMsgParam; + if(pktClearParam->pktFilterCallback) + { + pktClearParam->pktFilterCallback( + pktClearParam->cbCtx, + CONVERT_WDI2SIR_STATUS(pwdiRcvFltPktClearRspParamsType->wdiStatus)); + } vos_mem_free(pWdaParams->wdaMsgParam) ; vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams) ; @@ -19425,6 +19434,7 @@ void WDA_ReceiveFilterClearFilterRespCallback( void WDA_ReceiveFilterClearFilterReqCallback(WDI_Status wdiStatus, void* pUserData) { tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData; + tSirRcvFltPktClearParam *pktClearParam; VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "<------ %s, wdiStatus: %d", __func__, wdiStatus); @@ -19439,6 +19449,13 @@ void WDA_ReceiveFilterClearFilterReqCallback(WDI_Status wdiStatus, void* pUserDa if(IS_WDI_STATUS_FAILURE(wdiStatus)) { + pktClearParam = (tSirRcvFltPktClearParam *)pWdaParams->wdaMsgParam; + if(pktClearParam->pktFilterCallback) + { + pktClearParam->pktFilterCallback( + pktClearParam->cbCtx, + CONVERT_WDI2SIR_STATUS(wdiStatus)); + } vos_mem_free(pWdaParams->wdaWdiApiMsgParam); vos_mem_free(pWdaParams->wdaMsgParam); vos_mem_free(pWdaParams); @@ -19496,6 +19513,12 @@ VOS_STATUS WDA_ProcessReceiveFilterClearFilterReq (tWDA_CbContext *pWDA, { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, "Failure in WDA_ProcessReceiveFilterClearFilterReq(), free all the memory " ); + if(pRcvFltPktClearParam->pktFilterCallback) + { + pRcvFltPktClearParam->pktFilterCallback( + pRcvFltPktClearParam->cbCtx, + CONVERT_WDI2SIR_STATUS(status)); + } vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ; vos_mem_free(pWdaParams->wdaMsgParam); vos_mem_free(pWdaParams); From 8b22ae5b2326cac1086b57d69e766e97ee7dc187 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Tue, 1 Nov 2016 19:14:23 +0530 Subject: [PATCH 217/281] wlan: Reset Rx last SSN after clear filter Currently, when MSDU reorder info exists for a tid of station, then after clear filter host last Rx packet sequence number SSN goes out of sync with the hardware. Reason is in the period between set and clear filter packets coming to device will be dropped at the firmware because of the filter applied and host still has the last SSN before set filter. Also RX packet's SSN will wrap around and start from zero if SSN crosses 4096 in the period between set and clear filters. After clear filter because of above reasons RX packet SSN in issue case will be less than the host last RX SSN and when the difference is more than threshold which in this case is 3000 packet gets dropped. In this change reset the last Rx SSN to zero for the station's tid MSDU reorder info if exists. Change-Id: I30fb1a27efea2e57a229f674e0c2d80805847de5 CRs-Fixed: 1084362 --- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 8 +++- .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 12 ++++++ .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 40 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 69d087431aac..4d9f4d97be30 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -8999,7 +8999,6 @@ static void hdd_pkt_filter_done(void *data, v_U32_t status) { struct statsContext *cbCtx = (struct statsContext *)data; - hddLog(VOS_TRACE_LEVEL_INFO, FL("Pkt Filter Clear Status : %d"), status); @@ -9029,6 +9028,7 @@ static void hdd_pkt_filter_done(void *data, v_U32_t status) int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest) { hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; tSirRcvPktFilterCfgType packetFilterSetReq = {0}; tSirRcvFltPktClearParam packetFilterClrReq = {0}; struct statsContext cbCtx; @@ -9118,6 +9118,12 @@ int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest) hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Clear Packet Filter Request for Id: %d", __func__, pRequest->filterId); + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + WLANTL_ResetRxSSN((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, + pHddStaCtx->conn_info.staId[0]); + } + init_completion(&cbCtx.completion); cbCtx.magic = CLEAR_FILTER_MAGIC; cbCtx.pAdapter = pAdapter; diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index b309a1b499d1..9f200b56fb14 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -3352,4 +3352,16 @@ WLANTL_SetMcastDuplicateDetection ); #endif /* WLAN_FEATURE_RMC */ +/* + * WLANTL_ResetRxSSN - reset last rx ssn + * @pvosGCtx: global vos context + * @ucSTAId: station id + * + * This function resets the last ssn of all tids of the station + * for whom BA reorder session exists. + * + * Return: none + */ +void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId); + #endif /* #ifndef WLAN_QCT_WLANTL_H */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 7902ac7df434..5ef562bade88 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -13775,6 +13775,46 @@ WLANTL_GetSTALinkCapacity return VOS_STATUS_SUCCESS; }/* WLANTL_GetSTALinkCapacity */ +/* + * WLANTL_ResetRxSSN - reset last rx ssn + * @pvosGCtx: global vos context + * @ucSTAId: station id + * + * This function resets the last ssn of all tids of the station + * for whom BA reorder session exists. + * + * Return: none + */ +void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId) +{ + WLANTL_CbType* pTLCb = NULL; + WLANTL_STAClientType* pClientSTA = NULL; + uint8_t i; + + if (WLANTL_STA_ID_INVALID(ucSTAId)) { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL:Invalid station id requested WLANTL_ResetRxSSN")); + return; + } + + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (NULL == pTLCb) { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "WLAN TL:Invalid TL pointer from pvosGCtx WLANTL_ResetRxSSN")); + return; + } + + pClientSTA = pTLCb->atlSTAClients[ucSTAId]; + + for (i = 0; i < WLAN_MAX_TID ; i++) { + if (0 == pClientSTA->atlBAReorderInfo[i].ucExists) { + continue; + } + TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "WLAN TL: Last RxSSN reset to zero for tid %d", i)); + pClientSTA->atlBAReorderInfo[i].LastSN = 0; + } +} #ifdef WLAN_FEATURE_RMC VOS_STATUS WLANTL_RmcInit From c99e957c8095a85a1ff20dcfd5919e1326122fd7 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Mon, 21 Nov 2016 17:45:31 +0530 Subject: [PATCH 218/281] wlan: Avoid dropping packets if data packet filter is set Currently, when MSDU reorder info exists for a tid of station, then host last Rx packet sequence number SSN goes out of sync with the hardware. As a result data packets other than the filtered packets in firmware which arrive on a particular tid to host will get dropped. In this change avoid dropping the packet if data packet filter is set. Change-Id: I4128e3be118afd76fd4abacc45f6ceb0f865ba5e CRs-Fixed: 1088971 --- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 5 +++ .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 12 +++++++ .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 31 +++++++++++++++++++ .../prima/CORE/TL/src/wlan_qct_tl_ba.c | 6 ++-- .../staging/prima/CORE/TL/src/wlan_qct_tli.h | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index 4d9f4d97be30..ef66b1685235 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -9111,6 +9111,8 @@ int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest) return -EINVAL; } + WLANTL_SetDataPktFilter((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, + pHddStaCtx->conn_info.staId[0], true); break; case HDD_RCV_FILTER_CLEAR: @@ -9148,6 +9150,9 @@ int wlan_hdd_set_filter(hdd_adapter_t *pAdapter, tpPacketFilterCfg pRequest) status); return -EINVAL; } + + WLANTL_SetDataPktFilter((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, + pHddStaCtx->conn_info.staId[0], false); break; default : diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index 9f200b56fb14..9b80e046023f 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -3364,4 +3364,16 @@ WLANTL_SetMcastDuplicateDetection */ void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId); +/* + * WLANTL_SetDataPktFilter - Set data filter flag + * @pvosGCtx: global vos context + * @ucSTAId: station id + * @flag: packet data filter flag + * + * This function sets the data pkt filter flag of all tids + * of the station for whom BA reorder session exists. + * + * Return: none + */ +void WLANTL_SetDataPktFilter(v_PVOID_t pvosGCtx, uint8_t ucSTAId, bool flag); #endif /* #ifndef WLAN_QCT_WLANTL_H */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 5ef562bade88..ae95be50dd76 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -14429,3 +14429,34 @@ WLANTL_SetMcastDuplicateDetection } #endif /* WLAN_FEATURE_RMC */ + +void WLANTL_SetDataPktFilter(v_PVOID_t pvosGCtx, uint8_t ucSTAId, bool flag) +{ + WLANTL_CbType* pTLCb = NULL; + WLANTL_STAClientType* pClientSTA = NULL; + uint8_t i; + + if (WLANTL_STA_ID_INVALID(ucSTAId)) { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid station id requested", __func__)); + return; + } + + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (NULL == pTLCb) { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid TL pointer from pvosGCtx", __func__)); + return; + } + + pClientSTA = pTLCb->atlSTAClients[ucSTAId]; + + for (i = 0; i < WLAN_MAX_TID ; i++) { + if (0 == pClientSTA->atlBAReorderInfo[i].ucExists) + continue; + + TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "WLAN TL: Last RxSSN reset to zero for tid %d", i)); + pClientSTA->atlBAReorderInfo[i].set_data_filter = flag; + } +} diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c index 9f601887f46b..f94058504127 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c @@ -1156,7 +1156,8 @@ VOS_STATUS WLANTL_MSDUReorder break; case WLANTL_OPCODE_QCUR_FWDBUF: - if (currentReorderInfo->LastSN > CSN) + if ((currentReorderInfo->LastSN > CSN) && + !(currentReorderInfo->set_data_filter)) { if ((currentReorderInfo->LastSN - CSN) < CSN_WRAP_AROUND_THRESHOLD) { @@ -1299,7 +1300,8 @@ VOS_STATUS WLANTL_MSDUReorder break; case WLANTL_OPCODE_QCUR: - if (currentReorderInfo->LastSN > CSN) + if ((currentReorderInfo->LastSN > CSN) && + !(currentReorderInfo->set_data_filter)) { if ((currentReorderInfo->LastSN - CSN) < CSN_WRAP_AROUND_THRESHOLD) { diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h index 50698636f2d2..4d23eb22781b 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h @@ -484,6 +484,7 @@ typedef struct WLANTL_REORDER_BUFFER_T *reorderBuffer; v_U16_t LastSN; + bool set_data_filter; }WLANTL_BAReorderType; From e85b4fef901c467075b800123987070ddf8f7a9e Mon Sep 17 00:00:00 2001 From: Alberto97 Date: Fri, 7 Apr 2017 15:25:00 +0200 Subject: [PATCH 219/281] Revert "sdcardfs: Flag files as non-mappable" This reverts commit 5545878409d806ab315845021e38f52f63d08240. Change-Id: I5ebe08d6c90b4113b6d3fff3d70aeb95da21062f --- fs/sdcardfs/file.c | 8 -------- include/linux/fs.h | 4 ---- mm/mmap.c | 3 --- 3 files changed, 15 deletions(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 42f66f2425be..f31e5cc86d0b 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -223,7 +223,6 @@ static int sdcardfs_open(struct inode *inode, struct file *file) /* save current_cred and override it */ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode)); - file->f_mode |= FMODE_NONMAPPABLE; file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { @@ -317,11 +316,6 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag) return err; } -static struct file *sdcardfs_get_lower_file(struct file *f) -{ - return sdcardfs_lower_file(f); -} - const struct file_operations sdcardfs_main_fops = { .llseek = generic_file_llseek, .read = sdcardfs_read, @@ -336,7 +330,6 @@ const struct file_operations sdcardfs_main_fops = { .release = sdcardfs_file_release, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, - .get_lower_file = sdcardfs_get_lower_file, }; /* trimmed directory options */ @@ -353,5 +346,4 @@ const struct file_operations sdcardfs_dir_fops = { .flush = sdcardfs_flush, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, - .get_lower_file = sdcardfs_get_lower_file, }; diff --git a/include/linux/fs.h b/include/linux/fs.h index c3685a7013f7..130190845e88 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -125,9 +125,6 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File is opened with O_PATH; almost nothing can be done with it */ #define FMODE_PATH ((__force fmode_t)0x4000) -/* File hasn't page cache and can't be mmaped, for stackable filesystem */ -#define FMODE_NONMAPPABLE ((__force fmode_t)0x400000) - /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x1000000) @@ -1581,7 +1578,6 @@ struct file_operations { long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); int (*show_fdinfo)(struct seq_file *m, struct file *f); - struct file* (*get_lower_file)(struct file *f); }; struct inode_operations { diff --git a/mm/mmap.c b/mm/mmap.c index 376198fe1c3e..641dd3d2c3dc 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1225,9 +1225,6 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, *populate = 0; - while (file && (file->f_mode & FMODE_NONMAPPABLE)) - file = file->f_op->get_lower_file(file); - /* * Does the application expect PROT_READ to imply PROT_EXEC? * From dc7d0f29125d6be3fb195f64d0fb12104c789bed Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 21:14:45 -0800 Subject: [PATCH 220/281] ANDROID: sdcardfs: remove unnecessary call to do_munmap Adapted from wrapfs commit 5be6de9ecf02 ("Wrapfs: use vm_munmap in ->mmap") commit 2c9f6014a8bb ("Wrapfs: remove unnecessary call to vm_unmap in ->mmap") Code is unnecessary and causes deadlocks in newer kernels. Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: Ia252d60c60799d7e28fc5f1f0f5b5ec2430a2379 --- fs/sdcardfs/file.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index f31e5cc86d0b..d193d64e30e8 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -176,12 +176,6 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) goto out; } saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ - err = do_munmap(current->mm, vma->vm_start, - vma->vm_end - vma->vm_start); - if (err) { - pr_err("sdcardfs: do_munmap failed %d\n", err); - goto out; - } } /* From 760e7f49288aa0005d1f95c172da2aa1ca3a3767 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 21:24:58 -0800 Subject: [PATCH 221/281] ANDROID: sdcardfs: copy lower inode attributes in ->ioctl Adapted from wrapfs commit fbc9c6f83ea6 ("Wrapfs: copy lower inode attributes in ->ioctl") commit e97d8e26cc9e ("Wrapfs: use file_inode helper") Some ioctls (e.g., EXT2_IOC_SETFLAGS) can change inode attributes, so copy them from lower inode. Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: I0f12684b9dbd4088b4a622c7ea9c03087f40e572 --- fs/sdcardfs/file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index d193d64e30e8..f0befee6bc27 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -113,6 +113,10 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, if (lower_file->f_op->unlocked_ioctl) err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); + /* some ioctls can change inode attributes (EXT2_IOC_SETFLAGS) */ + if (!err) + sdcardfs_copy_and_fix_attrs(file_inode(file), + file_inode(lower_file)); out: return err; } From 297e8221e85c92a7c422bb826c24e64ea75db5d6 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 21:42:01 -0800 Subject: [PATCH 222/281] ANDROID: sdcardfs: fix ->llseek to update upper and lower offset Adapted from wrapfs commit 1d1d23a47baa ("Wrapfs: fix ->llseek to update upper and lower offsets") Fixes bug: xfstests generic/257. f_pos consistently is required by and only by dir_ops->wrapfs_readdir, main_ops is not affected. Signed-off-by: Erez Zadok Signed-off-by: Mengyang Li Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: I360a1368ac37ea8966910a58972b81504031d437 --- fs/sdcardfs/file.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index f0befee6bc27..33c416eeddd2 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -314,6 +314,29 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag) return err; } +/* + * Sdcardfs cannot use generic_file_llseek as ->llseek, because it would + * only set the offset of the upper file. So we have to implement our + * own method to set both the upper and lower file offsets + * consistently. + */ +static loff_t sdcardfs_file_llseek(struct file *file, loff_t offset, int whence) +{ + int err; + struct file *lower_file; + + err = generic_file_llseek(file, offset, whence); + if (err < 0) + goto out; + + lower_file = sdcardfs_lower_file(file); + err = generic_file_llseek(lower_file, offset, whence); + +out: + return err; +} + + const struct file_operations sdcardfs_main_fops = { .llseek = generic_file_llseek, .read = sdcardfs_read, @@ -332,7 +355,7 @@ const struct file_operations sdcardfs_main_fops = { /* trimmed directory options */ const struct file_operations sdcardfs_dir_fops = { - .llseek = generic_file_llseek, + .llseek = sdcardfs_file_llseek, .read = generic_read_dir, .iterate = sdcardfs_readdir, .unlocked_ioctl = sdcardfs_unlocked_ioctl, From 693388ca7fc2cd03b796e7323f6f9a0fc57355ef Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 22:11:08 -0800 Subject: [PATCH 223/281] ANDROID: sdcardfs: use d_splice_alias adapted from wrapfs commit 9671770ff8b9 ("Wrapfs: use d_splice_alias") Refactor interpose code to allow lookup to use d_splice_alias. Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: Icf51db8658202c48456724275b03dc77f73f585b --- fs/sdcardfs/lookup.c | 55 +++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index c2f29d95f06f..dcf54a3e644c 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -164,27 +164,25 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u } /* - * Connect a sdcardfs inode dentry/inode with several lower ones. This is - * the classic stackable file system "vnode interposition" action. - * - * @dentry: sdcardfs's dentry which interposes on lower one - * @sb: sdcardfs's super_block - * @lower_path: the lower path (caller does path_get/put) + * Helper interpose routine, called directly by ->lookup to handle + * spliced dentries. */ -int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, - struct path *lower_path, userid_t id) +static struct dentry *__sdcardfs_interpose(struct dentry *dentry, + struct super_block *sb, + struct path *lower_path, + userid_t id) { - int err = 0; struct inode *inode; struct inode *lower_inode; struct super_block *lower_sb; + struct dentry *ret_dentry; lower_inode = lower_path->dentry->d_inode; lower_sb = sdcardfs_lower_super(sb); /* check that the lower file system didn't cross a mount point */ if (lower_inode->i_sb != lower_sb) { - err = -EXDEV; + ret_dentry = ERR_PTR(-EXDEV); goto out; } @@ -196,14 +194,32 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, /* inherit lower inode number for sdcardfs's inode */ inode = sdcardfs_iget(sb, lower_inode, id); if (IS_ERR(inode)) { - err = PTR_ERR(inode); + ret_dentry = ERR_CAST(inode); goto out; } - d_add(dentry, inode); + ret_dentry = d_splice_alias(inode, dentry); + dentry = ret_dentry ?: dentry; update_derived_permission_lock(dentry); out: - return err; + return ret_dentry; +} + +/* + * Connect an sdcardfs inode dentry/inode with several lower ones. This is + * the classic stackable file system "vnode interposition" action. + * + * @dentry: sdcardfs's dentry which interposes on lower one + * @sb: sdcardfs's super_block + * @lower_path: the lower path (caller does path_get/put) + */ +int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, + struct path *lower_path, userid_t id) +{ + struct dentry *ret_dentry; + + ret_dentry = __sdcardfs_interpose(dentry, sb, lower_path, id); + return PTR_ERR(ret_dentry); } struct sdcardfs_name_data { @@ -244,6 +260,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, const struct qstr *name; struct path lower_path; struct qstr dname; + struct dentry *ret_dentry = NULL; struct sdcardfs_sb_info *sbi; sbi = SDCARDFS_SB(dentry->d_sb); @@ -330,9 +347,13 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, } sdcardfs_set_lower_path(dentry, &lower_path); - err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id); - if (err) /* path_put underlying path on error */ + ret_dentry = + __sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id); + if (IS_ERR(ret_dentry)) { + err = PTR_ERR(ret_dentry); + /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); + } goto out; } @@ -372,7 +393,9 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, err = 0; out: - return ERR_PTR(err); + if (err) + return ERR_PTR(err); + return ret_dentry; } /* From 1ec3abbf538ecf3f75c8192d66eb327948de28ed Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 9 Mar 2017 20:56:05 -0800 Subject: [PATCH 224/281] ANDROID: sdcardfs: update module info Signed-off-by: Daniel Rosenberg Change-Id: I958c7c226d4e9265fea8996803e5b004fb33d8ad --- fs/sdcardfs/main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 4031e4b2ee70..bf3d3ab9395e 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -478,10 +478,15 @@ static void __exit exit_sdcardfs_fs(void) pr_info("Completed sdcardfs module unload\n"); } -MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University" - " (http://www.fsl.cs.sunysb.edu/)"); -MODULE_DESCRIPTION("Wrapfs " SDCARDFS_VERSION - " (http://wrapfs.filesystems.org/)"); +/* Original wrapfs authors */ +MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University (http://www.fsl.cs.sunysb.edu/)"); + +/* Original sdcardfs authors */ +MODULE_AUTHOR("Woojoong Lee, Daeho Jeong, Kitae Lee, Yeongjin Gil System Memory Lab., Samsung Electronics"); + +/* Current maintainer */ +MODULE_AUTHOR("Daniel Rosenberg, Google"); +MODULE_DESCRIPTION("Sdcardfs " SDCARDFS_VERSION); MODULE_LICENSE("GPL"); module_init(init_sdcardfs_fs); From cbe50872c53426998075fad51dc7dca2cd228417 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Mar 2015 20:08:18 -0400 Subject: [PATCH 225/281] BACKPORT: UPSTREAM: sg_start_req(): make sure that there's not too many elements in iovec unfortunately, allowing an arbitrary 16bit value means a possibility of overflow in the calculation of total number of pages in bio_map_user_iov() - we rely on there being no more than PAGE_SIZE members of sum in the first loop there. If that sum wraps around, we end up allocating too small array of pointers to pages and it's easy to overflow it in the second loop. Bug: 35841297 X-Coverup: TINC (and there's no lumber cartel either) Cc: stable@vger.kernel.org # way, way back Signed-off-by: Al Viro [toddpoynor@google.com: fixups for 3.10] Change-Id: If219704c2af20796221461c1e57e687546185d4a --- drivers/scsi/sg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 59efcbb9e0b2..7668c9cd4155 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1702,6 +1702,9 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->from_user = 0; } + if (unlikely(iov_count > UIO_MAXIOV)) + return -EINVAL; + if (iov_count) { int len, size = sizeof(struct sg_iovec) * iov_count; struct iovec *iov; From 7e6711ffff0d8762391084276909d27a549ff92e Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 31 Jan 2017 11:54:04 -0500 Subject: [PATCH 226/281] BACKPORT: UPSTREAM: selinux: fix off-by-one in setprocattr SELinux tries to support setting/clearing of /proc/pid/attr attributes from the shell by ignoring terminating newlines and treating an attribute value that begins with a NUL or newline as an attempt to clear the attribute. However, the test for clearing attributes has always been wrong; it has an off-by-one error, and this could further lead to reading past the end of the allocated buffer since commit bb646cdb12e75d82258c2f2e7746d5952d3e321a ("proc_pid_attr_write(): switch to memdup_user()"). Fix the off-by-one error. Even with this fix, setting and clearing /proc/pid/attr attributes from the shell is not straightforward since the interface does not support multiple write() calls (so shells that write the value and newline separately will set and then immediately clear the attribute, requiring use of echo -n to set the attribute), whereas trying to use echo -n "" to clear the attribute causes the shell to skip the write() call altogether since POSIX says that a zero-length write causes no side effects. Thus, one must use echo -n to set and echo without -n to clear, as in the following example: $ echo -n unconfined_u:object_r:user_home_t:s0 > /proc/$$/attr/fscreate $ cat /proc/$$/attr/fscreate unconfined_u:object_r:user_home_t:s0 $ echo "" > /proc/$$/attr/fscreate $ cat /proc/$$/attr/fscreate Note the use of /proc/$$ rather than /proc/self, as otherwise the cat command will read its own attribute value, not that of the shell. There are no users of this facility to my knowledge; possibly we should just get rid of it. UPDATE: Upon further investigation it appears that a local process with the process:setfscreate permission can cause a kernel panic as a result of this bug. This patch fixes CVE-2017-2618. Signed-off-by: Stephen Smalley [PM: added the update about CVE-2017-2618 to the commit description] Cc: stable@vger.kernel.org # 3.5: d6ea83ec6864e Signed-off-by: Paul Moore Signed-off-by: James Morris Bug: 35136920 Upstream commit: 0c461cb727d146c9ef2d3e86214f498b78b7d125 Change-Id: I41ba111bd79f6f60306316eb6de0425b1b7d8d19 --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7f0ec618af0b..7e60237ec0b5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5610,7 +5610,7 @@ static int selinux_setprocattr(struct task_struct *p, return error; /* Obtain a SID for the context, if one was specified. */ - if (size && str[1] && str[1] != '\n') { + if (size && str[0] && str[0] != '\n') { if (str[size-1] == '\n') { str[size-1] = 0; size--; From 63cfc760116ad67b6cc6ccd246fc67653357ec0e Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 10 Apr 2017 20:54:30 -0700 Subject: [PATCH 227/281] ANDROID: sdcardfs: Directly pass lower file for mmap Instead of relying on a copy hack, pass the lower file as private data. This lets the kernel find the vma mapping for pages used by the file, allowing pages used by mapping to be reclaimed. This is adapted from following esdfs patches commit 0647e638d: ("esdfs: store lower file in vm_file for mmap") commit 064850866: ("esdfs: keep a counter for mmaped file") Change-Id: I75b74d1e5061db1b8c13be38d184e118c0851a1a Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/file.c | 3 +++ fs/sdcardfs/mmap.c | 57 ++++++++++++++++++---------------------------- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 33c416eeddd2..8943bef34096 100755 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -192,6 +192,9 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */ if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */ SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops; + vma->vm_private_data = file; + get_file(lower_file); + vma->vm_file = lower_file; out: return err; diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c index 9ec452391072..96759ca827e3 100755 --- a/fs/sdcardfs/mmap.c +++ b/fs/sdcardfs/mmap.c @@ -23,60 +23,45 @@ static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { int err; - struct file *file, *lower_file; + struct file *file; const struct vm_operations_struct *lower_vm_ops; - struct vm_area_struct lower_vma; - memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); - file = lower_vma.vm_file; + file = (struct file *)vma->vm_private_data; lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; BUG_ON(!lower_vm_ops); - lower_file = sdcardfs_lower_file(file); - /* - * XXX: vm_ops->fault may be called in parallel. Because we have to - * resort to temporarily changing the vma->vm_file to point to the - * lower file, a concurrent invocation of sdcardfs_fault could see a - * different value. In this workaround, we keep a different copy of - * the vma structure in our stack, so we never expose a different - * value of the vma->vm_file called to us, even temporarily. A - * better fix would be to change the calling semantics of ->fault to - * take an explicit file pointer. - */ - lower_vma.vm_file = lower_file; - err = lower_vm_ops->fault(&lower_vma, vmf); + err = lower_vm_ops->fault(vma, vmf); return err; } +static void sdcardfs_vm_open(struct vm_area_struct *vma) +{ + struct file *file = (struct file *)vma->vm_private_data; + + get_file(file); +} + +static void sdcardfs_vm_close(struct vm_area_struct *vma) +{ + struct file *file = (struct file *)vma->vm_private_data; + + fput(file); +} + static int sdcardfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { int err = 0; - struct file *file, *lower_file; + struct file *file; const struct vm_operations_struct *lower_vm_ops; - struct vm_area_struct lower_vma; - memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); - file = lower_vma.vm_file; + file = (struct file *)vma->vm_private_data; lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; BUG_ON(!lower_vm_ops); if (!lower_vm_ops->page_mkwrite) goto out; - lower_file = sdcardfs_lower_file(file); - /* - * XXX: vm_ops->page_mkwrite may be called in parallel. - * Because we have to resort to temporarily changing the - * vma->vm_file to point to the lower file, a concurrent - * invocation of sdcardfs_page_mkwrite could see a different - * value. In this workaround, we keep a different copy of the - * vma structure in our stack, so we never expose a different - * value of the vma->vm_file called to us, even temporarily. - * A better fix would be to change the calling semantics of - * ->page_mkwrite to take an explicit file pointer. - */ - lower_vma.vm_file = lower_file; - err = lower_vm_ops->page_mkwrite(&lower_vma, vmf); + err = lower_vm_ops->page_mkwrite(vma, vmf); out: return err; } @@ -100,4 +85,6 @@ const struct address_space_operations sdcardfs_aops = { const struct vm_operations_struct sdcardfs_vm_ops = { .fault = sdcardfs_fault, .page_mkwrite = sdcardfs_page_mkwrite, + .open = sdcardfs_vm_open, + .close = sdcardfs_vm_close, }; From 6d340f9c8a3629faa88f7d89999c6ea0e06fc070 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 17 Apr 2017 17:11:38 -0700 Subject: [PATCH 228/281] Android: sdcardfs: Change cache GID value Change-Id: Ieb955dd26493da26a458bc20fbbe75bca32b094f Signed-off-by: Daniel Rosenberg Bug: 37193650 --- fs/sdcardfs/derived_perm.c | 2 +- fs/sdcardfs/multiuser.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 668b83f1c1db..1ca15dc28bad 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -221,7 +221,7 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) break; case PERM_ANDROID_PACKAGE_CACHE: if (info->d_uid != 0) - gid = multiuser_get_cache_gid(info->d_uid); + gid = multiuser_get_ext_cache_gid(info->d_uid); else gid = multiuser_get_uid(info->userid, uid); break; diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index 2e89b5872314..d0c925cda299 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -23,6 +23,8 @@ #define AID_APP_END 19999 /* last app user */ #define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */ #define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */ +#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */ +#define AID_EXT_CACHE_GID_END 49999 /* end of gids for apps to mark external cached data */ #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ typedef uid_t userid_t; @@ -33,9 +35,9 @@ static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); } -static inline gid_t multiuser_get_cache_gid(uid_t uid) +static inline gid_t multiuser_get_ext_cache_gid(uid_t uid) { - return uid - AID_APP_START + AID_CACHE_GID_START; + return uid - AID_APP_START + AID_EXT_CACHE_GID_START; } static inline gid_t multiuser_get_ext_gid(uid_t uid) From c6e916c5e6101596c2d6f64c62bdc87b9d64c90c Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 18 Apr 2017 12:45:48 -0700 Subject: [PATCH 229/281] ANDROID: sdcardfs: ->iget fixes Adapted from wrapfs commit 8c49eaa0sb9c ("Wrapfs: ->iget fixes") Change where we igrab/iput to ensure we always hold a valid lower_inode. Return ENOMEM (not EACCES) if iget5_locked returns NULL. Signed-off-by: Erez Zadok Signed-off-by: Daniel Rosenberg Bug: 35766959 Change-Id: Id8d4e0c0cbc685a0a77685ce73c923e9a3ddc094 --- fs/sdcardfs/lookup.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index dcf54a3e644c..3ac40fead490 100755 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -91,7 +91,9 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u struct sdcardfs_inode_info *info; struct inode_data data; struct inode *inode; /* the new inode to return */ - int err; + + if (!igrab(lower_inode)) + return ERR_PTR(-ESTALE); data.id = id; data.lower_inode = lower_inode; @@ -106,22 +108,19 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u sdcardfs_inode_set, /* inode init function */ &data); /* data passed to test+set fxns */ if (!inode) { - err = -EACCES; iput(lower_inode); - return ERR_PTR(err); + return ERR_PTR(-ENOMEM); } - /* if found a cached inode, then just return it */ - if (!(inode->i_state & I_NEW)) + /* if found a cached inode, then just return it (after iput) */ + if (!(inode->i_state & I_NEW)) { + iput(lower_inode); return inode; + } /* initialize new inode */ info = SDCARDFS_I(inode); inode->i_ino = lower_inode->i_ino; - if (!igrab(lower_inode)) { - err = -ESTALE; - return ERR_PTR(err); - } sdcardfs_set_lower_inode(inode, lower_inode); inode->i_version++; From c1007305a4f1e1f1a14806f4f80373c07e16204f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Tue, 18 Apr 2017 22:49:38 -0700 Subject: [PATCH 230/281] Android: sdcardfs: Don't complain in fixup_lower_ownership Not all filesystems support changing the owner of a file. We shouldn't complain if it doesn't happen. Signed-off-by: Daniel Rosenberg Bug: 37488099 Change-Id: I403e44ab7230f176e6df82f6adb4e5c82ce57f33 --- fs/sdcardfs/derived_perm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c index 1ca15dc28bad..9a281b68c408 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -245,7 +245,7 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) error = notify_change2(path.mnt, path.dentry, &newattrs); mutex_unlock(&inode->i_mutex); if (error) - pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n"); + pr_debug("sdcardfs: Failed to touch up lower fs gid/uid for %s\n", name); } sdcardfs_put_lower_path(dentry, &path); } From ade55c044a468579a01acb8340795bb268115ca2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 4 Feb 2017 11:16:52 -0800 Subject: [PATCH 231/281] ipv4: keep skb->dst around in presence of IP options Andrey Konovalov got crashes in __ip_options_echo() when a NULL skb->dst is accessed. ipv4_pktinfo_prepare() should not drop the dst if (evil) IP options are present. We could refine the test to the presence of ts_needtime or srr, but IP options are not often used, so let's be conservative. Thanks to syzkaller team for finding this bug. Upstream commit: 34b2cef20f19c87999fff3da4071e66937db9644 Fixes: d826eb14ecef ("ipv4: PKTINFO doesnt need dst reference") Signed-off-by: Eric Dumazet Reported-by: Andrey Konovalov Signed-off-by: David S. Miller Change-Id: I57c61b5902cd7b823c04cdf29723c643371296a1 --- net/ipv4/ip_sockglue.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 23e6ab0a2dc0..b9dcaefe115b 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1046,7 +1046,14 @@ void ipv4_pktinfo_prepare(struct sk_buff *skb) pktinfo->ipi_ifindex = 0; pktinfo->ipi_spec_dst.s_addr = 0; } - skb_dst_drop(skb); + /* We need to keep the dst for __ip_options_echo() + * We could restrict the test to opt.ts_needtime || opt.srr, + * but the following is good enough as IP options are not often used. + */ + if (unlikely(IPCB(skb)->opt.optlen)) + skb_dst_force(skb); + else + skb_dst_drop(skb); } int ip_setsockopt(struct sock *sk, int level, From 1be4a03abd7e99b7e4b088993067546e0f78d13c Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Thu, 9 Mar 2017 18:05:51 +0530 Subject: [PATCH 232/281] wlan: Changes to force roam in low RSSI scenarios It could be possible that current AP might have better score even if RSSI is very low, which may cause DUT to discard better RSSI candidate and eventually disconnect from current AP. Add changes to make current AP score as zero if current AP RSSI is less than gPERMinRssiThresholdForRoam configuration value. CRs-Fixed: 2017287 Change-Id: Iabf3695b406781f407df80de560616e7e564495a --- drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 947489cd87e0..23ab858c355f 100644 --- a/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c +++ b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c @@ -2281,6 +2281,18 @@ static tANI_S32 csrFindSelfCongestionScore(tpAniSirGlobal pMac, if (pSession == NULL) return -1; + if (bssInfo->rssi < pMac->roam.configParam.PERMinRssiThresholdForRoam) { + smsLog(pMac, LOG1, + FL("Current AP has low rssi=%d than %d"), bssInfo->rssi, + pMac->roam.configParam.PERMinRssiThresholdForRoam); + /* + * Make Current candidate score as zero which will cause roaming + * in low RSSI scenarios + */ + pMac->currentBssScore = 0; + return 0; + } + for (i = 0; i <= pMac->PERroamCandidatesCnt; i++) if (pMac->candidateChannelInfo[i].channelNumber == bssInfo->channelId) break; From 107a88ba1625869f5f3f565f3e431a0463c1e6c2 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Wed, 15 Mar 2017 17:29:10 +0530 Subject: [PATCH 233/281] wlan: Indicate disconnect to SME to abort pre-auth If connect is received when SME is already connected, HDD try to disconnect the current connection and post disconnect to SME. If preauth is in progress the disconnect may get timeout and once again new connect is received which removes disconnect cmd from SME queue and tries to connect to new AP. This causes firmware to crash as BSS is already present for the session. To fix this indicate disconnect to SME so that preauth is aborted as soon as possible. Change-Id: I6c3ed5344950cb5acfe9df82acaeb77f605e1d28 CRs-Fixed: 2019891 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index f55a1f46e3c9..7e4eef8ce0f8 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -14681,6 +14681,11 @@ static int wlan_hdd_try_disconnect( hdd_adapter_t *pAdapter ) (eConnectionState_Connecting == pHddStaCtx->conn_info.connState) || (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)) { + /* Indicate disconnect to SME so that in-progress connection or preauth + * can be aborted + */ + sme_abortConnection(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId); spin_lock_bh(&pAdapter->lock_for_active_session); if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) { From 1517066651e88b5fbc96f3a49ea43b138f697b61 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:20:11 +0530 Subject: [PATCH 234/281] wlan: Interface API change for NUD stats debug Add interface api, for communication between FW and host for NUD debug stats Change-Id: Iba1282fbecb703140f89f7fdb733962c0c50458a CRs-Fixed: 1115233 --- drivers/staging/prima/riva/inc/wlan_hal_msg.h | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/staging/prima/riva/inc/wlan_hal_msg.h b/drivers/staging/prima/riva/inc/wlan_hal_msg.h index 581862c9307c..a74f2e4e7465 100644 --- a/drivers/staging/prima/riva/inc/wlan_hal_msg.h +++ b/drivers/staging/prima/riva/inc/wlan_hal_msg.h @@ -605,6 +605,11 @@ typedef enum WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ = 336, WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP = 337, + WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ = 354, + WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP = 355, + WLAN_HAL_FW_GET_ARP_STATS_REQ = 356, + WLAN_HAL_FW_GET_ARP_STATS_RSP = 357, + WLAN_HAL_MSG_MAX = WLAN_HAL_MSG_TYPE_MAX_ENUM_SIZE }tHalHostMsgType; @@ -6876,6 +6881,7 @@ typedef enum { WIFI_CONFIG = 61, ANTENNA_DIVERSITY_SELECTION = 62, PER_BASED_ROAMING = 63, + NUD_DEBUG = 68, MAX_FEATURE_SUPPORTED = 128, } placeHolderInCapBitmap; @@ -9302,6 +9308,69 @@ typedef PACKED_PRE struct PACKED_POST tHalModifyRoamParamsIndParams modifyRoamParamsReqParams; } tHalModifyRoamParamsInd, *tpHalModifyRoamParamsInd; +/*--------------------------------------------------------------------------- + * WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ + *--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 set_clr; /*1 set and 0 reset*/ + tANI_U8 pkt_type; /* Default 1: ARP */ + tANI_U32 ip_addr; /*GW ipv4 address */ +} tHalStatsArpReqParams, *tpHalStatsArpReqParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStatsArpReqParams statsArpReqParams; +} tHalStatsArpReqMsg, *tpHalStatsArpReqMsg; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP + *--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 status; //success or failure +} tHalStatsArpRspParams, *tpHalStatsArpRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStatsArpRspParams statsArpRspParams; +} tHalStatsArpRspMsg, *tpHalStatsArpRspMsg; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_FW_GET_ARP_STATS_REQ + *--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U8 pkt_type; /* Furture purpose */ +} tHalStatsGetArpReqParams, *tpHalStatsGetArpReqParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tHalStatsGetArpReqParams statsGetArpReqParams; +} tHalStatsGetArpReqMsg, *tpHalStatsGetArpReqMsg; + +/*--------------------------------------------------------------------------- + * WLAN_HAL_FW_GET_ARP_STATS_RSP + *--------------------------------------------------------------------------*/ +typedef PACKED_PRE struct PACKED_POST +{ + tANI_U32 status; + tANI_U16 dad; + tANI_U16 arpReqRcvdInFW; + tANI_U16 ackedArpReqCnt; + tANI_U16 arpRspCnt; + tANI_U8 data[1]; +} tdbugArpStatsgetRspParams, *tpdbugArpStatsgetRspParams; + +typedef PACKED_PRE struct PACKED_POST +{ + tHalMsgHeader header; + tdbugArpStatsgetRspParams fwArpstatsRspParams; +} tHalARPfwStatsRspMsg, *tpHalARPfwStatsRspMsg; + #if defined(__ANI_COMPILER_PRAGMA_PACK_STACK) #pragma pack(pop) #elif defined(__ANI_COMPILER_PRAGMA_PACK) From 85e26c60b17f18e7b3bfa9e9b0c140690be18e66 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Mon, 6 Mar 2017 11:35:34 +0530 Subject: [PATCH 235/281] wlan: Fix SAP SSR reinit for uninitialized config qcacld-2.0 to prima propagation. SSR can happen during SAP initialization. Thus check for SAP initialization complete before attempting to restart SAP instance during SSR. Change-Id: Ib26116cfc33684035df692ae6c7b5d83cb0a27b8 CRs-fixed: 2005281 --- drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h | 1 + .../staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 14 ++++++++++++-- .../prima/CORE/HDD/src/wlan_hdd_early_suspend.c | 7 ++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 317d0a24cef0..5d5ebd96218a 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -101,6 +101,7 @@ #define SOFTAP_BSS_STARTED (4) #define DEVICE_IFACE_OPENED (5) #define TDLS_INIT_DONE (6) +#define SOFTAP_INIT_DONE (7) /** Maximum time(ms)to wait for disconnect to complete **/ #define WLAN_WAIT_TIME_DISCONNECT 5000 diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 7e4eef8ce0f8..cc7585f0a865 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -9235,7 +9235,7 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, eCsrAuthType RSNAuthType; eCsrEncryptionType RSNEncryptType; eCsrEncryptionType mcRSNEncryptType; - int status = VOS_STATUS_SUCCESS; + int status = VOS_STATUS_SUCCESS, ret = 0; tpWLAN_SAPEventCB pSapEventCallback; hdd_hostapd_state_t *pHostapdState; v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext; @@ -9680,12 +9680,15 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, } pConfig->acsBandSwitchThreshold = iniConfig->acsBandSwitchThreshold; + set_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags); + pSapEventCallback = hdd_hostapd_SAPEventCB; if(WLANSAP_StartBss(pVosContext, pSapEventCallback, pConfig, (v_PVOID_t)pHostapdAdapter->dev) != VOS_STATUS_SUCCESS) { hddLog(LOGE,FL("SAP Start Bss fail")); - return -EINVAL; + ret = -EINVAL; + goto error; } hddLog(LOG1, @@ -9728,6 +9731,9 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, EXIT(); return 0; +error: + clear_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags); + return ret; } #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) @@ -10007,6 +10013,8 @@ static int __wlan_hdd_cfg80211_stop_ap (struct wiphy *wiphy, // Reset WNI_CFG_PROBE_RSP Flags wlan_hdd_reset_prob_rspies(pAdapter); + clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags); + pAdapter->sessionCtx.ap.beacon = NULL; kfree(old); #ifdef WLAN_FEATURE_P2P_DEBUG @@ -10086,6 +10094,8 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, return -ENODEV; } + clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); status = wlan_hdd_validate_context(pHddCtx); if (0 != status) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c index f7547fe5e9ab..3817d5ca9bc4 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -2335,9 +2335,10 @@ static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx) while (NULL != adapter_node && VOS_STATUS_SUCCESS == status) { adapter = adapter_node->pAdapter; if (adapter && adapter->device_mode == WLAN_HDD_SOFTAP) { - hddLog(VOS_TRACE_LEVEL_INFO, FL("in sap mode %p"), - adapter); - wlan_hdd_start_sap(adapter); + if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) { + hddLog(VOS_TRACE_LEVEL_INFO, FL("Restart prev SAP session")); + wlan_hdd_start_sap(adapter); + } } status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); adapter_node = next; From f4fea9ea3254e8e0c88f6d6a4b529071aedb7917 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:21:57 +0530 Subject: [PATCH 236/281] wlan: Add Vendor command to set/get NUD debug stats Add vendor commands to set/reset and get NUD debug stats from firmware. Change-Id: Ib016a4580a97d7048c6c1c06ae51264ce0342f27 CRs-Fixed: 1115214 --- .../prima/CORE/HDD/inc/wlan_hdd_cfg80211.h | 62 +++ .../prima/CORE/HDD/inc/wlan_hdd_main.h | 59 +++ .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 370 +++++++++++++++++- .../prima/CORE/HDD/src/wlan_hdd_main.c | 1 + drivers/staging/prima/CORE/MAC/inc/sirApi.h | 46 +++ .../prima/CORE/MAC/src/include/sirParams.h | 5 + drivers/staging/prima/CORE/SME/inc/sme_Api.h | 8 +- .../prima/CORE/SME/src/sme_common/sme_Api.c | 70 ++++ .../CORE/SYS/legacy/src/utils/src/macTrace.c | 2 + .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 6 +- .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 270 +++++++++++++ .../prima/CORE/WDI/CP/inc/wlan_qct_wdi.h | 53 +++ .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h | 35 +- .../prima/CORE/WDI/CP/src/wlan_qct_wdi.c | 316 +++++++++++++++ 14 files changed, 1298 insertions(+), 5 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h index f00390dcc22f..d1ca157f87ea 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -197,6 +197,11 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101, QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105, + + /* Start / Stop the NUD stats collections */ + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149, + /* Get the NUD stats, represented by the enum qca_attr_nud_stats_get */ + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150, }; enum qca_nl80211_vendor_subcmds_index { @@ -232,6 +237,63 @@ enum qca_nl80211_vendor_subcmds_index { QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX, +}; + +/** + * qca_wlan_vendor_attr_nud_stats_set: attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carry the requisite + * information to start / stop the NUD stats collection. + */ +enum qca_attr_nud_stats_set { + QCA_ATTR_NUD_STATS_SET_INVALID = 0, + + /* Flag to Start / Stop the NUD stats collection + * Start - If included , Stop - If not included + */ + QCA_ATTR_NUD_STATS_SET_START = 1, + /* IPv4 address of Default Gateway (in network byte order) */ + QCA_ATTR_NUD_STATS_GW_IPV4 = 2, + + /* keep last */ + QCA_ATTR_NUD_STATS_SET_LAST, + QCA_ATTR_NUD_STATS_SET_MAX = + QCA_ATTR_NUD_STATS_SET_LAST - 1, +}; + +/** + * qca_attr_nud_stats_get: attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carry the requisite + * NUD stats collected when queried. + */ +enum qca_attr_nud_stats_get { + QCA_ATTR_NUD_STATS_GET_INVALID = 0, + /* ARP Request Count from net dev */ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1, + /* ARP Request Count sent to lower MAC from upper MAC */ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2, + /* ARP Request Count received by lower MAC from upper MAC */ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3, + /* ARP Request Count successfully transmitted by the device */ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4, + /* ARP Response Count received by lower MAC */ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5, + /* ARP Response Count received by upper MAC */ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6, + /* ARP Response Count delivered to netdev */ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7, + /* ARP Response Count delivered to netdev */ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8, + /* + * Flag indicating if the Stations Link to AP is active. + * Active Link - If exists, Inactive link - If not included + */ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE= 9, + QCA_ATTR_NUD_STATS_AP_LINK_DAD= 10, + /* keep last */ + QCA_ATTR_NUD_STATS_GET_LAST, + QCA_ATTR_NUD_STATS_GET_MAX = + QCA_ATTR_NUD_STATS_GET_LAST - 1, }; enum qca_wlan_vendor_attr diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 5d5ebd96218a..cfcfeb7ad29a 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -377,6 +377,35 @@ typedef struct hdd_pmf_stats_s } hdd_pmf_stats_t; #endif +typedef enum +{ + HDD_TX_FRAME_IN_NOT_ASSOCIATED_STATE = 0, + HDD_VOS_PACKET_RETURNED_BY_VOSS_IS_NULL, + HDD_WLANTL_STAPKTPENDING_RETURNED_ERROR_CODE, + HDD_INSERT_TX_QUEUE_FAILED, + HDD_FAILED_TO_SIGNAL_TL, + HDD_ERROR_ATTACHING_SKB, + HDD_FAILURE_EXTRACTING_SKB_FROM_VOS_PKT, + HDD_FAILURE_WALKING_PACKET_CHAIN, + HDD_STA_RX_ARP_PACKET_REFUSED_IN_NET_STACK +} HDD_PACKET_DROP_CAUSE; + +typedef struct hdd_arp_stats_s +{ + uint16 txCount; + uint16 rxCount; + uint16 txDropped; + uint16 rxDropped; + uint16 rxDelivered; + uint16 rxRefused; + uint16 tx_host_fw_sent; + uint16 rx_host_drop_reorder; + uint16_t tx_fw_cnt; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; + HDD_PACKET_DROP_CAUSE reason; +} hdd_arp_stats_t; + typedef struct hdd_stats_s { tCsrSummaryStatsInfo summary_stat; @@ -387,6 +416,7 @@ typedef struct hdd_stats_s tCsrPerStaStatsInfo perStaStats; hdd_tx_rx_stats_t hddTxRxStats; hdd_chip_reset_stats_t hddChipResetStats; + hdd_arp_stats_t hddArpStats; #ifdef WLAN_FEATURE_11W hdd_pmf_stats_t hddPmfStats; #endif @@ -1217,6 +1247,8 @@ struct hdd_adapter_s /* Currently used antenna Index*/ int antennaIndex; + bool con_status; + bool dad; }; #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) @@ -1274,6 +1306,10 @@ typedef struct #define WLAN_WAIT_TIME_LL_STATS 800 +#define WLAN_WAIT_TIME_NUD_STATS 800 +#define WLAN_NUD_STATS_LEN 800 +#define WLAN_NUD_STATS_ARP_PKT_TYPE 1 + /* FW memory dump feature @TODO : Move this code to a separate file later */ #define PROCFS_MEMDUMP_DIR "debug" @@ -1321,6 +1357,15 @@ struct hdd_ll_stats_context { struct completion response_event; }; #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * struct hdd_nud_stats_context - hdd NUD stats context + * + * @response_event: NUD stats request wait event + */ +struct hdd_nud_stats_context { + struct completion response_event; +}; #ifdef WLAN_FEATURE_EXTSCAN /** * struct hdd_ext_scan_context - hdd ext scan context @@ -1606,6 +1651,7 @@ struct hdd_context_s #ifdef WLAN_FEATURE_LINK_LAYER_STATS struct hdd_ll_stats_context ll_stats_context; #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + struct hdd_nud_stats_context nud_stats_context; #ifdef WLAN_FEATURE_EXTSCAN struct hdd_ext_scan_context ext_scan_context; @@ -1956,6 +2002,19 @@ static inline void hdd_init_ll_stat_ctx(void) return; } #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * hdd_init_nud_stats_ctx() - initialize NUD stats context + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_init_nud_stats_ctx(hdd_context_t *hdd_ctx) +{ + init_completion(&hdd_ctx->nud_stats_context.response_event); + return; +} + void hdd_initialize_adapter_common(hdd_adapter_t *pAdapter); void hdd_wlan_free_wiphy_channels(struct wiphy *wiphy); void wlan_hdd_init_deinit_defer_scan_context(scan_context_t *scan_ctx); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index cc7585f0a865..7cab0bab586b 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -7464,6 +7464,353 @@ static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, return ret; } + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_SET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define STATS_SET_START \ + QCA_ATTR_NUD_STATS_SET_START +#define STATS_GW_IPV4 \ + QCA_ATTR_NUD_STATS_GW_IPV4 +#define STATS_SET_MAX \ + QCA_ATTR_NUD_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_nud_stats[STATS_SET_MAX +1] = +{ + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, +}; + +/** + * hdd_set_nud_stats_cb() - hdd callback api to get status + * @data: pointer to adapter + * @rsp: status + * + * Return: None + */ +static void hdd_set_nud_stats_cb(void *data, VOS_STATUS rsp) +{ + + hdd_adapter_t *adapter = (hdd_adapter_t *)data; + + if (NULL == adapter) + return; + + if (VOS_STATUS_SUCCESS == rsp) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s success received STATS_SET_START", __func__); + } else { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s STATS_SET_START Failed!!", __func__); + } + return; +} + +/** + * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[STATS_SET_MAX + 1]; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + setArpStatsParams arp_stats_params; + int err = 0; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s NUD_DEBUG feature not supported by firmware!!", __func__); + return -EINVAL; + } + + err = nla_parse(tb, STATS_SET_MAX, data, data_len, + qca_wlan_vendor_set_nud_stats); + if (err) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s STATS_SET_START ATTR", __func__); + return err; + } + + if (tb[STATS_SET_START]) + { + if (!tb[STATS_GW_IPV4]) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD", __func__); + return -EINVAL; + } + arp_stats_params.flag = true; + arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]); + } else { + arp_stats_params.flag = false; + } + if (arp_stats_params.flag) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s STATS_SET_START Cleared!!", __func__); + vos_mem_zero(&adapter->hdd_stats.hddArpStats, sizeof(adapter->hdd_stats.hddArpStats)); + } + + arp_stats_params.pkt_type = 1; // ARP packet type + + arp_stats_params.rsp_cb_fn = hdd_set_nud_stats_cb; + arp_stats_params.data_ctx = adapter; + + if (eHAL_STATUS_SUCCESS != + sme_set_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + EXIT(); + + return err; +} + +/** + * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} +#undef STATS_SET_INVALID +#undef STATS_SET_START +#undef STATS_GW_IPV4 +#undef STATS_SET_MAX + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_GET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define COUNT_FROM_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#define COUNT_TO_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#define RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#define COUNT_TX_SUCCESS \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#define RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#define RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#define RSP_COUNT_TO_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#define RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#define AP_LINK_ACTIVE \ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#define AP_LINK_DAD \ + QCA_ATTR_NUD_STATS_AP_LINK_DAD +#define STATS_GET_MAX \ + QCA_ATTR_NUD_STATS_GET_MAX + +const struct nla_policy +qca_wlan_vendor_get_nud_stats[STATS_GET_MAX +1] = +{ + [COUNT_FROM_NETDEV] = {.type = NLA_U16 }, + [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 }, + [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [COUNT_TX_SUCCESS] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 }, + [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 }, + [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 }, + [AP_LINK_ACTIVE] = {.type = NLA_FLAG }, + [AP_LINK_DAD] = {.type = NLA_FLAG }, +}; + +static void hdd_get_nud_stats_cb(void *data, rsp_stats *rsp) +{ + + hdd_adapter_t *adapter = (hdd_adapter_t *)data; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_nud_stats_context *context; + int status; + + ENTER(); + + if (NULL == adapter) + return; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + return; + } + + if (!rsp) { + hddLog(LOGE, FL("data is null")); + return; + } + + adapter->hdd_stats.hddArpStats.tx_fw_cnt = rsp->tx_fw_cnt; + adapter->hdd_stats.hddArpStats.rx_fw_cnt = rsp->rx_fw_cnt; + adapter->hdd_stats.hddArpStats.tx_ack_cnt = rsp->tx_ack_cnt; + adapter->dad |= rsp->dad; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + complete(&context->response_event); + spin_unlock(&hdd_context_lock); + + return; +} +static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int err = 0; + unsigned long rc; + struct hdd_nud_stats_context *context; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + getArpStatsParams arp_stats_params; + struct sk_buff *skb; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.get_rsp_cb_fn = hdd_get_nud_stats_cb; + arp_stats_params.data_ctx = adapter; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + + if (!sme_IsFeatureSupportedByFW(NUD_DEBUG)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s NUD_DEBUG feature not supported by firmware!!", __func__); + return -EINVAL; + } + + if (eHAL_STATUS_SUCCESS != + sme_get_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_NUD_STATS)); + if (!rc) + { + hddLog(LOGE, + FL("Target response timed out request ")); + return -ETIMEDOUT; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + WLAN_NUD_STATS_LEN); + if (!skb) + { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: cfg80211_vendor_cmd_alloc_reply_skb failed", + __func__); + return -ENOMEM; + } + + if (nla_put_u16(skb, COUNT_FROM_NETDEV, + adapter->hdd_stats.hddArpStats.txCount) || + nla_put_u16(skb, COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hddArpStats.tx_host_fw_sent) || + nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hddArpStats.tx_fw_cnt) || + nla_put_u16(skb, COUNT_TX_SUCCESS, + adapter->hdd_stats.hddArpStats.tx_ack_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hddArpStats.rx_fw_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hddArpStats.rxCount) || + nla_put_u16(skb, RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hddArpStats.rxDelivered) || + nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hddArpStats.rx_host_drop_reorder)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(skb); + return -EINVAL; + } + if (adapter->con_status) + nla_put_flag(skb, AP_LINK_ACTIVE); + if (adapter->dad) + nla_put_flag(skb, AP_LINK_DAD); + + cfg80211_vendor_cmd_reply(skb); + return err; +} + +static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + vos_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len); + vos_ssr_unprotect(__func__); + + return ret; +} + +#undef QCA_ATTR_NUD_STATS_SET_INVALID +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#undef QCA_ATTR_NUD_STATS_GET_MAX + const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { @@ -7709,7 +8056,23 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_wifi_configuration_set - } + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_nud_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_nud_stats + }, }; /* vendor specific events */ @@ -7840,7 +8203,10 @@ struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST }, - + [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + }, }; /* diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c index 9d79eb2184c8..0a38b2d48eb7 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_main.c @@ -11801,6 +11801,7 @@ int hdd_wlan_startup(struct device *dev ) hdd_init_ll_stats_ctx(pHddCtx); + hdd_init_nud_stats_ctx(pHddCtx); #ifdef CONFIG_ENABLE_LINUX_REG init_completion(&pHddCtx->linux_reg_req); diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 3539665ae83d..67945175ea98 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -3789,11 +3789,57 @@ typedef struct tANI_U32 reserved2; }tAniLoggingInitRsp, *tpAniLoggingInitRsp; +/** + * struct rsp_stats - arp packet stats + * @status: success or failure + * @tx_fw_cnt: tx packets count + * @tx_ack_cnt: tx acknowledgement count + */ +typedef struct { + uint32_t status; + uint16_t dad; + uint16_t tx_fw_cnt; + uint16_t tx_ack_cnt; + uint16_t rx_fw_cnt; +} rsp_stats; + +typedef void(*setArpStatsReqCb)(void *data, VOS_STATUS rsp); + +/** + * struct setArpStatsParams - set/reset arp stats + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + * @rsp_cb_fn: FW response callback api + * @data_ctx: parameter for callback api + */ +typedef struct { + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; + setArpStatsReqCb rsp_cb_fn; + void *data_ctx; +} setArpStatsParams, *psetArpStatsParams; + +typedef void(*getArpStatsReqCb)(void *data, rsp_stats *rsp); +/** + * struct getArpStatsParams - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @get_rsp_cb_fn: FW response callback api + * @data_ctx: parameter for callback api + */ +typedef struct { + uint8_t pkt_type; + getArpStatsReqCb get_rsp_cb_fn; + void *data_ctx; +} getArpStatsParams, *pgetArpStatsParams; + typedef void(*FWLoggingInitReqCb)(void *fwlogInitCbContext, tAniLoggingInitRsp *pRsp); typedef void ( *tGetFrameLogCallback) (void *pContext); typedef void(*RssiMonitorReqCb)(void *rssiMonitorCbContext, VOS_STATUS status); typedef void(*pktFilterReqCb)(void *data, tANI_U32 status); + typedef struct sAniGetFrameLogReq { tANI_U16 msgType; diff --git a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h index b91e2fe6378d..8d3e8699bf67 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h +++ b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h @@ -144,6 +144,7 @@ typedef enum { #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD PER_BASED_ROAMING = 63, #endif + NUD_DEBUG = 68, //MAX_FEATURE_SUPPORTED = 128 } placeHolderInCapBitmap; @@ -765,6 +766,10 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_PER_ROAM_SCAN_TRIGGER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 289) #endif #define SIR_HAL_UPDATE_CFG_INT_PARAM (SIR_HAL_ITC_MSG_TYPES_BEGIN + 290) +/* ARP Debug stats */ +#define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 301) +#define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 302) + #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) // CFG message types diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 41a1640ae520..97467cbb228a 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3961,4 +3961,10 @@ eHalStatus sme_remove_bssid_from_scan_list(tHalHandle hal, void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, tANI_BOOLEAN sendMgmtPktViaWQ5); eHalStatus sme_update_cfg_int_param(tHalHandle hHal, tANI_U32 cfg_id); + +/* ARP DEBUG STATS */ +eHalStatus sme_set_nud_debug_stats(tHalHandle hHal, + psetArpStatsParams pSetStatsParam); +eHalStatus sme_get_nud_debug_stats(tHalHandle hHal, + pgetArpStatsParams pGetStatsParam); #endif //#if !defined( __SME_API_H ) diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index 158b36adb584..ba892cebba5a 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -14419,3 +14419,73 @@ void sme_set_mgmt_frm_via_wq5(tHalHandle hHal, tANI_BOOLEAN sendMgmtPktViaWQ5) } return; } + +/* ARP DEBUG STATS */ + +/** + * sme_set_nud_debug_stats() - sme api to set nud debug stats + * @hHal: handle to hal + * @pSetStatsParam: pointer to set stats param + */ +eHalStatus sme_set_nud_debug_stats(tHalHandle hHal, + setArpStatsParams *pSetStatsParam) +{ + setArpStatsParams *arp_set_param; + vos_msg_t msg; + + arp_set_param = vos_mem_malloc(sizeof(*arp_set_param)); + if (arp_set_param == NULL) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_copy(arp_set_param, pSetStatsParam, sizeof(*arp_set_param)); + + msg.type = WDA_SET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_set_param; + + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Not able to post message to WDA")); + vos_mem_free(arp_set_param); + return VOS_STATUS_E_FAILURE; + } + + return VOS_STATUS_SUCCESS; +} + +/** + * sme_get_nud_debug_stats() - sme api to get nud debug stats + * @hHal: handle to hal + * @pGetStatsParam: pointer to set stats param + */ +eHalStatus sme_get_nud_debug_stats(tHalHandle hHal, + getArpStatsParams *pGetStatsParam) +{ + getArpStatsParams *arpGetParams; + vos_msg_t msg; + + arpGetParams = vos_mem_malloc(sizeof(*arpGetParams)); + if (arpGetParams == NULL) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_copy(arpGetParams, pGetStatsParam, sizeof(*arpGetParams)); + + msg.type = WDA_GET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arpGetParams; + + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Not able to post message to WDA")); + vos_mem_free(arpGetParams); + return VOS_STATUS_E_FAILURE; + } + + return VOS_STATUS_SUCCESS; +} diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c index 12a8a6b5a40e..7c4703bbf548 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c @@ -906,6 +906,8 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) CASE_RETURN_STRING(WDA_MON_STOP_REQ); CASE_RETURN_STRING(WDA_SPOOF_MAC_ADDR_REQ); CASE_RETURN_STRING(WDA_LOST_LINK_PARAMS_IND); + CASE_RETURN_STRING(WDA_SET_ARP_STATS_REQ); + CASE_RETURN_STRING(WDA_GET_ARP_STATS_REQ); default: return((tANI_U8*) "UNKNOWN" ); break; diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index d058e45ac0dd..0dc52dd3f4ac 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1291,6 +1291,10 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_START_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_START_REQ #define WDA_STOP_RSSI_MONITOR_REQ SIR_HAL_RSSI_MON_STOP_REQ +/* ARP Debug */ +#define WDA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ +#define WDA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ + tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId, diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index d6df4091f01c..5d10db7f8cc9 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -15302,6 +15302,266 @@ VOS_STATUS WDA_ProcessTLPauseInd(tWDA_CbContext *pWDA, v_U32_t params) return WLANTL_SuspendDataTx(pWDA->pVosContext, &staId, NULL); } +/** + * WDA_SetARPStatsParamsRspCallback() - WDA callback api to set/reset arp stats + * @wdiSetStatsRsp: pointer to set stats response + * @user_data: user data + * + * Return: None + */ +void WDA_SetARPStatsParamsRspCallback( + WDI_SetARPStatsRspParamsType *wdiSetStatsRsp, + void *user_data) +{ + tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data; + setArpStatsParams *arpStatsParams; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "ENTER <------ %s " ,__func__); + + if(NULL == wda_params) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wda_params received NULL", __func__); + VOS_ASSERT(0); + return; + } + + if(NULL == wda_params->wdaMsgParam) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wda_params->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(wda_params->wdaWdiApiMsgParam); + vos_mem_free(wda_params); + return; + } + + arpStatsParams = (setArpStatsParams *)wda_params->wdaMsgParam; + if(arpStatsParams->rsp_cb_fn) + { + arpStatsParams->rsp_cb_fn(arpStatsParams->data_ctx, + CONVERT_WDI2VOS_STATUS(wdiSetStatsRsp->status)); + } + else + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: ARP stats callback is NULL", __func__); + } + + vos_mem_free(wda_params->wdaWdiApiMsgParam); + vos_mem_free(wda_params->wdaMsgParam); + vos_mem_free(wda_params); + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "EXIT <------ %s " ,__func__); + return; +} + +/** + * WDA_GetARPStatsParamsRspCallback() - WDA callback api to get arp stats + * @wdiGetStatsRsp: pointer to get stats response + * @user_data: user data + * + * Return: None + */ +void WDA_GetARPStatsParamsRspCallback( + WDI_GetARPStatsRspParamsType *wdiGetStatsRsp, + void *user_data) +{ + tWDA_ReqParams *wda_params = (tWDA_ReqParams *)user_data; + getArpStatsParams *arpStatsParams; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "ENTER <------ %s " ,__func__); + + if(NULL == wda_params) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wda_params received NULL", __func__); + VOS_ASSERT(0); + return; + } + + if(NULL == wda_params->wdaMsgParam) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: wda_params->wdaMsgParam is NULL", __func__); + VOS_ASSERT(0); + vos_mem_free(wda_params->wdaWdiApiMsgParam); + vos_mem_free(wda_params); + return; + } + + arpStatsParams = (getArpStatsParams *)wda_params->wdaMsgParam; + if(arpStatsParams->get_rsp_cb_fn) + { + arpStatsParams->get_rsp_cb_fn(arpStatsParams->data_ctx, + (rsp_stats *)wdiGetStatsRsp); + } + else + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: ARP stats callback is NULL", __func__); + } + + vos_mem_free(wda_params->wdaWdiApiMsgParam); + vos_mem_free(wda_params->wdaMsgParam); + vos_mem_free(wda_params); + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "EXIT <------ %s " ,__func__); + return; +} + +/** + * WDA_ProcessSetARPStatsReq() - WDA api to process set arp stats command + * @pWDA: wda handle + * @pSetStatsParams: pointer to set arp stats + * + * Return: VOS_STATUS + * 0 Success else failure + */ +VOS_STATUS WDA_ProcessSetARPStatsReq(tWDA_CbContext *pWDA, + setArpStatsParams *pSetStatsParams) +{ + WDI_SetARPStatsParamsInfoType *wdiSetStatsParam; + tWDA_ReqParams *wda_params; + WDI_Status wdi_status = WDI_STATUS_SUCCESS; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("---> %s"), __func__); + + if(NULL == pSetStatsParams) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pSetStatsParams received NULL", + __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + wdiSetStatsParam = (WDI_SetARPStatsParamsInfoType *) + vos_mem_malloc(sizeof(*wdiSetStatsParam)); + if (!wdiSetStatsParam) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to allocate buffer to send " + "set_dhcp_server_offload cmd"); + vos_mem_free(pSetStatsParams); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_zero(wdiSetStatsParam, sizeof(*wdiSetStatsParam)); + + wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == wda_params) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(wdiSetStatsParam); + vos_mem_free(pSetStatsParams); + return VOS_STATUS_E_NOMEM; + } + + wdiSetStatsParam->flag = pSetStatsParams->flag; + wdiSetStatsParam->pkt_type = pSetStatsParams->pkt_type; + wdiSetStatsParam->ip_addr = pSetStatsParams->ip_addr; + + /* Store Params pass it to WDI */ + wda_params->wdaWdiApiMsgParam = (void *)wdiSetStatsParam; + wda_params->pWdaContext = pWDA; + /* Store param pointer as passed in by caller */ + wda_params->wdaMsgParam = pSetStatsParams; + + wdi_status = WDI_SetARPStatsReq(wdiSetStatsParam, + (WDI_SetARPStatsRspCb)WDA_SetARPStatsParamsRspCallback, + wda_params); + + if(IS_WDI_STATUS_FAILURE(wdi_status)) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure, free all the memory", __func__); + vos_mem_free(wda_params->wdaWdiApiMsgParam) ; + vos_mem_free(wda_params->wdaMsgParam); + vos_mem_free(wda_params); + } + + return wdi_status; +} + +/** + * WDA_ProcessGetARPStatsReq() - WDA api to process get arp stats command + * @pWDA: wda handle + * @pGetStatsParams: pointer to get arp stats + * + * Return: VOS_STATUS + * 0 Success else failure + */ +VOS_STATUS WDA_ProcessGetARPStatsReq(tWDA_CbContext *pWDA, + getArpStatsParams *pGetStatsParams) +{ + WDI_GetARPStatsParamsInfoType *wdiGetStatsParam; + tWDA_ReqParams *wda_params; + WDI_Status wdi_status = WDI_STATUS_SUCCESS; + + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + FL("---> %s"), __func__); + + if(NULL == pGetStatsParams) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pGetStatsParams received NULL", + __func__); + VOS_ASSERT(0) ; + return VOS_STATUS_E_FAULT; + } + + wdiGetStatsParam = (WDI_GetARPStatsParamsInfoType *) + vos_mem_malloc(sizeof(*wdiGetStatsParam)); + if (!wdiGetStatsParam) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Failed to allocate buffer to send " + "set_dhcp_server_offload cmd"); + vos_mem_free(pGetStatsParams); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_zero(wdiGetStatsParam, sizeof(*wdiGetStatsParam)); + + wda_params = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ; + if(NULL == wda_params) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + vos_mem_free(wdiGetStatsParam); + vos_mem_free(pGetStatsParams); + return VOS_STATUS_E_NOMEM; + } + + wdiGetStatsParam->pkt_type = pGetStatsParams->pkt_type; + + /* Store Params pass it to WDI */ + wda_params->wdaWdiApiMsgParam = (void *)wdiGetStatsParam; + wda_params->pWdaContext = pWDA; + /* Store param pointer as passed in by caller */ + wda_params->wdaMsgParam = pGetStatsParams; + + wdi_status = WDI_GetARPStatsReq(wdiGetStatsParam, + (WDI_GetARPStatsRspCb)WDA_GetARPStatsParamsRspCallback, + wda_params); + + if(IS_WDI_STATUS_FAILURE(wdi_status)) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure, free all the memory", __func__); + vos_mem_free(wda_params->wdaWdiApiMsgParam) ; + vos_mem_free(wda_params->wdaMsgParam); + vos_mem_free(wda_params); + } + + return wdi_status; +} + /* * FUNCTION: WDA_McProcessMsg * Trigger DAL-AL to start CFG download @@ -16290,6 +16550,16 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) WDA_ProcessTLPauseInd(pWDA, pMsg->bodyval); break; } + case WDA_SET_ARP_STATS_REQ: + { + WDA_ProcessSetARPStatsReq(pWDA, (setArpStatsParams *)pMsg->bodyptr); + break; + } + case WDA_GET_ARP_STATS_REQ: + { + WDA_ProcessGetARPStatsReq(pWDA, (getArpStatsParams *)pMsg->bodyptr); + break; + } default: { VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h index 6f0864d8af32..f76970efd8d2 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi.h @@ -8449,6 +8449,9 @@ typedef void (*WDI_WifiConfigSetRspCb) (WDI_WifconfigSetRsp *wdiRsp, void *pUse typedef void (*WDI_AntennaDivSelRspCb)(WDI_Status status, void *resp, void *pUserData); +typedef void (*wdi_nud_set_arp_rsp_cb)(void *event_data,void *user_data); +typedef void (*wdi_nud_get_arp_rsp_cb)(void *event_data,void *user_data); + /*======================================================================== * Function Declarations and Documentation ==========================================================================*/ @@ -12237,4 +12240,54 @@ WDI_SetAllowedActionFramesInd( ); void WDI_SetMgmtPktViaWQ5(wpt_boolean sendMgmtPktViaWQ5); + +/* ARP DEBUG STATS */ +typedef struct +{ + wpt_uint8 flag; + wpt_uint8 pkt_type; + wpt_uint32 ip_addr; +} WDI_SetARPStatsParamsInfoType; + +typedef struct +{ + wpt_uint32 status; +} WDI_SetARPStatsRspParamsType; + +typedef void (*WDI_SetARPStatsRspCb)(WDI_SetARPStatsRspParamsType* StatsRsp, + void* pUserData); + +WDI_Status +WDI_SetARPStatsReq +( + WDI_SetARPStatsParamsInfoType *pwdiSetStatsReqParams, + WDI_SetARPStatsRspCb wdiSetARPStatsRspCb, + void* pUserData +); + +/* ARP DEBUG STATS */ +typedef struct +{ + wpt_uint8 pkt_type; +} WDI_GetARPStatsParamsInfoType; + +typedef struct +{ + wpt_uint32 status; + wpt_uint16 dad; + wpt_uint16 tx_fw_cnt; + wpt_uint16 rx_fw_cnt; + wpt_uint16 tx_ack_cnt; +} WDI_GetARPStatsRspParamsType; + +typedef void (*WDI_GetARPStatsRspCb)(WDI_GetARPStatsRspParamsType* StatsRsp, + void* pUserData); + +WDI_Status +WDI_GetARPStatsReq +( + WDI_GetARPStatsParamsInfoType *pwdiGetStatsReqParams, + WDI_GetARPStatsRspCb wdiGetARPStatsRspCb, + void* pUserData +); #endif /* #ifndef WLAN_QCT_WDI_H */ diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h index 7debb41ad074..4b74e41fbe3e 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -493,6 +493,9 @@ typedef enum WDI_PER_ROAM_SCAN_OFFLOAD_REQ = 116, WDI_PER_ROAM_SCAN_TRIGGER_REQ = 117, #endif +/* ARP DEBUG STATS */ + WDI_FW_ARP_STATS_REQ = 118, + WDI_FW_GET_ARP_STATS_REQ = 119, WDI_MAX_REQ, @@ -870,6 +873,8 @@ typedef enum WDI_PER_ROAM_SCAN_OFFLOAD_RSP = 116, WDI_PER_ROAM_SCAN_TRIGGER_RSP = 117, #endif + WDI_FW_ARP_STATS_RSP = 118, + WDI_FW_GET_ARP_STATS_RSP = 119, /*------------------------------------------------------------------------- Indications @@ -6676,5 +6681,33 @@ WDI_ProcessSetAllowedActionFramesInd WDI_ControlBlockType* pWDICtx, WDI_EventInfoType* pEventData ); + +WDI_Status +WDI_ProcessSetArpStatsReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessSetArpStatsResp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessGetArpStatsReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); + +WDI_Status +WDI_ProcessGetArpStatsResp +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +); #endif /*WLAN_QCT_WDI_I_H*/ diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c index 62acabfa049c..b4dac6967b85 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi.c @@ -220,6 +220,11 @@ static placeHolderInCapBitmap supportEnabledFeatures[] = ,WIFI_CONFIG //61 ,ANTENNA_DIVERSITY_SELECTION //62 ,PER_BASED_ROAMING //63 + ,FEATURE_NOT_SUPPORTED //64 + ,FEATURE_NOT_SUPPORTED //65 + ,FEATURE_NOT_SUPPORTED //66 + ,FEATURE_NOT_SUPPORTED //67 + ,NUD_DEBUG //68 }; /*-------------------------------------------------------------------------- @@ -516,6 +521,10 @@ WDI_ReqProcFuncType pfnReqProcTbl[WDI_MAX_UMAC_IND] = NULL, NULL, #endif /* WLAN_FEATURE_ROAM_SCAN_OFFLOAD */ + + WDI_ProcessSetArpStatsReq, /* WDI_FW_ARP_STATS_REQ */ + WDI_ProcessGetArpStatsReq, /* WDI_FW_GET_ARP_STATS_REQ */ + /*------------------------------------------------------------------------- Indications -------------------------------------------------------------------------*/ @@ -837,6 +846,9 @@ WDI_RspProcFuncType pfnRspProcTbl[WDI_MAX_RESP] = NULL, NULL, #endif +/* ARP Debug Stats*/ + WDI_ProcessSetArpStatsResp, /* WDI_FW_ARP_STATS_RSP */ + WDI_ProcessGetArpStatsResp, /* WDI_FW_GET_ARP_STATS_RSP */ /*--------------------------------------------------------------------- Indications ---------------------------------------------------------------------*/ @@ -1297,6 +1309,11 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId) CASE_RETURN_STRING( WDI_ANTENNA_DIVERSITY_SELECTION_REQ ); CASE_RETURN_STRING( WDI_MODIFY_ROAM_PARAMS_IND ); CASE_RETURN_STRING( WDI_SET_ALLOWED_ACTION_FRAMES_IND ); + CASE_RETURN_STRING( WDI_FW_ARP_STATS_REQ ); + CASE_RETURN_STRING( WDI_FW_GET_ARP_STATS_REQ ); +#ifdef WLAN_FEATURE_APFIND + CASE_RETURN_STRING( WDI_SET_AP_FIND_IND ); +#endif default: return "Unknown WDI MessageId"; } @@ -1304,6 +1321,84 @@ static char *WDI_getReqMsgString(wpt_uint16 wdiReqMsgId) +/** + * WDI_ProcessSetArpStatsResp() - WDI api to process set arp stats response + * @wdi_ctx: wdi context + * @event_data: event data + * + * Return: WDI_Status + */ +WDI_Status +WDI_ProcessSetArpStatsResp +( + WDI_ControlBlockType *wdi_ctx, + WDI_EventInfoType *event_data +) +{ + wdi_nud_set_arp_rsp_cb nud_set_arp_rsp_callback; + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s: Enter ", __func__); + /*------------------------------------------------------------------- + Sanity check + -----------------------------------------------------------------*/ + if ((NULL == wdi_ctx) || (NULL == event_data) || + (NULL == event_data->pEventData)) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + nud_set_arp_rsp_callback = + (wdi_nud_set_arp_rsp_cb)wdi_ctx->pfncRspCB; + + nud_set_arp_rsp_callback((void *) event_data->pEventData, + wdi_ctx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + +/** + * WDI_ProcessGetArpStatsResp() - WDI api to process get arp stats response + * @wdi_ctx: wdi context + * @event_data: event data + * + * Return: WDI_Status + */ +WDI_Status +WDI_ProcessGetArpStatsResp +( + WDI_ControlBlockType *wdi_ctx, + WDI_EventInfoType *event_data +) +{ + wdi_nud_get_arp_rsp_cb nud_get_arp_rsp_callback; + + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s: Enter ", __func__); + /*------------------------------------------------------------------- + Sanity check + -----------------------------------------------------------------*/ + if ((NULL == wdi_ctx) || (NULL == event_data) || + (NULL == event_data->pEventData)) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + nud_get_arp_rsp_callback = + (wdi_nud_get_arp_rsp_cb)wdi_ctx->pfncRspCB; + + nud_get_arp_rsp_callback((void *) event_data->pEventData, + wdi_ctx->pRspCBUserData); + + return WDI_STATUS_SUCCESS; +} + /** @brief WDI_getRespMsgString prints the WDI resonse message in string. @@ -1641,6 +1736,11 @@ void WDI_TraceHostFWCapabilities(tANI_U32 *capabilityBitmap) "%s", "PER_BASED_ROAMING"); pCapStr += strlen("PER_BASED_ROAMING"); break; + case NUD_DEBUG: + snprintf(pCapStr, sizeof("NUD_DEBUG"), + "%s", "NUD_DEBUG"); + pCapStr += strlen("NUD_DEEBUG"); + break; } *pCapStr++ = ','; *pCapStr++ = ' '; @@ -24750,6 +24850,10 @@ WDI_2_HAL_REQ_TYPE case WDI_PER_ROAM_SCAN_TRIGGER_REQ: return WLAN_HAL_PER_ROAM_SCAN_TRIGGER_REQ; #endif + case WDI_FW_ARP_STATS_REQ: + return WLAN_HAL_FW_SET_CLEAR_ARP_STATS_REQ; + case WDI_FW_GET_ARP_STATS_REQ: + return WLAN_HAL_FW_GET_ARP_STATS_REQ; default: return WLAN_HAL_MSG_MAX; } @@ -25119,6 +25223,10 @@ case WLAN_HAL_DEL_STA_SELF_RSP: case WLAN_HAL_PER_ROAM_SCAN_TRIGGER_RSP: return WDI_PER_ROAM_SCAN_TRIGGER_RSP; #endif + case WLAN_HAL_FW_SET_CLEAR_ARP_STATS_RSP: + return WDI_FW_ARP_STATS_RSP; + case WLAN_HAL_FW_GET_ARP_STATS_RSP: + return WDI_FW_GET_ARP_STATS_RSP; default: return eDRIVER_TYPE_MAX; } @@ -38195,3 +38303,211 @@ WDI_Status WDI_SetAllowedActionFramesInd( return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); } + +/** + * WDI_ProcessSetArpStatsReq() - WDI api to process arp stats request + * @pWDICtx: wdi context + * @pEventData: event data + * + * Return: WDI_Status + */ +WDI_Status +WDI_ProcessSetArpStatsReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_SetARPStatsParamsInfoType *pSetARPStatsReqParams; + WDI_SetARPStatsRspCb wdiSetARPStatsRspCb; + wpt_uint8* pSendBuffer; + wpt_uint16 usDataOffset; + wpt_uint16 usSendSize; + WDI_Status wdi_status; + tHalStatsArpReqMsg statsReqParams; + + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) || + ( NULL == pWDICtx ) ) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pSetARPStatsReqParams = + (WDI_SetARPStatsParamsInfoType *)pEventData->pEventData; + wdiSetARPStatsRspCb = (WDI_SetARPStatsRspCb)pEventData->pCBfnc; + + if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, WDI_FW_ARP_STATS_REQ, + sizeof(statsReqParams.statsArpReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + sizeof(statsReqParams.statsArpReqParams)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Unable to get send buffer in set bss key req %p %p %p", + pEventData, pSetARPStatsReqParams, wdiSetARPStatsRspCb); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + statsReqParams.statsArpReqParams.set_clr = pSetARPStatsReqParams->flag; + statsReqParams.statsArpReqParams.pkt_type = + pSetARPStatsReqParams->pkt_type; + statsReqParams.statsArpReqParams.ip_addr = pSetARPStatsReqParams->ip_addr; + + wpalMemoryCopy( pSendBuffer+usDataOffset, + &statsReqParams.statsArpReqParams, + sizeof(statsReqParams.statsArpReqParams)); + + wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize, + wdiSetARPStatsRspCb, pEventData->pUserData, + WDI_FW_ARP_STATS_RSP); + + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Exit",__func__, __LINE__); + return wdi_status; +} + +/** + * WDI_SetARPStatsReq() - WDI api to process set arp stats request + * @pwdiSetStatsReqParams: pointer to set stats params + * @wdiSetStatsRspCb: pointer to set response callback + * @pUserData: user data + * + * Return: WDI_Status + */ +WDI_Status +WDI_SetARPStatsReq +( + WDI_SetARPStatsParamsInfoType* pwdiSetStatsReqParams, + WDI_SetARPStatsRspCb wdiSetStatsRspCb, + void* pUserData +) +{ + WDI_EventInfoType wdiEventData; + + if (eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_FW_ARP_STATS_REQ; + wdiEventData.pEventData = pwdiSetStatsReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiSetStatsReqParams); + wdiEventData.pCBfnc = wdiSetStatsRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); + +}/*WDI_GetARPStatsReq*/ + +/** + * WDI_ProcessGetArpStatsReq() - WDI api to process get arp stats request + * @pWDICtx: wdi context + * @pEventData: event data + * + * Return: WDI_Status + */ +WDI_Status +WDI_ProcessGetArpStatsReq +( + WDI_ControlBlockType* pWDICtx, + WDI_EventInfoType* pEventData +) +{ + WDI_GetARPStatsParamsInfoType *pGetARPStatsReqParams; + WDI_GetARPStatsRspCb wdiGetARPStatsRspCb; + wpt_uint8* pSendBuffer; + wpt_uint16 usDataOffset; + wpt_uint16 usSendSize; + WDI_Status wdi_status; + tHalStatsGetArpReqMsg statsReqParams; + + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Enter",__func__, __LINE__); + + if (( NULL == pEventData ) || ( NULL == pEventData->pEventData) || + ( NULL == pWDICtx ) ) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "%s: Invalid parameters", __func__); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + pGetARPStatsReqParams = + (WDI_GetARPStatsParamsInfoType *)pEventData->pEventData; + wdiGetARPStatsRspCb = (WDI_GetARPStatsRspCb)pEventData->pCBfnc; + + if ((WDI_STATUS_SUCCESS != WDI_GetMessageBuffer(pWDICtx, + WDI_FW_GET_ARP_STATS_REQ, + sizeof(statsReqParams.statsGetArpReqParams), + &pSendBuffer, &usDataOffset, &usSendSize))|| + ( usSendSize < (usDataOffset + + sizeof(statsReqParams.statsGetArpReqParams)))) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN, + "Unable to get send buffer in set bss key req %p %p %p", + pEventData, pGetARPStatsReqParams, wdiGetARPStatsRspCb); + WDI_ASSERT(0); + return WDI_STATUS_E_FAILURE; + } + + statsReqParams.statsGetArpReqParams.pkt_type = + pGetARPStatsReqParams->pkt_type; + + wpalMemoryCopy( pSendBuffer+usDataOffset, + &statsReqParams.statsGetArpReqParams, + sizeof(statsReqParams.statsGetArpReqParams)); + + wdi_status = WDI_SendMsg(pWDICtx, pSendBuffer, usSendSize, + wdiGetARPStatsRspCb, pEventData->pUserData, + WDI_FW_GET_ARP_STATS_RSP); + + VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO, + "%s: %d Exit",__func__, __LINE__); + return wdi_status; +} + +/** + * WDI_GetARPStatsReq() - WDI api to process get arp stats request + * @pwdiGetStatsReqParams: pointer to get stats params + * @wdiGetStatsRspCb: pointer to get response callback + * @pUserData: user data + * + * Return: WDI_Status + */ +WDI_Status +WDI_GetARPStatsReq +( + WDI_GetARPStatsParamsInfoType* pwdiGetStatsReqParams, + WDI_GetARPStatsRspCb wdiGetStatsRspCb, + void* pUserData +) +{ + WDI_EventInfoType wdiEventData; + + if (eWLAN_PAL_FALSE == gWDIInitialized ) + { + WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, + "WDI API call before module is initialized - Fail request"); + + return WDI_STATUS_E_NOT_ALLOWED; + } + + wdiEventData.wdiRequest = WDI_FW_GET_ARP_STATS_REQ; + wdiEventData.pEventData = pwdiGetStatsReqParams; + wdiEventData.uEventDataSize = sizeof(*pwdiGetStatsReqParams); + wdiEventData.pCBfnc = wdiGetStatsRspCb; + wdiEventData.pUserData = pUserData; + + return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData); + +}/*WDI_GetARPStatsReq*/ From ff0194d90122ffb128979dbd5a519d500dd74e24 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:23:25 +0530 Subject: [PATCH 237/281] wlan: During ARP debug set FW in datapath for ARP For ARP packet debug keep FW in datapath and set tx BD complete Tx interrupt field with dialogue token. Also Make use of reserved TX BD field to indicate packet as ARP to firmware Change-Id: I8477388ecc83bf6e9dfa75d85d5c8dcbb9f774d7 CRs-Fixed: 1115218 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 2 + .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 14 ++++++ .../staging/prima/CORE/TL/inc/wlan_qct_tl.h | 9 ++++ .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 45 ++++++++++++++--- .../staging/prima/CORE/TL/src/wlan_qct_tli.h | 2 + drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 2 + drivers/staging/prima/CORE/VOSS/src/vos_api.c | 49 +++++++++++++++++++ .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 2 + .../prima/CORE/WDA/src/wlan_qct_wda_ds.c | 4 +- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h | 11 +++-- .../prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h | 3 +- .../prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c | 6 ++- .../prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h | 7 +-- .../prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c | 8 +-- 14 files changed, 145 insertions(+), 19 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index cfcfeb7ad29a..209f35fb2bb2 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1685,6 +1685,8 @@ struct hdd_context_s v_U8_t last_scan_reject_session_id; scan_reject_states last_scan_reject_reason; v_TIME_t last_scan_reject_timestamp; + + uint32_t track_arp_ip; }; typedef enum { diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 7cab0bab586b..439a76e945f3 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -7530,6 +7530,7 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, struct net_device *dev = wdev->netdev; hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(adapter))->pvosContext; setArpStatsParams arp_stats_params; int err = 0; @@ -7574,6 +7575,19 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, arp_stats_params.pkt_type = 1; // ARP packet type + if (arp_stats_params.flag) { + hdd_ctx->track_arp_ip = arp_stats_params.ip_addr; + WLANTL_SetARPFWDatapath(pVosContext, true); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s Set FW in data path for ARP with tgt IP :%d", + __func__, hdd_ctx->track_arp_ip); + } + else { + WLANTL_SetARPFWDatapath(pVosContext, false); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s Remove FW from data path", __func__); + } + arp_stats_params.rsp_cb_fn = hdd_set_nud_stats_cb; arp_stats_params.data_ctx = adapter; diff --git a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h index 9b80e046023f..35d9f7d976b2 100644 --- a/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h +++ b/drivers/staging/prima/CORE/TL/inc/wlan_qct_tl.h @@ -3376,4 +3376,13 @@ void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId); * Return: none */ void WLANTL_SetDataPktFilter(v_PVOID_t pvosGCtx, uint8_t ucSTAId, bool flag); + +/** + * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP + * @pvosGCtx: global vos context + * @flag: value to keep or remove FW from data path + * + * Return: void + */ +void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag); #endif /* #ifndef WLAN_QCT_WLANTL_H */ diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index ae95be50dd76..6dc738375d18 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -2752,8 +2752,8 @@ WLANTL_TxBAPFrm ucWDSEnabled, extraHeadSpace, pMetaInfo->ucType, &pTLCb->atlSTAClients[ucStaId]->wSTADesc.vSelfMACAddress, pMetaInfo->ucTID, 0 /* No ACK */, pMetaInfo->usTimeStamp, - pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucUP, - pMetaInfo->ucTxBdToken); + pMetaInfo->ucIsEapol || pMetaInfo->ucIsWai, pMetaInfo->ucIsArp, + pMetaInfo->ucUP, pMetaInfo->ucTxBdToken); if ( VOS_STATUS_SUCCESS != vosStatus ) { @@ -3694,7 +3694,7 @@ WLANTL_TxMgmtFrm vosStatus = WDA_DS_BuildTxPacketInfo( pvosGCtx, vosFrmBuf , &vDestMacAddr, 1 /* always 802.11 frames*/, &usPktLen, uQosHdr /*qos not enabled !!!*/, 0 /* WDS off */, 0, wFrmType, pvAddr2MacAddr, ucTid, - ucAckResponse, usTimeStamp, 0, 0, ucTxBdToken); + ucAckResponse, usTimeStamp, 0, 0, 0, ucTxBdToken); if ( !VOS_IS_STATUS_SUCCESS(vosStatus) ) @@ -7887,8 +7887,8 @@ WLANTL_STATxConn extraHeadSpace, ucTypeSubtype, &pClientSTA->wSTADesc.vSelfMACAddress, ucTid, txFlag, - tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai, tlMetaInfo.ucUP, - tlMetaInfo.ucTxBdToken); + tlMetaInfo.usTimeStamp, tlMetaInfo.ucIsEapol || tlMetaInfo.ucIsWai, + tlMetaInfo.ucIsArp, tlMetaInfo.ucUP, tlMetaInfo.ucTxBdToken); if ( VOS_STATUS_SUCCESS != vosStatus ) { @@ -8307,6 +8307,16 @@ WLANTL_STATxAuth #endif /* FEATURE_WLAN_TDLS */ if( tlMetaInfo.ucIsArp ) { + if (pTLCb->track_arp) + { + if (vos_check_arp_target_ip(vosDataBuff)) + { + ucTxFlag |= HAL_USE_FW_IN_TX_PATH; + ucTxFlag |= HAL_TXCOMP_REQUESTED_MASK; + tlMetaInfo.ucTxBdToken = ++ pTLCb->txbd_token; + } + } + if (pStaClient->arpOnWQ5) { ucTxFlag |= HAL_USE_FW_IN_TX_PATH; @@ -8331,7 +8341,7 @@ WLANTL_STATxAuth extraHeadSpace, ucTypeSubtype, &pStaClient->wSTADesc.vSelfMACAddress, ucTid, ucTxFlag, tlMetaInfo.usTimeStamp, - tlMetaInfo.ucIsEapol, tlMetaInfo.ucUP, + tlMetaInfo.ucIsEapol, tlMetaInfo.ucIsArp, tlMetaInfo.ucUP, tlMetaInfo.ucTxBdToken); if(!VOS_IS_STATUS_SUCCESS(vosStatus)) @@ -13816,6 +13826,29 @@ void WLANTL_ResetRxSSN(v_PVOID_t pvosGCtx, uint8_t ucSTAId) } } +/** + * WLANTL_SetARPFWDatapath() - keep or remove FW in data path for ARP + * + * @flag: value to keep or remove FW from data path + * + * Return: void + */ +void WLANTL_SetARPFWDatapath(void * pvosGCtx, bool flag) +{ + + WLANTL_CbType* pTLCb = NULL; + + pTLCb = VOS_GET_TL_CB(pvosGCtx); + if (NULL == pTLCb) { + TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid TL pointer from pvosGCtx", __func__)); + return; + } + + pTLCb->track_arp = flag; + +} + #ifdef WLAN_FEATURE_RMC VOS_STATUS WLANTL_RmcInit ( diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h index 4d23eb22781b..fdb5898b8fb1 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tli.h @@ -967,6 +967,8 @@ typedef struct WLANTL_RoamMonitorType gDsRxRoamStats; #endif + uint8_t track_arp; + uint32_t txbd_token; }WLANTL_CbType; diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index b1b846cd3f92..c5a1556f0dc7 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -526,4 +526,6 @@ v_BOOL_t vos_is_probe_rsp_offload_enabled(void); void vos_smd_dump_stats(void); void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event); void vos_dump_wdi_events(void); + +bool vos_check_arp_target_ip(vos_pkt_t *pPacket); #endif // if !defined __VOS_NVITEM_H diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index f218b8e5d3a9..0015f5da9e61 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -103,6 +103,9 @@ /* Trace index for WDI Read/Write */ #define VOS_TRACE_INDEX_MAX 256 +/* ARP Target IP offset */ +#define VOS_ARP_TARGET_IP_OFFSET 58 + /*--------------------------------------------------------------------------- * Data definitions * ------------------------------------------------------------------------*/ @@ -3664,3 +3667,49 @@ void vos_dump_wdi_events(void) gvos_wdi_msg_trace[i].message); } } +/** + * vos_check_arp_target_ip() - check if the Target IP is gateway IP + * @pPacket: pointer to vos packet + * + * Return: true if the IP is of gateway or false otherwise + */ +bool vos_check_arp_target_ip(vos_pkt_t *pPacket) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + hdd_context_t *pHddCtx = NULL; + struct sk_buff *skb; + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return false; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return false; + } + + if (unlikely(NULL == pPacket)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: NULL pointer", __func__); + return false; + } + + if ( VOS_STATUS_SUCCESS != + vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: OS PKT pointer is NULL", __func__); + return false; + } + + if (pHddCtx->track_arp_ip == + (v_U32_t)(*(v_U32_t *)(skb->data + VOS_ARP_TARGET_IP_OFFSET))) + return true; + + return false; +} diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index 0dc52dd3f4ac..90873fa6649f 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -1602,6 +1602,7 @@ WDA_DS_FinishULA txFlag timeStamp ucIsEapol + ucIsArp ucUP OUT @@ -1631,6 +1632,7 @@ WDA_DS_BuildTxPacketInfo v_U32_t txFlag, v_U32_t timeStamp, v_U8_t ucIsEapol, + v_U8_t ucIsArp, v_U8_t ucUP, v_U32_t ucTxBdToken ); diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c index 2e303fb400d3..b4a9bbba7e3f 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda_ds.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -436,6 +436,7 @@ WDA_DS_BuildTxPacketInfo v_U32_t txFlag, v_U32_t timeStamp, v_U8_t ucIsEapol, + v_U8_t ucIsArp, v_U8_t ucUP, v_U32_t ucTxBdToken ) @@ -497,6 +498,7 @@ WDA_DS_BuildTxPacketInfo pTxMetaInfo->ac = ucUP; pTxMetaInfo->fUP = uTid; pTxMetaInfo->isEapol = ucIsEapol; + pTxMetaInfo->isArp = ucIsArp; pTxMetaInfo->fdisableFrmXlt = ucDisableFrmXtl; pTxMetaInfo->frmType = ( ( typeSubtype & 0x30 ) >> 4 ); pTxMetaInfo->typeSubtype = typeSubtype; diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h index e42c1833a952..c828c4b2ea5d 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_bd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1113,10 +1113,13 @@ typedef struct This is filled by Host in Virgo 1.0 but it gets filled by ADU in Virgo2.0/Libra. Queue ID */ wpt_uint32 queueId:5; - - wpt_uint32 reserved5:7; + + wpt_uint32 isArp:1; + + wpt_uint32 reserved5:6; #else - wpt_uint32 reserved5:7; + wpt_uint32 reserved5:6; + wpt_uint32 isArp:1; wpt_uint32 queueId:5; wpt_uint32 bdRate:2; wpt_uint32 ap:2; diff --git a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h index 465946ebae84..85446f1b6ddd 100644 --- a/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h +++ b/drivers/staging/prima/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -435,6 +435,7 @@ WDI_FillTxBd wpt_uint8 ucProtMgmtFrame, wpt_uint32 uTimeStamp, wpt_uint8 isEapol, + wpt_uint8 isArp, wpt_uint8* staIndex, wpt_uint32 txBdToken ); diff --git a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c index 48bf139ff169..25d627f23886 100644 --- a/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c +++ b/drivers/staging/prima/CORE/WDI/CP/src/wlan_qct_wdi_dp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -386,6 +386,7 @@ WDI_FillTxBd wpt_uint8 ucProtMgmtFrame, wpt_uint32 uTimeStamp, wpt_uint8 isEapol, + wpt_uint8 isArp, wpt_uint8* staIndex, wpt_uint32 txBdToken ) @@ -409,6 +410,9 @@ WDI_FillTxBd Get type and subtype of the frame first ------------------------------------------------------------------------*/ pBd->txBdToken = txBdToken; + + pBd->isArp = isArp; + ucType = (ucTypeSubtype & WDI_FRAME_TYPE_MASK) >> WDI_FRAME_TYPE_OFFSET; ucSubType = (ucTypeSubtype & WDI_FRAME_SUBTYPE_MASK); diff --git a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h index 483ad65980b2..2acb5cec4cd1 100644 --- a/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h +++ b/drivers/staging/prima/CORE/WDI/DP/inc/wlan_qct_wdi_ds.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -53,11 +53,12 @@ typedef struct wpt_uint32 txFlags; wpt_uint8 ac; wpt_uint8 isEapol:1; //0 - not eapol 1 - eapol - wpt_uint8 isWai:1; //WAPI 0 - not WAI 1 WAI + wpt_uint8 isWai:1; //WAPI 0 - not WAI 1 WAI + wpt_uint8 isArp:1; //0 - not ARP 1 - ARP wpt_uint8 fdisableFrmXlt:1; //0 - Let ADU do FT. 1 - bypass ADU FT wpt_uint8 qosEnabled:1; //0 - non-Qos 1 - Qos wpt_uint8 fenableWDS:1; //0 - not WDS 1 WDS - wpt_uint8 reserved1:3; + wpt_uint8 reserved1:2; wpt_uint8 typeSubtype; wpt_uint8 fUP; wpt_uint8 fSTAMACAddress[6]; diff --git a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c index 902c0de1f596..e0f2c53d85fd 100644 --- a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c +++ b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -129,6 +129,7 @@ WDI_Status WDI_DS_TxPacket(void *pContext, wpt_uint8 ucUP; wpt_uint8 ucTypeSubtype; wpt_uint8 isEapol; + wpt_uint8 isArp; wpt_uint8 alignment; wpt_uint32 ucTxFlag; wpt_uint8 ucProtMgmtFrame; @@ -160,6 +161,7 @@ WDI_Status WDI_DS_TxPacket(void *pContext, ucTypeSubtype = pTxMetadata->typeSubtype; ucUP = pTxMetadata->fUP; isEapol = pTxMetadata->isEapol; + isArp = pTxMetadata->isArp; ucTxFlag = pTxMetadata->txFlags; ucProtMgmtFrame = pTxMetadata->fProtMgmtFrame; pSTAMACAddress = &(pTxMetadata->fSTAMACAddress[0]); @@ -212,8 +214,8 @@ WDI_Status WDI_DS_TxPacket(void *pContext, "Packet Length is %d\n", pTxMetadata->fPktlen); } wdiStatus = WDI_FillTxBd(pContext, ucTypeSubtype, pSTAMACAddress, pAddr2MACAddress, - &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, &staId, - pTxMetadata->txBdToken); + &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, isArp, + &staId, pTxMetadata->txBdToken); if(WDI_STATUS_SUCCESS != wdiStatus) { From a5ebafcd02ccef9bb547d3ded56601829baf0f00 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:25:26 +0530 Subject: [PATCH 238/281] wlan: Add changes to collect Arp packet stats Add changes to collect arp packet stats along with existing hdd stats to debug the arp packet related issues Change-Id: I3574d512744bcdd0021f8a57d2f9f70e1b154458 CRs-Fixed: 1115366 --- .../staging/prima/CORE/DXE/src/wlan_qct_dxe.c | 16 ++- .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 116 ++++++++++++++++++ .../prima/CORE/TL/src/wlan_qct_tl_ba.c | 5 +- drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 2 + .../staging/prima/CORE/VOSS/inc/vos_packet.h | 14 ++- drivers/staging/prima/CORE/VOSS/src/vos_api.c | 82 +++++++++++++ .../staging/prima/CORE/VOSS/src/vos_packet.c | 31 ++++- .../prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c | 7 ++ .../CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c | 9 +- .../CORE/WDI/WPAL/inc/wlan_qct_pal_api.h | 4 +- .../CORE/WDI/WPAL/src/wlan_qct_pal_api.c | 13 +- 11 files changed, 292 insertions(+), 7 deletions(-) diff --git a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c index c7f7235b0a81..de64b93c89e3 100644 --- a/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c +++ b/drivers/staging/prima/CORE/DXE/src/wlan_qct_dxe.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3445,6 +3445,12 @@ static wpt_status dxeTXPushFrame //HDXE_ASSERT(0); } + if(wpalIsArpPkt(palPacket)) + { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s :ARP packet", __func__); + } + /* Everything is ready * Trigger to start DMA */ status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr, @@ -3695,6 +3701,14 @@ static wpt_status dxeTXCompFrame } return status; } + + if(wpalIsArpPkt(currentCtrlBlk->xfrFrame)) + { + HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR, + "%s :ARP packet DMA-ed ", __func__); + wpalUpdateTXArpFWdeliveredStats(); + } + hostCtxt->txCompCB(hostCtxt->clientCtxt, currentCtrlBlk->xfrFrame, eWLAN_PAL_STATUS_SUCCESS); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index 3cae5479a191..45878d977c27 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -819,6 +819,7 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); v_BOOL_t txSuspended = VOS_FALSE; struct sk_buff *skb1; + v_BOOL_t arp_pkt; if (NULL == pHddCtx) { VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, @@ -835,6 +836,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } + arp_pkt = vos_is_arp_pkt(skb, false); + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txCount; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :ARP packet received form net_dev", __func__); + } + //Get TL Q index corresponding to Qdisc queue index/AC. qid = hdd_QdiscAcToTlAC[skb->queue_mapping]; ac = qid; @@ -852,6 +862,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO, FL("Tx frame in not associated state in %d context"), pAdapter->device_mode); + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_TX_FRAME_IN_NOT_ASSOCIATED_STATE; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s :Tx frame in not associated state, ARP packet Dropped ", + __func__); + } ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid]; @@ -895,6 +914,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, "%s: WLANTL_STAPktPending() returned error code %d", __func__, status); + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_WLANTL_STAPKTPENDING_RETURNED_ERROR_CODE; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:ARP Packet Dropped WLANTL_STAPktPending returned error %d", + __func__, status); + } ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid]; @@ -966,6 +994,14 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if ( !VOS_IS_STATUS_SUCCESS( status ) ) { VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s:Insert Tx queue failed. Pkt dropped", __func__); + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_INSERT_TX_QUEUE_FAILED; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:Insert Tx queue failed. ARP packet dropped", __func__); + } ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid]; ++pAdapter->stats.tx_dropped; @@ -1027,6 +1063,15 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb1 = pktNode->skb; kfree_skb(skb1); } + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILED_TO_SIGNAL_TL; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: ARP packet Dropped : Failed to signal TL for QId=%d", + __func__, qid ); + } ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid]; @@ -1938,6 +1983,7 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, tANI_U8 acAdmitted, i; v_U8_t proto_type = 0; WLANTL_ACEnumType actualAC; + v_BOOL_t arp_pkt; //Sanity check on inputs if ( ( NULL == vosContext ) || @@ -2075,10 +2121,20 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, vos_pkt_return_packet(pVosPacket); return VOS_STATUS_E_FAILURE; } + arp_pkt = vos_is_arp_pkt(skb, false); //Attach skb to VOS packet. status = vos_pkt_set_os_packet( pVosPacket, skb ); if (status != VOS_STATUS_SUCCESS) { + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_ERROR_ATTACHING_SKB; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s :Error attaching skb,ARP packet droped", __func__); + } + VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __func__); vos_pkt_return_packet(pVosPacket); ++pAdapter->stats.tx_dropped; @@ -2090,6 +2146,16 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, //Just being paranoid. To be removed later if(pVosPacket == NULL) { + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.txDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_VOS_PACKET_RETURNED_BY_VOSS_IS_NULL; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :VOS packet returned by VOSS is NULL,ARP packet droped", + __func__); + } + VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s: VOS packet returned by VOSS is NULL", __func__); ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError; @@ -2148,6 +2214,12 @@ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, if( HDD_ETHERTYPE_ARP_SIZE == packet_size ) pPktMetaInfo->ucIsArp = hdd_IsARP( pVosPacket ) ? 1 : 0; + if(pPktMetaInfo->ucIsArp) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :STA TX ARP Received in TL ",__func__); + } + #ifdef FEATURE_WLAN_WAPI // Override usIsEapol value when its zero for WAPI case pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0; @@ -2569,6 +2641,7 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, vos_pkt_t* pVosPacket; vos_pkt_t* pNextVosPacket; v_U8_t proto_type; + v_BOOL_t arp_pkt; //Sanity check on inputs if ( ( NULL == vosContext ) || @@ -2609,6 +2682,14 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, // both "success" and "empty" are acceptable results if (!((status == VOS_STATUS_SUCCESS) || (status == VOS_STATUS_E_EMPTY))) { + + if(hdd_IsARP(pVosPacket)) + { + ++pAdapter->hdd_stats.hddArpStats.rxDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILURE_WALKING_PACKET_CHAIN; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: ARP packet Drop: Failure walking packet chain", __func__); + } ++pAdapter->hdd_stats.hddTxRxStats.rxDropped; VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, "%s: Failure walking packet chain", __func__); @@ -2619,6 +2700,15 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_FALSE ); if(!VOS_IS_STATUS_SUCCESS( status )) { + + if(hdd_IsARP(pVosPacket)) + { + ++pAdapter->hdd_stats.hddArpStats.rxDropped; + pAdapter->hdd_stats.hddArpStats.reason = HDD_FAILURE_EXTRACTING_SKB_FROM_VOS_PKT; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: ARP packet Dropped: Failure extracting skb from vos pkt", + __func__); + } ++pAdapter->hdd_stats.hddTxRxStats.rxDropped; VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR, "%s: Failure extracting skb from vos pkt", __func__); @@ -2680,6 +2770,15 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, } } + arp_pkt = vos_is_arp_pkt(skb, false); + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.rxCount; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :STA RX ARP received",__func__); + } + if (pHddCtx->rx_wow_dump) { if (!(VOS_PKT_PROTO_TYPE_ARP & proto_type) && !(VOS_PKT_PROTO_TYPE_EAPOL & proto_type)) @@ -2719,11 +2818,28 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, if (NET_RX_SUCCESS == rxstat) { + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.rxDelivered; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "STA RX ARP packet Delivered to net stack"); + } + ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered; ++pAdapter->hdd_stats.hddTxRxStats.pkt_rx_count; } else { + + if (arp_pkt) + { + ++pAdapter->hdd_stats.hddArpStats.rxRefused; + pAdapter->hdd_stats.hddArpStats.reason = HDD_STA_RX_ARP_PACKET_REFUSED_IN_NET_STACK; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s :STA RX ARP packet Refused in net stack", __func__); + } + ++pAdapter->hdd_stats.hddTxRxStats.rxRefused; } // now process the next packet in the chain diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c index f94058504127..b97af6cfdf16 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1165,6 +1165,9 @@ VOS_STATUS WLANTL_MSDUReorder TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, "(QCUR_FWDBUF) dropping old frame, SN=%d LastSN=%d", CSN, currentReorderInfo->LastSN)); + if (vos_is_arp_pkt((*vosDataBuff)->pSkb, true)) + vos_update_arp_rx_drop_reorder(); + status = vos_pkt_return_packet(*vosDataBuff); if (!VOS_IS_STATUS_SUCCESS(status)) { diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index c5a1556f0dc7..0f6fef666f49 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -528,4 +528,6 @@ void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event); void vos_dump_wdi_events(void); bool vos_check_arp_target_ip(vos_pkt_t *pPacket); +void vos_update_arp_fw_tx_delivered(void); +void vos_update_arp_rx_drop_reorder(void); #endif // if !defined __VOS_NVITEM_H diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h index 3aa0a33b55eb..ad838d7bcf96 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1170,4 +1170,16 @@ v_PVOID_t vos_get_pkt_end(vos_pkt_t *pPacket); */ v_VOID_t vos_recover_tail(vos_pkt_t *pPacket); +/** + @breaf vos_is_arp_pkt() - Check the packet is ARP or not. + + @param + pskb - pointer to skb + is_translated - header translation check + @return + TRUE - if packet is ARP + FALSE -if packet is not ARP +*/ +bool vos_is_arp_pkt(void *pskb, bool is_translated); + #endif // !defined( __VOS_PKT_H ) diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index 0015f5da9e61..34802d8b6083 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -3713,3 +3713,85 @@ bool vos_check_arp_target_ip(vos_pkt_t *pPacket) return false; } + +/** + * vos_update_arp_fw_tx_delivered() - update the ARP stats host to FW deliver + * count + * + * Return: None + */ +void vos_update_arp_fw_tx_delivered(void) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + hdd_context_t *pHddCtx = NULL; + hdd_adapter_t * pAdapter; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + uint8_t status; + + if(!pVosContext) { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && 0 == status) + { + pAdapter = pAdapterNode->pAdapter; + if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION) + break; + + status = hdd_get_next_adapter (pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + pAdapter->hdd_stats.hddArpStats.tx_host_fw_sent++; +} + +/** + * vos_update_arp_rx_drop_reorder() - update the RX ARP stats drop due + * reorder logic at host + * + * Return: None + */ +void vos_update_arp_rx_drop_reorder(void) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + hdd_context_t *pHddCtx = NULL; + hdd_adapter_t * pAdapter; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + uint8_t status; + + if(!pVosContext) { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && 0 == status) + { + pAdapter = pAdapterNode->pAdapter; + if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION) + break; + + status = hdd_get_next_adapter (pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + pAdapter->hdd_stats.hddArpStats.rx_host_drop_reorder++; +} diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c index 43daf9f7d370..733217687af9 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_packet.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_packet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -3100,6 +3100,35 @@ v_U8_t vos_pkt_get_proto_type return pkt_proto_type; } +bool vos_is_arp_pkt(void *pskb, bool is_translated) +{ + v_U16_t ether_type; + struct sk_buff *skb = NULL; +#define HEADER_OFFSET_802_11 20 + + if (NULL == pskb) + { + return FALSE; + } + + skb = (struct sk_buff *)pskb; + + if (is_translated) + ether_type = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_PROT_ETH_TYPE_OFFSET + HEADER_OFFSET_802_11)); + else + ether_type = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_PROT_ETH_TYPE_OFFSET)); + + if (VOS_PKT_PROT_ARP_ETH_TYPE == VOS_SWAP_U16(ether_type)) + { + return TRUE; + } + else + { + return FALSE; + } +#undef HEADER_OFFSET_802_11 +} + v_PVOID_t vos_get_pkt_head(vos_pkt_t *pPacket) { struct sk_buff *skb; diff --git a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c index e0f2c53d85fd..ac4512a83cd8 100644 --- a/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c +++ b/drivers/staging/prima/CORE/WDI/DP/src/wlan_qct_wdi_ds.c @@ -213,6 +213,13 @@ WDI_Status WDI_DS_TxPacket(void *pContext, WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, "Packet Length is %d\n", pTxMetadata->fPktlen); } + + if (pTxMetadata->isArp) + { + WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO, + "%s :Transmitting ARP packet",__func__); + } + wdiStatus = WDI_FillTxBd(pContext, ucTypeSubtype, pSTAMACAddress, pAddr2MACAddress, &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, isArp, &staId, pTxMetadata->txBdToken); diff --git a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c index 018b8be4f5ef..a43656a1b41a 100644 --- a/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c +++ b/drivers/staging/prima/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1259,6 +1259,13 @@ wpt_status WDTS_TxPacket(void *pContext, wpt_packet *pFrame) #else ((pTxMetadata->isEapol) ? WDTS_CHANNEL_TX_HIGH_PRI : WDTS_CHANNEL_TX_LOW_PRI) : WDTS_CHANNEL_TX_HIGH_PRI; #endif + + if (pTxMetadata->isArp) + { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :Transmitting ARP packet", __func__); + } + // Send packet to Transport Driver. status = gTransportDriver.xmit(pDTDriverContext, pFrame, channel); if ((WLAN_LOG_LEVEL_ACTIVE == diff --git a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h index c1a8d181233c..aeacf6f58a02 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h +++ b/drivers/staging/prima/CORE/WDI/WPAL/inc/wlan_qct_pal_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -389,4 +389,6 @@ int wpalIsDxeSSREnable(void); wpt_uint8 wpalIsFwLoggingEnabled(void); wpt_uint8 wpalIsFwLoggingSupported(void); wpt_uint8 wpalIsFwEvLoggingEnabled(void); +bool wpalIsArpPkt(void *pPacket); +void wpalUpdateTXArpFWdeliveredStats(void); #endif // __WLAN_QCT_PAL_API_H diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c index 9e0f047fea41..a6019cbdbbf5 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012,2014-2015,2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -542,3 +542,14 @@ int wpalIsDxeSSREnable(void) return vos_get_dxeSSREnable(); } +bool wpalIsArpPkt(void *pPacket) +{ + vos_pkt_t *pkt = (vos_pkt_t*)pPacket; + + return vos_is_arp_pkt(pkt->pSkb, true); +} + +void wpalUpdateTXArpFWdeliveredStats(void) +{ + vos_update_arp_fw_tx_delivered(); +} From bd08fb5a6aa728672dad2b2f02d0975afdf92c73 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:26:55 +0530 Subject: [PATCH 239/281] wlan: Add ARP stats to WE_GET_STATS ioctl Add ARP packet stats to WE_GET_STATS ioctl Change-Id: I3a34476bad75df675b6ea777d7027a90463eeef1 CRs-Fixed: 1115366 --- .../staging/prima/CORE/HDD/src/wlan_hdd_wext.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index ef66b1685235..a004a9fdb363 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -6919,6 +6919,7 @@ static int __iw_get_char_setnone(struct net_device *dev, hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); hdd_tx_rx_stats_t *pStats = &pAdapter->hdd_stats.hddTxRxStats; hdd_chip_reset_stats_t *pResetStats = &pHddCtx->hddChipResetStats; + hdd_arp_stats_t *parpStats = &pAdapter->hdd_stats.hddArpStats; snprintf(extra, WE_MAX_STR_LEN, @@ -6939,6 +6940,11 @@ static int __iw_get_char_setnone(struct net_device *dev, "\nchains %u, packets %u, dropped %u, delivered %u, refused %u" "\n\nResetsStats" "\n TotalLogp %u Cmd53 %u MutexRead %u MIF-Error %u FW-Heartbeat %u Others %u" + "\n" + "\n\nARP Transmit" + "\nTransmit Count %u, dropped %u" + "\n\nARP Receive" + "\nReceive Count %u, dropped %u, Delivered %u, Refused %u, Drop Reason %u" "\n", pStats->txXmitCalled, pStats->txXmitDropped, @@ -7012,7 +7018,16 @@ static int __iw_get_char_setnone(struct net_device *dev, pResetStats->totalMutexReadFailures, pResetStats->totalMIFErrorFailures, pResetStats->totalFWHearbeatFailures, - pResetStats->totalUnknownExceptions + pResetStats->totalUnknownExceptions, + + parpStats->txCount, + parpStats->txDropped, + + parpStats->rxCount, + parpStats->rxDropped, + parpStats->rxDelivered, + parpStats->rxRefused, + parpStats->reason ); wrqu->data.length = strlen(extra); From 290898a7c1543d5204caaab678132566348e0f07 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:36:36 +0530 Subject: [PATCH 240/281] wlan: Implement Duplicate Address Detection (DAD) It's been found that DUT did not receive packet directed to it due to duplicate IP assigned to another host leading to disconnection in case of ARP exchanges. This commit ensure that such scenario been detected and logged so that user is aware of this anomaly. Change-Id: I8f56a2df27078015616704de9b7629a305dca5f4 CRs-Fixed: 1115226 --- .../staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h | 10 ++++- .../prima/CORE/HDD/src/wlan_hdd_assoc.c | 1 + .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 42 +++++++++++++++++++ .../staging/prima/CORE/HDD/src/wlan_hdd_wmm.c | 33 ++++++++++++++- 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h index ca4db65c53f7..4e1eb237b831 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -415,4 +415,12 @@ VOS_STATUS hdd_wmm_adapter_clear( hdd_adapter_t *pAdapter ); ===========================================================================*/ void hdd_log_ip_addr(struct sk_buff *skb); +/**============================================================================ + @brief hdd_get_arp_src_ip() - Function to get ARP src IP addr + @param pAdapter : [in] pointer to os packet + + @return : IP address + ===========================================================================*/ +uint32_t hdd_get_arp_src_ip(struct sk_buff *skb); + #endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c index 4fc44c2557a4..b7c935de7633 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_assoc.c @@ -1258,6 +1258,7 @@ static eHalStatus hdd_DisConnectHandler( hdd_adapter_t *pAdapter, tCsrRoamInfo * pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BE] = 0; pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BK] = 0; #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + pAdapter->dad = false; // Clear saved connection information in HDD hdd_connRemoveConnectInfo( pHddStaCtx ); diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index 45878d977c27..aab2ded59414 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -2615,6 +2615,40 @@ VOS_STATUS hdd_rx_packet_monitor_cbk(v_VOID_t *vosContext,vos_pkt_t *pVosPacket return status; } +bool hdd_is_duplicate_ip_arp(struct sk_buff *skb) +{ + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + uint32_t arp_ip,if_ip; + + if (NULL == skb) + return false; + + arp_ip = hdd_get_arp_src_ip(skb); + + if(!skb->dev) return false; + + in_dev = __in_dev_get_rtnl(skb->dev); + + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(skb->dev->name, ifa->ifa_label)) + break; + } + } + if (ifa && ifa->ifa_local) { + + if_ip = ntohl(ifa->ifa_local); + if (if_ip == arp_ip) { + return true; + } + } + + return false; +} + /**============================================================================ @brief hdd_rx_packet_cbk() - Receive callback registered with TL. TL will call this to notify the HDD when one or more packets were @@ -2802,6 +2836,14 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, ++pAdapter->hdd_stats.hddTxRxStats.rxPackets; ++pAdapter->stats.rx_packets; pAdapter->stats.rx_bytes += skb->len; + + if (arp_pkt) + { + pAdapter->dad = hdd_is_duplicate_ip_arp(skb); + if(pAdapter->dad) + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s :Duplicate IP detected",__func__); + } #ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK vos_wake_lock_timeout_release(&pHddCtx->rx_wake_lock, HDD_WAKE_LOCK_DURATION, diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c index e854ad271701..b91f0c8407fa 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wmm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1959,6 +1959,37 @@ void hdd_log_ip_addr(struct sk_buff *skb) } } +/**============================================================================ + @brief hdd_get_arp_src_ip() - Function to get ARP src IP addr + @param skb : [in] pointer to OS packet (sk_buff) + @return : IP addr + ===========================================================================*/ +uint32_t hdd_get_arp_src_ip(struct sk_buff *skb) +{ + struct arphdr *arp; + unsigned char *arp_ptr; + uint32_t src_ip; + +#define ARP_HDR_SIZE ( sizeof(__be16)*3 + sizeof(unsigned char)*2 ) +#define ARP_SENDER_HW_ADDRESS_SZ (6) +#define ARP_SENDER_IP_ADDRESS_SZ (4) + + arp = (struct arphdr *)skb->data; + + arp_ptr = (unsigned char *)arp + ARP_HDR_SIZE; + arp_ptr += ARP_SENDER_HW_ADDRESS_SZ; + + memcpy(&src_ip, arp_ptr, ARP_SENDER_IP_ADDRESS_SZ); + + src_ip=ntohl(src_ip); + + return src_ip; + +#undef ARP_HDR_SIZE +#undef ARP_SENDER_HW_ADDRESS_SZ +#undef ARP_SENDER_IP_ADDRESS_SZ +} + /**============================================================================ @brief hdd_wmm_classify_pkt() - Function which will classify an OS packet into a WMM AC based on either 802.1Q or DSCP From 0ea3ee548e8c4c118f227317ab0c6df433439430 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:38:01 +0530 Subject: [PATCH 241/281] wlan: Don't reset the dad variable for non duplicate address ARP requests Currently return value of check dad utility function is assigned to the dad variable. As a result this resets the dad detected value for ARP requests for which dad utility function returns false. As part of this fix it will take care not to reset the variable. Change-Id: I2a6b28d66492b9274493a9507c3ce360399e055a CRs-Fixed: 2005983 --- drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index aab2ded59414..c80b4c85adbb 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -2839,7 +2839,7 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, if (arp_pkt) { - pAdapter->dad = hdd_is_duplicate_ip_arp(skb); + pAdapter->dad |= hdd_is_duplicate_ip_arp(skb); if(pAdapter->dad) VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s :Duplicate IP detected",__func__); From a4eeb512b54576ddd68f92383258f22625121911 Mon Sep 17 00:00:00 2001 From: "Asodi T,Venkateswara Reddy" Date: Fri, 24 Mar 2017 16:38:57 +0530 Subject: [PATCH 242/281] wlan: Send ADDBA req to test the connection status In some cases AP silently kick outs the DUT and DUT is unaware of its connection status. After this when DUT send packets to AP, AP drops the packets. To check if the connection is alive send ADD BA request to AP. In this change ADDBA req is send on a particular tid for which BA session does not exist. Change-Id: Ie88a5c88b8b880cfc694a5899fc6be03bf52a2bc CRs-fixed: 1116816 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 1 + .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 66 ++++++- drivers/staging/prima/CORE/MAC/inc/sirApi.h | 6 + .../prima/CORE/MAC/src/include/sirParams.h | 2 + drivers/staging/prima/CORE/SME/inc/sme_Api.h | 3 + .../prima/CORE/SME/src/sme_common/sme_Api.c | 45 +++++ .../CORE/SYS/legacy/src/utils/src/macTrace.c | 2 + .../staging/prima/CORE/WDA/inc/wlan_qct_wda.h | 6 + .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 183 +++++++++++++++++- 9 files changed, 311 insertions(+), 3 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 209f35fb2bb2..39ffa06093f0 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -1247,6 +1247,7 @@ struct hdd_adapter_s /* Currently used antenna Index*/ int antennaIndex; + bool nud_set_arp_stats; bool con_status; bool dad; }; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 439a76e945f3..a72bd3c3f452 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -7485,6 +7485,24 @@ qca_wlan_vendor_set_nud_stats[STATS_SET_MAX +1] = [STATS_GW_IPV4] = {.type = NLA_U32 }, }; +/** + * hdd_test_con_alive() - check connection alive + * @adapter: pointer to adapter + * + * Return: true if SME command is sent of false otherwise + */ +static bool hdd_test_con_alive(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (eHAL_STATUS_SUCCESS != sme_test_con_alive(hdd_ctx->hHal)) { + hddLog(LOGE, FL("could not send ADDBA")); + return false; + } + + return true; +} + /** * hdd_set_nud_stats_cb() - hdd callback api to get status * @data: pointer to adapter @@ -7503,6 +7521,8 @@ static void hdd_set_nud_stats_cb(void *data, VOS_STATUS rsp) if (VOS_STATUS_SUCCESS == rsp) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s success received STATS_SET_START", __func__); + if (adapter->nud_set_arp_stats) + hdd_test_con_alive(adapter); } else { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s STATS_SET_START Failed!!", __func__); @@ -7563,11 +7583,13 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, return -EINVAL; } arp_stats_params.flag = true; + adapter->nud_set_arp_stats = true; arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]); } else { arp_stats_params.flag = false; + adapter->nud_set_arp_stats = false; } - if (arp_stats_params.flag) { + if (!arp_stats_params.flag) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s STATS_SET_START Cleared!!", __func__); vos_mem_zero(&adapter->hdd_stats.hddArpStats, sizeof(adapter->hdd_stats.hddArpStats)); @@ -7676,6 +7698,42 @@ qca_wlan_vendor_get_nud_stats[STATS_GET_MAX +1] = [AP_LINK_DAD] = {.type = NLA_FLAG }, }; +/** + * hdd_con_alive_cb() - Call back to get the connection status + * @context: pointer to adapter + * + * Return: None + */ +static void hdd_con_alive_cb(void *context, bool status) +{ + hdd_adapter_t *adapter = (hdd_adapter_t *)context; + adapter->con_status = status; +} + +/** + * hdd_get_con_alive() - get the connection status + * @adapter: pointer to adapter + * + * Return: true if SME command is sent of false otherwise + */ +static bool hdd_get_con_alive(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + getConStatusParams conStatusParams; + + conStatusParams.rsp_cb_fn = hdd_con_alive_cb; + conStatusParams.data_ctx = adapter; + + if (eHAL_STATUS_SUCCESS != sme_get_con_alive(hdd_ctx->hHal, + &conStatusParams)) + { + hddLog(LOGE, FL("could not get connection status")); + return false; + } + + return true; +} + static void hdd_get_nud_stats_cb(void *data, rsp_stats *rsp) { @@ -7730,6 +7788,8 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, if (0 != err) return err; + hdd_get_con_alive(adapter); + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; arp_stats_params.get_rsp_cb_fn = hdd_get_nud_stats_cb; arp_stats_params.data_ctx = adapter; @@ -7791,8 +7851,10 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, kfree_skb(skb); return -EINVAL; } - if (adapter->con_status) + if (adapter->con_status) { nla_put_flag(skb, AP_LINK_ACTIVE); + adapter->con_status = false; + } if (adapter->dad) nla_put_flag(skb, AP_LINK_DAD); diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 67945175ea98..7acadd90b7e0 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -6109,5 +6109,11 @@ typedef struct { tANI_U32 value; } tModifyRoamParamsReqParams, * tpModifyRoamParamsReqParams; +typedef void(*hdd_conAliveCb)(void *data, bool status); + +typedef struct { + hdd_conAliveCb rsp_cb_fn; + void *data_ctx; +}getConStatusParams, *pgetConStatusParams; #endif /* __SIR_API_H */ diff --git a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h index 8d3e8699bf67..5dfe0eaf51a1 100644 --- a/drivers/staging/prima/CORE/MAC/src/include/sirParams.h +++ b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h @@ -770,6 +770,8 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 301) #define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 302) +#define SIR_HAL_TRIGGER_ADD_BA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 303) +#define SIR_HAL_GET_CON_STATUS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 304) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) // CFG message types diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 97467cbb228a..66a459fb69ed 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h @@ -3967,4 +3967,7 @@ eHalStatus sme_set_nud_debug_stats(tHalHandle hHal, psetArpStatsParams pSetStatsParam); eHalStatus sme_get_nud_debug_stats(tHalHandle hHal, pgetArpStatsParams pGetStatsParam); +eHalStatus sme_test_con_alive(tHalHandle hHal); +eHalStatus sme_get_con_alive(tHalHandle hHal, + pgetConStatusParams conStatusParams); #endif //#if !defined( __SME_API_H ) diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index ba892cebba5a..4f3a87b16407 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -14489,3 +14489,48 @@ eHalStatus sme_get_nud_debug_stats(tHalHandle hHal, return VOS_STATUS_SUCCESS; } + +eHalStatus sme_test_con_alive(tHalHandle hHal) +{ + vos_msg_t wdaMsg = {0}; + + wdaMsg.type = WDA_TRIGGER_ADD_BA_REQ; + wdaMsg.bodyptr = NULL; + wdaMsg.reserved = 0; + + if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_WDA, &wdaMsg)) + return VOS_STATUS_E_FAILURE; + + return VOS_STATUS_SUCCESS; +} + + +eHalStatus sme_get_con_alive(tHalHandle hHal, + pgetConStatusParams conStatusParams) +{ + vos_msg_t wdaMsg = {0}; + pgetConStatusParams statusParams; + VOS_STATUS vosStatus; + + statusParams = vos_mem_malloc(sizeof(getConStatusParams)); + if (NULL == statusParams) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return VOS_STATUS_E_NOMEM; + } + + vos_mem_copy(statusParams, conStatusParams, sizeof(getConStatusParams)); + wdaMsg.type = WDA_GET_CON_STATUS; + wdaMsg.bodyptr = statusParams; + wdaMsg.reserved = 0; + + vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &wdaMsg); + if (!VOS_IS_STATUS_SUCCESS(vosStatus)) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL(" Not able to post message")); + vos_mem_free(statusParams); + return VOS_STATUS_E_FAILURE; + } + + return VOS_STATUS_SUCCESS; +} diff --git a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c index 7c4703bbf548..0da70dc30c0c 100644 --- a/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c +++ b/drivers/staging/prima/CORE/SYS/legacy/src/utils/src/macTrace.c @@ -908,6 +908,8 @@ tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg ) CASE_RETURN_STRING(WDA_LOST_LINK_PARAMS_IND); CASE_RETURN_STRING(WDA_SET_ARP_STATS_REQ); CASE_RETURN_STRING(WDA_GET_ARP_STATS_REQ); + CASE_RETURN_STRING(WDA_TRIGGER_ADD_BA_REQ); + CASE_RETURN_STRING(WDA_GET_CON_STATUS); default: return((tANI_U8*) "UNKNOWN" ); break; diff --git a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h index 90873fa6649f..fdc768d8ca41 100644 --- a/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h +++ b/drivers/staging/prima/CORE/WDA/inc/wlan_qct_wda.h @@ -525,6 +525,10 @@ typedef struct uint8_t mgmt_pktfree_fail; vos_lock_t mgmt_pkt_lock; + /* debug connection status */ + bool tx_aggr; + uint8_t sta_id; + uint8_t tid; } tWDA_CbContext ; typedef struct @@ -1294,6 +1298,8 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); /* ARP Debug */ #define WDA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ #define WDA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ +#define WDA_TRIGGER_ADD_BA_REQ SIR_HAL_TRIGGER_ADD_BA_REQ +#define WDA_GET_CON_STATUS SIR_HAL_GET_CON_STATUS tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 5d10db7f8cc9..50a77f3139b5 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -166,6 +166,12 @@ static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) ; static VOS_STATUS wdaDestroyTimers(tWDA_CbContext *pWDA); bool WDA_AllowAddBA(tpAniSirGlobal pMAc, tANI_U8 staId, tANI_U8 tid); void WDA_BaCheckActivity(tWDA_CbContext *pWDA) ; + +/* check connection status */ +void WDA_TriggerBACheck(tWDA_CbContext *pWDA); +void WDA_GetConnectionStatus(tWDA_CbContext *pWDA, + getConStatusParams *conStatusParams); + void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA); void WDA_HALDumpCmdCallback(WDI_HALDumpCmdRspParamsType *wdiRspParams, void* pUserData); #ifdef WLAN_FEATURE_VOWIFI_11R @@ -16187,13 +16193,23 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) WDA_BaCheckActivity(pWDA) ; break ; } - /* timer related messages */ case WDA_TIMER_TRAFFIC_STATS_IND: { WDA_TimerTrafficStatsInd(pWDA); break; } + /* Connection status related messages */ + case WDA_TRIGGER_ADD_BA_REQ: + { + WDA_TriggerBACheck(pWDA); + break; + } + case WDA_GET_CON_STATUS: + { + WDA_GetConnectionStatus(pWDA, (getConStatusParams *)pMsg->bodyptr); + break; + } #ifdef WLAN_FEATURE_VOWIFI_11R case WDA_AGGR_QOS_REQ: { @@ -18094,6 +18110,171 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) } return ; } + +/* + * Trigger BA request to test connection status + */ +void WDA_TriggerBACheck(tWDA_CbContext *pWDA) +{ + tANI_U8 curSta = 0; + tANI_U8 tid = 0; + tANI_U8 size = 0; + tANI_U8 baCandidateCount = 0; + tANI_U8 newBaCandidate = 0; + tANI_U32 val; + WDI_TriggerBAReqCandidateType baCandidate[WDA_MAX_STA] = {{0}}; + tpAniSirGlobal pMac; + + if (NULL == pWDA || NULL == pWDA->pVosContext) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Invalid memory", __func__); + return; + } + + if(WDA_MAX_STA < pWDA->wdaMaxSta) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Inconsistent STA entries in WDA"); + } + + pMac = (tpAniSirGlobal )VOS_GET_MAC_CTXT(pWDA->pVosContext); + if(NULL == pMac) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pMac is NULL",__func__); + return ; + } + + if (wlan_cfgGetInt(pMac, + WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC, &val) != + eSIR_SUCCESS) { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "Unable to get WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC"); + val = 0; + } + + /* walk through all STA entries and find out TX packet count */ + for(curSta = 0 ; curSta < pWDA->wdaMaxSta ; curSta++) + { + tANI_U32 currentOperChan = pWDA->wdaStaInfo[curSta].currentOperChan; + WLANTL_STAStateType tlSTAState; + tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex; + + if (!((WDA_VALID_STA_INDEX == validStaIndex) && + (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE( pWDA->pVosContext, + curSta, &tlSTAState)))) + continue; + + if (WLANTL_STA_AUTHENTICATED != tlSTAState) + continue; + +#ifdef WLAN_SOFTAP_VSTA_FEATURE + /* We can only do BA on "hard" STAs */ + if (!(IS_HWSTA_IDX(curSta))) + continue; +#endif + + if(val && ((currentOperChan >= SIR_11B_CHANNEL_BEGIN) && + (currentOperChan <= SIR_11B_CHANNEL_END))) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: BTC disabled aggregation - dont start " + "TX ADDBA req",__func__); + continue; + } + + for(tid = 0; tid < STACFG_MAX_TC; tid ++) + { + if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) && + WDA_AllowAddBA(pMac, curSta, tid)) + { + baCandidate[baCandidateCount].ucTidBitmap |= 1 << tid; + newBaCandidate = WDA_ENABLE_BA; + pWDA->tx_aggr = true; + pWDA->tid = tid; + pWDA->sta_id = curSta; + break; + } + } + + if(WDA_ENABLE_BA == newBaCandidate) + { + baCandidate[baCandidateCount].ucSTAIdx = curSta; + size += sizeof(WDI_TriggerBAReqCandidateType); + baCandidateCount++; + newBaCandidate = WDA_DISABLE_BA; + } + } + + if (0 < baCandidateCount) + { + WDI_Status status = WDI_STATUS_SUCCESS; + WDI_TriggerBAReqParamsType *wdiTriggerBaReq; + tWDA_ReqParams *pWdaParams = + (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)); + if(NULL == pWdaParams) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + VOS_ASSERT(0); + return; + } + wdiTriggerBaReq = (WDI_TriggerBAReqParamsType *) + vos_mem_malloc(sizeof(WDI_TriggerBAReqParamsType) + size); + if(NULL == wdiTriggerBaReq) + { + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: VOS MEM Alloc Failure", __func__); + vos_mem_free(pWdaParams); + return; + } + do + { + WDI_TriggerBAReqinfoType *triggerBaInfo = + &wdiTriggerBaReq->wdiTriggerBAInfoType; + triggerBaInfo->usBACandidateCnt = baCandidateCount; + triggerBaInfo->ucSTAIdx = baCandidate[0].ucSTAIdx; + triggerBaInfo->ucBASessionID = 0; + vos_mem_copy((wdiTriggerBaReq + 1), baCandidate, size); + } while(0); + wdiTriggerBaReq->wdiReqStatusCB = NULL; + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "------> %s " ,__func__); + pWdaParams->pWdaContext = pWDA; + pWdaParams->wdaWdiApiMsgParam = wdiTriggerBaReq; + pWdaParams->wdaMsgParam = NULL; + status = WDI_TriggerBAReq(wdiTriggerBaReq, size, + WDA_TriggerBaReqCallback, pWdaParams); + if(IS_WDI_STATUS_FAILURE(status)) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: Failure in Trigger BA REQ, free memory", __func__); + vos_mem_free(pWdaParams->wdaMsgParam); + vos_mem_free(pWdaParams->wdaWdiApiMsgParam); + vos_mem_free(pWdaParams); + } + } + else { + pWDA->tx_aggr = false; + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: ADD BA is disabled for all the tids", __func__); + } + + return; +} + +void WDA_GetConnectionStatus(tWDA_CbContext *pWDA, + getConStatusParams *conStatusParams) +{ + uint8_t sta_id = pWDA->sta_id; + uint8_t tid = pWDA->tid; + + if (!pWDA->tx_aggr || !WDA_GET_BA_TXFLAG(pWDA, sta_id, tid)) { + if (conStatusParams->rsp_cb_fn) + conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, false); + return; + } + + conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, true); +} + /* * WDA common routine to create timer used by WDA. */ From ab8b381a487115451a23e076b2b0e887f1ea7f54 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Mon, 13 Feb 2017 23:07:44 +0530 Subject: [PATCH 243/281] wlan: Refactor trigger ADDBA code for test connection status This change is to refactor the ADDBA request code which is done to test AP connection status when framework detects network unreachability. Change-Id: If50640daad6e7c2e9aa738b20a94981657dd241f CRs-fixed: 1116816 --- .../staging/prima/CORE/MAC/inc/aniGlobal.h | 7 + .../staging/prima/CORE/WDA/src/wlan_qct_wda.c | 282 ++++++------------ 2 files changed, 94 insertions(+), 195 deletions(-) diff --git a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h index 1d50dbfa1b24..ad2df331f60c 100644 --- a/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h +++ b/drivers/staging/prima/CORE/MAC/inc/aniGlobal.h @@ -260,6 +260,12 @@ typedef struct { v_TIME_t failed_timestamp[MAX_TIDS]; } tLimStaBAInfo; +typedef struct { + bool tx_aggr; + uint8_t sta_id; + uint8_t tid; +} t_test_status_bainfo; + typedef struct sAniSirLim { ////////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// @@ -914,6 +920,7 @@ tLimMlmOemDataRsp *gpLimMlmOemDataRsp; tANI_U32 txBdToken; tANI_U32 EnableTdls2040BSSCoexIE; tLimStaBAInfo staBaInfo[WLAN_MAX_STA_COUNT]; + t_test_status_bainfo test_status_bainfo; } tAniSirLim, *tpAniSirLim; typedef struct sLimMgmtFrameRegistration diff --git a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 50a77f3139b5..f88a83b8398b 100644 --- a/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c +++ b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c @@ -165,10 +165,9 @@ void WDA_lowLevelIndCallback(WDI_LowLevelIndType *wdiLowLevelInd, static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) ; static VOS_STATUS wdaDestroyTimers(tWDA_CbContext *pWDA); bool WDA_AllowAddBA(tpAniSirGlobal pMAc, tANI_U8 staId, tANI_U8 tid); -void WDA_BaCheckActivity(tWDA_CbContext *pWDA) ; +void WDA_BaCheckActivity(tWDA_CbContext *pWDA, bool test_con); /* check connection status */ -void WDA_TriggerBACheck(tWDA_CbContext *pWDA); void WDA_GetConnectionStatus(tWDA_CbContext *pWDA, getConStatusParams *conStatusParams); @@ -16190,7 +16189,7 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) /* timer related messages */ case WDA_TIMER_BA_ACTIVITY_REQ: { - WDA_BaCheckActivity(pWDA) ; + WDA_BaCheckActivity(pWDA, false); break ; } /* timer related messages */ @@ -16202,7 +16201,7 @@ VOS_STATUS WDA_McProcessMsg( v_CONTEXT_t pVosContext, vos_msg_t *pMsg ) /* Connection status related messages */ case WDA_TRIGGER_ADD_BA_REQ: { - WDA_TriggerBACheck(pWDA); + WDA_BaCheckActivity(pWDA, true); break; } case WDA_GET_CON_STATUS: @@ -17925,10 +17924,45 @@ bool WDA_AllowAddBA(tpAniSirGlobal pMac, tANI_U8 staId, tANI_U8 tid) return true; } +void WDA_GetConnectionStatus(tWDA_CbContext *pWDA, + getConStatusParams *conStatusParams) +{ + tpAniSirGlobal pMac; + uint8_t sta_id, tid; + bool tx_aggr; + bool status = false; + + pMac = (tpAniSirGlobal)VOS_GET_MAC_CTXT(pWDA->pVosContext); + if (NULL == pMac) + { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, + "%s: pMac is NULL",__func__); + return; + } + + tx_aggr= pMac->lim.test_status_bainfo.tx_aggr; + sta_id = pMac->lim.test_status_bainfo.sta_id; + tid = pMac->lim.test_status_bainfo.tid; + + if (tx_aggr && WDA_GET_BA_TXFLAG(pWDA, sta_id, tid)) + status = true; + + if (conStatusParams->rsp_cb_fn) + conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, status); +} + +static void WDA_StoreTestBAInfo(tpAniSirGlobal pMac, bool tx_aggr, + uint8_t sta_id, uint8_t tid) +{ + pMac->lim.test_status_bainfo.tx_aggr = tx_aggr; + pMac->lim.test_status_bainfo.sta_id= sta_id; + pMac->lim.test_status_bainfo.tid = tid; +} + /* * BA Activity check timer handler */ -void WDA_BaCheckActivity(tWDA_CbContext *pWDA) +void WDA_BaCheckActivity(tWDA_CbContext *pWDA, bool test_con) { tANI_U8 curSta = 0 ; tANI_U8 tid = 0 ; @@ -17938,6 +17972,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) tANI_U32 val; WDI_TriggerBAReqCandidateType baCandidate[WDA_MAX_STA] = {{0}} ; tpAniSirGlobal pMac; + bool found = false; if (NULL == pWDA) { @@ -17981,6 +18016,12 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) for(curSta = 0 ; curSta < pWDA->wdaMaxSta ; curSta++) { tANI_U32 currentOperChan = pWDA->wdaStaInfo[curSta].currentOperChan; + WLANTL_STAStateType tlSTAState; + tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex; + + if (found) + break; + #ifdef WLAN_SOFTAP_VSTA_FEATURE // We can only do BA on "hard" STAs. if (!(IS_HWSTA_IDX(curSta))) @@ -17988,41 +18029,47 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) continue; } #endif //WLAN_SOFTAP_VSTA_FEATURE + + if (!((WDA_VALID_STA_INDEX == validStaIndex) && + (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE(pWDA->pVosContext, + curSta, &tlSTAState)))) + continue; + + if (WLANTL_STA_AUTHENTICATED != tlSTAState) + continue; + + if(val && ((currentOperChan >= SIR_11B_CHANNEL_BEGIN) && + (currentOperChan <= SIR_11B_CHANNEL_END))) { + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: BTC disabled aggregation - dont start" + "TX ADDBA req",__func__); + continue; + } + for(tid = 0 ; tid < STACFG_MAX_TC ; tid++) { - WLANTL_STAStateType tlSTAState ; tANI_U32 txPktCount = 0 ; - tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex ; - if((WDA_VALID_STA_INDEX == validStaIndex) && - (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE( pWDA->pVosContext, - curSta, &tlSTAState)) && - (VOS_STATUS_SUCCESS == WDA_TL_GET_TX_PKTCOUNT( pWDA->pVosContext, - curSta, tid, &txPktCount))) + if (VOS_STATUS_SUCCESS == WDA_TL_GET_TX_PKTCOUNT( pWDA->pVosContext, + curSta, tid, &txPktCount)) { -#if 0 - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO_LOW, - "************* %d:%d, %d ",curSta, txPktCount, - pWDA->wdaStaInfo[curSta].framesTxed[tid]); -#endif - if(val && ( (currentOperChan >= SIR_11B_CHANNEL_BEGIN) && - (currentOperChan <= SIR_11B_CHANNEL_END))) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "%s: BTC disabled aggregation - dont start " - "TX ADDBA req",__func__); - } - else if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) - && (WLANTL_STA_AUTHENTICATED == tlSTAState) - && WDA_AllowAddBA(pMac, curSta, tid) - && (((eSYSTEM_STA_IN_IBSS_ROLE == - pWDA->wdaGlobalSystemRole) && txPktCount ) - || (txPktCount >= WDA_LAST_POLLED_THRESHOLD(pWDA, - curSta, tid)))) + if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) && + WDA_AllowAddBA(pMac, curSta, tid) && + (((eSYSTEM_STA_IN_IBSS_ROLE == pWDA->wdaGlobalSystemRole) + && txPktCount) || + (txPktCount >= WDA_LAST_POLLED_THRESHOLD(pWDA, curSta, tid)) || + test_con)) { /* get prepare for sending message to HAL */ //baCandidate[baCandidateCount].staIdx = curSta ; baCandidate[baCandidateCount].ucTidBitmap |= 1 << tid ; newBaCandidate = WDA_ENABLE_BA ; + + /* Trigger only one BA request to check connection status */ + if (test_con) { + WDA_StoreTestBAInfo(pMac, true, curSta, tid); + found = true; + break; + } } pWDA->wdaStaInfo[curSta].framesTxed[tid] = txPktCount ; } @@ -18091,6 +18138,14 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) } else { + if (test_con) + { + WDA_StoreTestBAInfo(pMac, false, pWDA->wdaMaxSta, STACFG_MAX_TC); + VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, + "%s: ADDBA to test connection status no valid Tid found", + __func__); + } + VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO_LOW, "There is no TID for initiating BA"); } @@ -18111,170 +18166,6 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) return ; } -/* - * Trigger BA request to test connection status - */ -void WDA_TriggerBACheck(tWDA_CbContext *pWDA) -{ - tANI_U8 curSta = 0; - tANI_U8 tid = 0; - tANI_U8 size = 0; - tANI_U8 baCandidateCount = 0; - tANI_U8 newBaCandidate = 0; - tANI_U32 val; - WDI_TriggerBAReqCandidateType baCandidate[WDA_MAX_STA] = {{0}}; - tpAniSirGlobal pMac; - - if (NULL == pWDA || NULL == pWDA->pVosContext) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: Invalid memory", __func__); - return; - } - - if(WDA_MAX_STA < pWDA->wdaMaxSta) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Inconsistent STA entries in WDA"); - } - - pMac = (tpAniSirGlobal )VOS_GET_MAC_CTXT(pWDA->pVosContext); - if(NULL == pMac) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: pMac is NULL",__func__); - return ; - } - - if (wlan_cfgGetInt(pMac, - WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC, &val) != - eSIR_SUCCESS) { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "Unable to get WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC"); - val = 0; - } - - /* walk through all STA entries and find out TX packet count */ - for(curSta = 0 ; curSta < pWDA->wdaMaxSta ; curSta++) - { - tANI_U32 currentOperChan = pWDA->wdaStaInfo[curSta].currentOperChan; - WLANTL_STAStateType tlSTAState; - tANI_U8 validStaIndex = pWDA->wdaStaInfo[curSta].ucValidStaIndex; - - if (!((WDA_VALID_STA_INDEX == validStaIndex) && - (VOS_STATUS_SUCCESS == WDA_TL_GET_STA_STATE( pWDA->pVosContext, - curSta, &tlSTAState)))) - continue; - - if (WLANTL_STA_AUTHENTICATED != tlSTAState) - continue; - -#ifdef WLAN_SOFTAP_VSTA_FEATURE - /* We can only do BA on "hard" STAs */ - if (!(IS_HWSTA_IDX(curSta))) - continue; -#endif - - if(val && ((currentOperChan >= SIR_11B_CHANNEL_BEGIN) && - (currentOperChan <= SIR_11B_CHANNEL_END))) { - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "%s: BTC disabled aggregation - dont start " - "TX ADDBA req",__func__); - continue; - } - - for(tid = 0; tid < STACFG_MAX_TC; tid ++) - { - if(!WDA_GET_BA_TXFLAG(pWDA, curSta, tid) && - WDA_AllowAddBA(pMac, curSta, tid)) - { - baCandidate[baCandidateCount].ucTidBitmap |= 1 << tid; - newBaCandidate = WDA_ENABLE_BA; - pWDA->tx_aggr = true; - pWDA->tid = tid; - pWDA->sta_id = curSta; - break; - } - } - - if(WDA_ENABLE_BA == newBaCandidate) - { - baCandidate[baCandidateCount].ucSTAIdx = curSta; - size += sizeof(WDI_TriggerBAReqCandidateType); - baCandidateCount++; - newBaCandidate = WDA_DISABLE_BA; - } - } - - if (0 < baCandidateCount) - { - WDI_Status status = WDI_STATUS_SUCCESS; - WDI_TriggerBAReqParamsType *wdiTriggerBaReq; - tWDA_ReqParams *pWdaParams = - (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)); - if(NULL == pWdaParams) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: VOS MEM Alloc Failure", __func__); - VOS_ASSERT(0); - return; - } - wdiTriggerBaReq = (WDI_TriggerBAReqParamsType *) - vos_mem_malloc(sizeof(WDI_TriggerBAReqParamsType) + size); - if(NULL == wdiTriggerBaReq) - { - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: VOS MEM Alloc Failure", __func__); - vos_mem_free(pWdaParams); - return; - } - do - { - WDI_TriggerBAReqinfoType *triggerBaInfo = - &wdiTriggerBaReq->wdiTriggerBAInfoType; - triggerBaInfo->usBACandidateCnt = baCandidateCount; - triggerBaInfo->ucSTAIdx = baCandidate[0].ucSTAIdx; - triggerBaInfo->ucBASessionID = 0; - vos_mem_copy((wdiTriggerBaReq + 1), baCandidate, size); - } while(0); - wdiTriggerBaReq->wdiReqStatusCB = NULL; - VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "------> %s " ,__func__); - pWdaParams->pWdaContext = pWDA; - pWdaParams->wdaWdiApiMsgParam = wdiTriggerBaReq; - pWdaParams->wdaMsgParam = NULL; - status = WDI_TriggerBAReq(wdiTriggerBaReq, size, - WDA_TriggerBaReqCallback, pWdaParams); - if(IS_WDI_STATUS_FAILURE(status)) - { - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR, - "%s: Failure in Trigger BA REQ, free memory", __func__); - vos_mem_free(pWdaParams->wdaMsgParam); - vos_mem_free(pWdaParams->wdaWdiApiMsgParam); - vos_mem_free(pWdaParams); - } - } - else { - pWDA->tx_aggr = false; - VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, - "%s: ADD BA is disabled for all the tids", __func__); - } - - return; -} - -void WDA_GetConnectionStatus(tWDA_CbContext *pWDA, - getConStatusParams *conStatusParams) -{ - uint8_t sta_id = pWDA->sta_id; - uint8_t tid = pWDA->tid; - - if (!pWDA->tx_aggr || !WDA_GET_BA_TXFLAG(pWDA, sta_id, tid)) { - if (conStatusParams->rsp_cb_fn) - conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, false); - return; - } - - conStatusParams->rsp_cb_fn(conStatusParams->data_ctx, true); -} - /* * WDA common routine to create timer used by WDA. */ @@ -18358,6 +18249,7 @@ static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) } return VOS_STATUS_SUCCESS ; } + /* * WDA common routine to destroy timer used by WDA. */ From 0bacdaef6289af652b3f2ea853d0aa5e48adfff7 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Wed, 1 Feb 2017 10:28:31 +0530 Subject: [PATCH 244/281] wlan: Send DELBA for BA session set up to test connection During internet unreachability detection ADDBA request is sent on used tid to check if the connection is alive. If the connection status is alive BA session will be set up. In this change send DELBA for the BA session which is established to test the connection status. Change-Id: I4eac7d04d71be51ca4bcf8063113267d77877f95 CRs-fixed: 1116816 --- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 24 +++++++++ drivers/staging/prima/CORE/MAC/inc/sirApi.h | 3 +- drivers/staging/prima/CORE/MAC/inc/wniApi.h | 1 + .../MAC/src/pe/lim/limProcessMessageQueue.c | 1 + .../MAC/src/pe/lim/limProcessSmeReqMessages.c | 54 +++++++++++++++++++ drivers/staging/prima/CORE/SME/inc/sme_Api.h | 2 + .../prima/CORE/SME/src/sme_common/sme_Api.c | 49 +++++++++++++++++ 7 files changed, 132 insertions(+), 2 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index a72bd3c3f452..a3f404b21caa 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -7734,6 +7734,29 @@ static bool hdd_get_con_alive(hdd_adapter_t *adapter) return true; } +/** + * hdd_con_test_DELBA() - delete the BA session + * @adapter: pointer to adapter + * + * Return: true if SME command is sent of false otherwise + */ +static bool hdd_con_test_DELBA(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *pHddStaCtx = &adapter->sessionCtx.station; + uint8_t sta_id = pHddStaCtx->conn_info.staId[0]; + + ENTER(); + + if (eHAL_STATUS_SUCCESS != sme_test_con_delba((hdd_ctx->hHal), sta_id, + adapter->sessionId)) { + hddLog(LOGE, FL("could not send DELBA ")); + return false; + } + + return true; +} + static void hdd_get_nud_stats_cb(void *data, rsp_stats *rsp) { @@ -7854,6 +7877,7 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, if (adapter->con_status) { nla_put_flag(skb, AP_LINK_ACTIVE); adapter->con_status = false; + hdd_con_test_DELBA(adapter); } if (adapter->dad) nla_put_flag(skb, AP_LINK_DAD); diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 7acadd90b7e0..af6bf0393142 100644 --- a/drivers/staging/prima/CORE/MAC/inc/sirApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/sirApi.h @@ -2929,11 +2929,10 @@ typedef struct sSmeDelBAPeerInd // Message Type tANI_U16 mesgType; - tSirMacAddr bssId;//BSSID - // Message Length tANI_U16 mesgLen; + tSirMacAddr bssId;//BSSID // Station Index tANI_U16 staIdx; diff --git a/drivers/staging/prima/CORE/MAC/inc/wniApi.h b/drivers/staging/prima/CORE/MAC/inc/wniApi.h index ff69d7f45045..bdea77c7c0c2 100644 --- a/drivers/staging/prima/CORE/MAC/inc/wniApi.h +++ b/drivers/staging/prima/CORE/MAC/inc/wniApi.h @@ -235,6 +235,7 @@ enum eWniMsgTypes eWNI_SME_PRE_CHANNEL_SWITCH_FULL_POWER, eWNI_SME_GET_SNR_REQ, eWNI_SME_LOST_LINK_PARAMS_IND, + eWNI_SME_DEL_TEST_BA, //General Power Save Messages eWNI_PMC_MSG_TYPES_BEGIN, eWNI_PMC_PWR_SAVE_CFG, diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c index cb83c73df283..e8b9fced0b36 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessMessageQueue.c @@ -1625,6 +1625,7 @@ limProcessMessages(tpAniSirGlobal pMac, tpSirMsgQ limMsg) #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ case eWNI_SME_MAC_SPOOF_ADDR_IND: case eWNI_SME_REGISTER_MGMT_FRAME_CB: + case eWNI_SME_DEL_TEST_BA: // These messages are from HDD limProcessNormalHddMsg(pMac, limMsg, false); //no need to response to hdd break; diff --git a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c index 1eafb0ef6787..cead21d75b15 100644 --- a/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c +++ b/drivers/staging/prima/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c @@ -5519,6 +5519,57 @@ static void lim_register_mgmt_frame_ind_cb(tpAniSirGlobal pMac, limLog(pMac, LOGE, FL("sme_req->callback is null")); } +static void lim_delba_con_status(tpAniSirGlobal pMac, + void *msg_buf) +{ + tpSmeDelBAPeerInd delba_params; + tpDphHashNode pSta; + tANI_U16 aid; + tLimBAState curBaState; + tpPESession psessionEntry; + tANI_U8 sessionId; + + delba_params = (tpSmeDelBAPeerInd)msg_buf; + + psessionEntry = peFindSessionByBssid(pMac, delba_params->bssId, &sessionId); + if (!psessionEntry) + { + PELOGE(limLog(pMac, LOGE,FL("session does not exist for given BSSId"));) + return; + } + + pSta = dphLookupHashEntry(pMac, delba_params->bssId, &aid, + &psessionEntry->dph.dphHashTable); + if(!pSta) + { + limLog(pMac, LOGE, + FL("STA context not found - ignoring BA Delete IND from HAL")); + return; + } + + LIM_GET_STA_BA_STATE(pSta, delba_params->baTID, &curBaState); + if( eLIM_BA_STATE_IDLE != curBaState ) + { + limLog(pMac, LOGE, + FL("Received unexpected BA Delete IND when STA BA state is %d"), + curBaState); + return; + } + + if(eSIR_SUCCESS != limPostMlmDelBAReq(pMac, pSta, + delba_params->baDirection, + delba_params->baTID, + eSIR_MAC_PEER_REJECT_MECHANISIM_REASON, + psessionEntry)) { + limLog(pMac, LOGE, FL("Post DEL BA request failed")); + } + else + { + limLog(pMac, LOG1, FL(" Delete BA session StaId %d on tid %d"), + delba_params->staIdx, delba_params->baTID); + } +} + /** * limProcessSmeReqMessages() * @@ -5865,6 +5916,9 @@ limProcessSmeReqMessages(tpAniSirGlobal pMac, tpSirMsgQ pMsg) case eWNI_SME_REGISTER_MGMT_FRAME_CB: lim_register_mgmt_frame_ind_cb(pMac, pMsgBuf); break; + case eWNI_SME_DEL_TEST_BA: + lim_delba_con_status(pMac, pMsgBuf); + break; default: vos_mem_free((v_VOID_t*)pMsg->bodyptr); pMsg->bodyptr = NULL; diff --git a/drivers/staging/prima/CORE/SME/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 66a459fb69ed..cf65a45270b4 100644 --- a/drivers/staging/prima/CORE/SME/inc/sme_Api.h +++ b/drivers/staging/prima/CORE/SME/inc/sme_Api.h @@ -3970,4 +3970,6 @@ eHalStatus sme_get_nud_debug_stats(tHalHandle hHal, eHalStatus sme_test_con_alive(tHalHandle hHal); eHalStatus sme_get_con_alive(tHalHandle hHal, pgetConStatusParams conStatusParams); +eHalStatus sme_test_con_delba(tHalHandle hHal, uint8_t sta_id, + uint8_t session_id); #endif //#if !defined( __SME_API_H ) diff --git a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c index 4f3a87b16407..dbcbccb66d40 100644 --- a/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/staging/prima/CORE/SME/src/sme_common/sme_Api.c @@ -14534,3 +14534,52 @@ eHalStatus sme_get_con_alive(tHalHandle hHal, return VOS_STATUS_SUCCESS; } + +eHalStatus sme_test_con_delba(tHalHandle hHal, uint8_t sta_id, + uint8_t session_id) +{ + tpSmeDelBAPeerInd msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + eHalStatus status = eHAL_STATUS_FAILURE; + + if (!CSR_IS_SESSION_VALID(pMac, session_id)) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Session is invalid")); + return status; + } + + if (!pMac->lim.test_status_bainfo.tx_aggr) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("BA session not established")); + return status; + } + + if (eHAL_STATUS_SUCCESS == sme_AcquireGlobalLock(&pMac->sme)) + { + msg = vos_mem_malloc(sizeof(tSmeDelBAPeerInd)); + if (NULL == msg) + { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return VOS_STATUS_E_NOMEM; + } + + msg->staIdx = sta_id; + msg->baTID = pMac->lim.test_status_bainfo.tid; + vos_mem_copy(msg->bssId, pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); + msg->baDirection = eBA_INITIATOR; + + msg->mesgType = eWNI_SME_DEL_TEST_BA; + msg->mesgLen = sizeof(tSmeDelBAPeerInd); + + status = palSendMBMessage(pMac->hHdd, msg); + + sme_ReleaseGlobalLock(&pMac->sme); + } + + return status; +} From d6a896e02e1a66d398428a22722e1e57a5113de0 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Fri, 17 Mar 2017 14:57:27 +0530 Subject: [PATCH 245/281] wlan: ARP stats for only request and reponse from gateway IP Track and get the stats for the ARP requests send to and ARP responses received from gateway IP. Gateway IP is provided as part of set NUD vendor command. Change-Id: If6d18b896116206fa75fc10a243d2c58e8c37f4b CRs-Fixed: 2019636 --- .../prima/CORE/HDD/inc/wlan_hdd_main.h | 4 +- .../prima/CORE/HDD/src/wlan_hdd_cfg80211.c | 6 +- .../prima/CORE/HDD/src/wlan_hdd_tx_rx.c | 26 +-- .../prima/CORE/HDD/src/wlan_hdd_wext.c | 4 +- .../staging/prima/CORE/TL/src/wlan_qct_tl.c | 4 +- .../prima/CORE/TL/src/wlan_qct_tl_ba.c | 5 +- drivers/staging/prima/CORE/VOSS/inc/vos_api.h | 5 +- .../staging/prima/CORE/VOSS/inc/vos_packet.h | 10 ++ drivers/staging/prima/CORE/VOSS/src/vos_api.c | 152 ++++++++++++++++-- .../CORE/WDI/WPAL/src/wlan_qct_pal_api.c | 8 +- 10 files changed, 196 insertions(+), 28 deletions(-) diff --git a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h index 39ffa06093f0..6ce324a48b28 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_main.h @@ -392,8 +392,8 @@ typedef enum typedef struct hdd_arp_stats_s { - uint16 txCount; - uint16 rxCount; + uint16 tx_arp_req_count; + uint16 rx_arp_rsp_count; uint16 txDropped; uint16 rxDropped; uint16 rxDelivered; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index a3f404b21caa..547d6ad72120 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -7592,6 +7592,7 @@ static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, if (!arp_stats_params.flag) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s STATS_SET_START Cleared!!", __func__); + hdd_ctx->track_arp_ip = 0; vos_mem_zero(&adapter->hdd_stats.hddArpStats, sizeof(adapter->hdd_stats.hddArpStats)); } @@ -7855,7 +7856,7 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, } if (nla_put_u16(skb, COUNT_FROM_NETDEV, - adapter->hdd_stats.hddArpStats.txCount) || + adapter->hdd_stats.hddArpStats.tx_arp_req_count) || nla_put_u16(skb, COUNT_TO_LOWER_MAC, adapter->hdd_stats.hddArpStats.tx_host_fw_sent) || nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, @@ -7865,7 +7866,7 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, adapter->hdd_stats.hddArpStats.rx_fw_cnt) || nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, - adapter->hdd_stats.hddArpStats.rxCount) || + adapter->hdd_stats.hddArpStats.rx_arp_rsp_count) || nla_put_u16(skb, RSP_COUNT_TO_NETDEV, adapter->hdd_stats.hddArpStats.rxDelivered) || nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, @@ -7882,6 +7883,7 @@ static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, if (adapter->dad) nla_put_flag(skb, AP_LINK_DAD); + hdd_ctx->track_arp_ip = 0; cfg80211_vendor_cmd_reply(skb); return err; } diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c index c80b4c85adbb..a3a73db43671 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -840,9 +840,11 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (arp_pkt) { - ++pAdapter->hdd_stats.hddArpStats.txCount; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s :ARP packet received form net_dev", __func__); + if (pHddCtx->track_arp_ip && vos_check_arp_req_target_ip(skb, false)) { + ++pAdapter->hdd_stats.hddArpStats.tx_arp_req_count; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :ARP packet received form net_dev", __func__); + } } //Get TL Q index corresponding to Qdisc queue index/AC. @@ -2676,6 +2678,7 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, vos_pkt_t* pNextVosPacket; v_U8_t proto_type; v_BOOL_t arp_pkt; + bool track_arp_resp = false; //Sanity check on inputs if ( ( NULL == vosContext ) || @@ -2808,9 +2811,12 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, if (arp_pkt) { - ++pAdapter->hdd_stats.hddArpStats.rxCount; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s :STA RX ARP received",__func__); + if (pHddCtx->track_arp_ip && vos_check_arp_rsp_src_ip(skb, false)) { + ++pAdapter->hdd_stats.hddArpStats.rx_arp_rsp_count; + track_arp_resp = true; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s :STA RX ARP received",__func__); + } } if (pHddCtx->rx_wow_dump) { @@ -2863,9 +2869,11 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, if (arp_pkt) { - ++pAdapter->hdd_stats.hddArpStats.rxDelivered; - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "STA RX ARP packet Delivered to net stack"); + if (track_arp_resp) { + ++pAdapter->hdd_stats.hddArpStats.rxDelivered; + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "STA RX ARP packet Delivered to net stack"); + } } ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered; diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index a004a9fdb363..5cadb459d21f 100644 --- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c @@ -7020,10 +7020,10 @@ static int __iw_get_char_setnone(struct net_device *dev, pResetStats->totalFWHearbeatFailures, pResetStats->totalUnknownExceptions, - parpStats->txCount, + parpStats->tx_arp_req_count, parpStats->txDropped, - parpStats->rxCount, + parpStats->rx_arp_rsp_count, parpStats->rxDropped, parpStats->rxDelivered, parpStats->rxRefused, diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c index 6dc738375d18..09754b8a967a 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl.c @@ -8309,11 +8309,13 @@ WLANTL_STATxAuth { if (pTLCb->track_arp) { - if (vos_check_arp_target_ip(vosDataBuff)) + if (vos_check_arp_req_target_ip(vosDataBuff->pSkb, true)) { ucTxFlag |= HAL_USE_FW_IN_TX_PATH; ucTxFlag |= HAL_TXCOMP_REQUESTED_MASK; tlMetaInfo.ucTxBdToken = ++ pTLCb->txbd_token; + TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, + "%s: ARP packet FW in data path", __func__)); } } diff --git a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c index b97af6cfdf16..ccfcfb0c6997 100644 --- a/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c +++ b/drivers/staging/prima/CORE/TL/src/wlan_qct_tl_ba.c @@ -1166,7 +1166,10 @@ VOS_STATUS WLANTL_MSDUReorder "(QCUR_FWDBUF) dropping old frame, SN=%d LastSN=%d", CSN, currentReorderInfo->LastSN)); if (vos_is_arp_pkt((*vosDataBuff)->pSkb, true)) - vos_update_arp_rx_drop_reorder(); + { + if (vos_check_arp_rsp_src_ip((*vosDataBuff)->pSkb, true)) + vos_update_arp_rx_drop_reorder(); + } status = vos_pkt_return_packet(*vosDataBuff); if (!VOS_IS_STATUS_SUCCESS(status)) diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h index 0f6fef666f49..898a039c4b76 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_api.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_api.h @@ -527,7 +527,10 @@ void vos_smd_dump_stats(void); void vos_log_wdi_event(uint16 msg, vos_wdi_trace_event_type event); void vos_dump_wdi_events(void); -bool vos_check_arp_target_ip(vos_pkt_t *pPacket); +bool vos_check_arp_target_ip(void *pSkb, bool conversion); +bool vos_check_arp_req_target_ip(void *pSkb, bool conversion); +bool vos_check_arp_src_ip(void *pSkb, bool conversion); +bool vos_check_arp_rsp_src_ip(void *pSkb, bool conversion); void vos_update_arp_fw_tx_delivered(void); void vos_update_arp_rx_drop_reorder(void); #endif // if !defined __VOS_NVITEM_H diff --git a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h index ad838d7bcf96..06e8e2c9ef2c 100644 --- a/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h +++ b/drivers/staging/prima/CORE/VOSS/inc/vos_packet.h @@ -53,6 +53,16 @@ #define VOS_PKT_PROTO_TYPE_EAPOL 0x02 #define VOS_PKT_PROTO_TYPE_DHCP 0x04 #define VOS_PKT_PROTO_TYPE_ARP 0x08 + +/* ARP packet offset values */ +#define VOS_PKT_ARP_OPCODE_OFFSET 20 +#define VOS_PKT_ARPOP_REQUEST 1 +#define VOS_PKT_ARPOP_REPLY 2 +#define VOS_ARP_TARGET_IP_OFFSET 38 +#define VOS_ARP_SRC_IP_OFFSET 28 + +#define VOS_80211_8023_HEADER_OFFSET 20 + /*-------------------------------------------------------------------------- Type declarations ------------------------------------------------------------------------*/ diff --git a/drivers/staging/prima/CORE/VOSS/src/vos_api.c b/drivers/staging/prima/CORE/VOSS/src/vos_api.c index 34802d8b6083..881a2b59bd64 100644 --- a/drivers/staging/prima/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/prima/CORE/VOSS/src/vos_api.c @@ -103,9 +103,6 @@ /* Trace index for WDI Read/Write */ #define VOS_TRACE_INDEX_MAX 256 -/* ARP Target IP offset */ -#define VOS_ARP_TARGET_IP_OFFSET 58 - /*--------------------------------------------------------------------------- * Data definitions * ------------------------------------------------------------------------*/ @@ -3670,14 +3667,16 @@ void vos_dump_wdi_events(void) /** * vos_check_arp_target_ip() - check if the Target IP is gateway IP * @pPacket: pointer to vos packet + * @conversion: 802.3 to 802.11 frame conversion * * Return: true if the IP is of gateway or false otherwise */ -bool vos_check_arp_target_ip(vos_pkt_t *pPacket) +bool vos_check_arp_target_ip(void *pSkb, bool conversion) { v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); hdd_context_t *pHddCtx = NULL; struct sk_buff *skb; + uint8_t offset; if(!pVosContext) { @@ -3692,28 +3691,163 @@ bool vos_check_arp_target_ip(vos_pkt_t *pPacket) return false; } - if (unlikely(NULL == pPacket)) + if (unlikely(NULL == pSkb)) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%s: NULL pointer", __func__); return false; } - if ( VOS_STATUS_SUCCESS != - vos_pkt_get_os_packet(pPacket, (void**)&skb, VOS_FALSE )) + skb = (struct sk_buff *)pSkb; + + if (conversion) + offset = VOS_ARP_TARGET_IP_OFFSET + VOS_80211_8023_HEADER_OFFSET; + else + offset = VOS_ARP_TARGET_IP_OFFSET; + + if (pHddCtx->track_arp_ip == + (v_U32_t)(*(v_U32_t *)(skb->data + offset))) + return true; + + return false; +} + +/** + * vos_check_arp_req_target_ip() - check if the ARP is request and + target IP is gateway + * @pPacket: pointer to vos packet + * @conversion: 802.3 to 802.11 frame conversion + * + * Return: true if the IP is of gateway or false otherwise + */ +bool vos_check_arp_req_target_ip(void *pSkb, bool conversion) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + struct sk_buff *skb; + uint8_t offset; + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return false; + } + + if (unlikely(NULL == pSkb)) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, - "%s: OS PKT pointer is NULL", __func__); + "%s: NULL pointer", __func__); return false; } + skb = (struct sk_buff *)pSkb; + + if (conversion) + offset = VOS_PKT_ARP_OPCODE_OFFSET + VOS_80211_8023_HEADER_OFFSET; + else + offset = VOS_PKT_ARP_OPCODE_OFFSET; + + if (htons(VOS_PKT_ARPOP_REQUEST) == + (uint16_t)(*(uint16_t *)(skb->data + offset))) + { + if (vos_check_arp_target_ip(skb, conversion)) + return true; + } + + return false; +} + +/** + * vos_check_arp_src_ip() - check if the ARP response src IP is gateway IP + * @pPacket: pointer to vos packet + * @conversion: 802.3 to 802.11 frame conversion + * + * Return: true if the IP is of gateway or false otherwise + */ +bool vos_check_arp_src_ip(void *pSkb, bool conversion) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + hdd_context_t *pHddCtx = NULL; + struct sk_buff *skb; + uint8_t offset; + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return false; + } + + pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext ); + if(!pHddCtx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return false; + } + + if (unlikely(NULL == pSkb)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: NULL pointer", __func__); + return false; + } + + skb = (struct sk_buff *)pSkb; + + if (conversion) + offset = VOS_ARP_SRC_IP_OFFSET + VOS_80211_8023_HEADER_OFFSET; + else + offset = VOS_ARP_SRC_IP_OFFSET; + if (pHddCtx->track_arp_ip == - (v_U32_t)(*(v_U32_t *)(skb->data + VOS_ARP_TARGET_IP_OFFSET))) + (v_U32_t)(*(v_U32_t *)(skb->data + offset))) return true; return false; } +/** + * vos_check_arp_rsp_src_ip() - check if the ARP is request and + target IP is gateway + * @pPacket: pointer to vos packet + * @conversion: 802.3 to 802.11 frame conversion + * + * Return: true if the IP is of gateway or false otherwise + */ +bool vos_check_arp_rsp_src_ip(void *pSkb, bool conversion) +{ + v_CONTEXT_t pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + struct sk_buff *skb; + uint8_t offset; + + if(!pVosContext) + { + hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__); + return false; + } + + if (unlikely(NULL == pSkb)) + { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + "%s: NULL pointer", __func__); + return false; + } + + skb = (struct sk_buff *)pSkb; + + if (conversion) + offset = VOS_PKT_ARP_OPCODE_OFFSET + VOS_80211_8023_HEADER_OFFSET; + else + offset = VOS_PKT_ARP_OPCODE_OFFSET; + + if (htons(VOS_PKT_ARPOP_REPLY) == + (uint16_t)(*(uint16_t *)(skb->data + offset))) + { + if (vos_check_arp_src_ip(skb, conversion)) + return true; + } + + return false; +} + /** * vos_update_arp_fw_tx_delivered() - update the ARP stats host to FW deliver * count diff --git a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c index a6019cbdbbf5..ee70505da23f 100644 --- a/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c +++ b/drivers/staging/prima/CORE/WDI/WPAL/src/wlan_qct_pal_api.c @@ -546,7 +546,13 @@ bool wpalIsArpPkt(void *pPacket) { vos_pkt_t *pkt = (vos_pkt_t*)pPacket; - return vos_is_arp_pkt(pkt->pSkb, true); + if (vos_is_arp_pkt(pkt->pSkb, true)) + { + if (vos_check_arp_req_target_ip(pkt->pSkb, true)) + return true; + } + + return false; } void wpalUpdateTXArpFWdeliveredStats(void) From 79d5878d81deb1e52503ac53291808842ed2ca1d Mon Sep 17 00:00:00 2001 From: Amey Telawane Date: Mon, 1 Aug 2016 16:50:43 +0530 Subject: [PATCH 246/281] trace: resolve stack corruption due to string copy Strcpy has no limit on string being copied which causes stack corruption leading to kernel panic. Use strlcpy to resolve the issue by providing length of string to be copied. CRs-fixed: 1048480 Change-Id: Ib290b25f7e0ff96927b8530e5c078869441d409f Signed-off-by: Amey Telawane --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 92e7c9cf46b0..4abe90eade6d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1472,7 +1472,7 @@ void trace_find_cmdline(int pid, char comm[]) arch_spin_lock(&trace_cmdline_lock); map = map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) - strcpy(comm, saved_cmdlines[map]); + strlcpy(comm, saved_cmdlines[map], TASK_COMM_LEN-1); else strcpy(comm, "<...>"); From a7513058f28ad6e3a21ddf3b057ff6b7e1cfa2c5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Sep 2016 10:01:23 -0700 Subject: [PATCH 247/281] perf: Tighten (and fix) the grouping condition The fix from 9fc81d87420d ("perf: Fix events installation during moving group") was incomplete in that it failed to recognise that creating a group with events for different CPUs is semantically broken -- they cannot be co-scheduled. Furthermore, it leads to real breakage where, when we create an event for CPU Y and then migrate it to form a group on CPU X, the code gets confused where the counter is programmed -- triggered in practice as well by me via the perf fuzzer. Fix this by tightening the rules for creating groups. Only allow grouping of counters that can be co-scheduled in the same context. This means for the same task and/or the same cpu. Change-Id: I01d7b24b44fff039e72c80cca7f70158fa354470 Fixes: 9fc81d87420d ("perf: Fix events installation during moving group") Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20150123125834.090683288@infradead.org Signed-off-by: Ingo Molnar Signed-off-by: Kamal Mostafa Git-commit: c3c87e770458aa004bd7ed3f29945ff436fd6511 Git-repo: http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git Signed-off-by: Patrick Fay --- include/linux/perf_event.h | 6 ------ kernel/events/core.c | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index dbd9755aac19..189007cac528 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -439,11 +439,6 @@ struct perf_event { #endif /* CONFIG_PERF_EVENTS */ }; -enum perf_event_context_type { - task_context, - cpu_context, -}; - /** * struct perf_event_context - event context structure * @@ -451,7 +446,6 @@ enum perf_event_context_type { */ struct perf_event_context { struct pmu *pmu; - enum perf_event_context_type type; /* * Protect the states of the events in the list, * nr_active, and the list: diff --git a/kernel/events/core.c b/kernel/events/core.c index 677f7b5478f0..7d948d3b0519 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6384,7 +6384,6 @@ int perf_pmu_register(struct pmu *pmu, char *name, int type) __perf_event_init_context(&cpuctx->ctx); lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); - cpuctx->ctx.type = cpu_context; cpuctx->ctx.pmu = pmu; cpuctx->jiffies_interval = 1; INIT_LIST_HEAD(&cpuctx->rotation_list); @@ -7048,7 +7047,19 @@ SYSCALL_DEFINE5(perf_event_open, * task or CPU context: */ if (move_group) { - if (group_leader->ctx->type != ctx->type) + /* + * Make sure we're both on the same task, or both + * per-cpu events. + */ + if (group_leader->ctx->task != ctx->task) + goto err_context; + + /* + * Make sure we're both events for the same CPU; + * grouping events for different CPUs is broken; since + * you can never concurrently schedule them anyhow. + */ + if (group_leader->cpu != event->cpu) goto err_context; } else { if (group_leader->ctx != ctx) From 71be8f75ef580fc2b9503689eac971135d9ae4a9 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Mon, 23 Jan 2017 13:15:58 -0800 Subject: [PATCH 248/281] ASoC: msm: qdsp6v2: completely deallocate on cal block creation failure Completely deallocate the cal block if creation fails to ensure no memory leaks are present. CRs-Fixed: 1112751 Change-Id: I76916c8b3f7e8e9b864dc39dab96f7d330774473 Signed-off-by: Siena Richard --- sound/soc/msm/qdsp6v2/audio_cal_utils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c index 3c4a70bb7427..d1b0dffa98c6 100644 --- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c +++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c @@ -535,7 +535,6 @@ static struct cal_block_data *create_cal_block(struct cal_type_data *cal_type, } INIT_LIST_HEAD(&cal_block->list); - list_add_tail(&cal_block->list, &cal_type->cal_blocks); cal_block->map_data.ion_map_handle = basic_cal->cal_data.mem_handle; if (basic_cal->cal_data.mem_handle > 0) { @@ -567,6 +566,7 @@ static struct cal_block_data *create_cal_block(struct cal_type_data *cal_type, goto err; } cal_block->buffer_number = basic_cal->cal_hdr.buffer_number; + list_add_tail(&cal_block->list, &cal_type->cal_blocks); pr_debug("%s: created block for cal type %d, buf num %d, map handle %d, map size %zd paddr 0x%pK!\n", __func__, cal_type->info.reg.cal_type, cal_block->buffer_number, @@ -576,6 +576,8 @@ static struct cal_block_data *create_cal_block(struct cal_type_data *cal_type, done: return cal_block; err: + kfree(cal_block->cal_info); + kfree(cal_block->client_info); kfree(cal_block); cal_block = NULL; return cal_block; From 432c213fa22401a4fd529634fdacf3d99ca3fe09 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Thu, 26 Jan 2017 15:02:42 -0800 Subject: [PATCH 249/281] drivers: soc: add mutex to prevent response being processed twice Add a mutex to prevent two threads from processing the same response at the same time. This ensures responses are processed completely and sequentially. CRs-Fixed: 1116015 Change-Id: Id2ef32edb939f8af2850b54bd6f6f447939c0732 Signed-off-by: Siena Richard --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 977d2c6dc190..4ffaad6547e6 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,6 +42,12 @@ struct voice_svc_prvt { struct list_head response_queue; wait_queue_head_t response_wait; spinlock_t response_lock; + /* + * This mutex ensures responses are processed in sequential order and + * that no two threads access and free the same response at the same + * time. + */ + struct mutex response_mutex_lock; }; struct apr_data { @@ -460,6 +466,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, goto done; } + mutex_lock(&prtd->response_mutex_lock); spin_lock_irqsave(&prtd->response_lock, spin_flags); if (list_empty(&prtd->response_queue)) { @@ -473,7 +480,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, pr_debug("%s: Read timeout\n", __func__); ret = -ETIMEDOUT; - goto done; + goto unlock; } else if (ret > 0 && !list_empty(&prtd->response_queue)) { pr_debug("%s: Interrupt recieved for response\n", __func__); @@ -481,7 +488,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, pr_debug("%s: Interrupted by SIGNAL %d\n", __func__, ret); - goto done; + goto unlock; } spin_lock_irqsave(&prtd->response_lock, spin_flags); @@ -500,7 +507,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, __func__, count, size); ret = -ENOMEM; - goto done; + goto unlock; } if (!access_ok(VERIFY_WRITE, arg, size)) { @@ -508,7 +515,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, __func__); ret = -EPERM; - goto done; + goto unlock; } ret = copy_to_user(arg, &resp->resp, @@ -518,7 +525,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, pr_err("%s: copy_to_user failed %d\n", __func__, ret); ret = -EPERM; - goto done; + goto unlock; } spin_lock_irqsave(&prtd->response_lock, spin_flags); @@ -532,6 +539,8 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg, ret = count; +unlock: + mutex_unlock(&prtd->response_mutex_lock); done: return ret; } @@ -587,6 +596,7 @@ static int voice_svc_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&prtd->response_queue); init_waitqueue_head(&prtd->response_wait); spin_lock_init(&prtd->response_lock); + mutex_init(&prtd->response_mutex_lock); file->private_data = (void *)prtd; /* Current APR implementation doesn't support session based @@ -637,6 +647,7 @@ static int voice_svc_release(struct inode *inode, struct file *file) pr_err("%s: Failed to dereg MVM %d\n", __func__, ret); } + mutex_lock(&prtd->response_mutex_lock); spin_lock_irqsave(&prtd->response_lock, spin_flags); while (!list_empty(&prtd->response_queue)) { @@ -650,6 +661,9 @@ static int voice_svc_release(struct inode *inode, struct file *file) } spin_unlock_irqrestore(&prtd->response_lock, spin_flags); + mutex_unlock(&prtd->response_mutex_lock); + + mutex_destroy(&prtd->response_mutex_lock); kfree(file->private_data); file->private_data = NULL; From 47472109e384111bfb649f88fb5709d3d43c61f7 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Mon, 5 Dec 2016 12:26:52 -0800 Subject: [PATCH 250/281] ASoC: msm: qdsp6v2: return error when copy from userspace fails A copy_from_user is not always expected to succeed. Therefore, check for an error before operating on the buffer post copy. Change-Id: Ibba9a47c84e735d30e32eeac5b80d51044b7a9e8 CRs-Fixed: 1094852 Signed-off-by: Siena Richard --- sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c index 0a513b6e2c42..e1d9476aee0c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c @@ -819,6 +819,11 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, (sizeof(buf_node->frame.frm_hdr) + sizeof(buf_node->frame.pktlen)); } + if (ret) { + pr_err("%s: copy from user failed %d\n", + __func__, ret); + return -EFAULT; + } spin_lock_irqsave(&prtd->dsp_lock, dsp_flags); list_add_tail(&buf_node->list, &prtd->in_queue); spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags); From da638cc248f0d692a89e26f788c43d6f641c81ef Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Fri, 4 Nov 2016 14:35:58 +0800 Subject: [PATCH 251/281] ASoC: soc: prevent risk of buffer overflow In case of large value for bufcnt_t or bufcnt, cmd_size may overflow. Buffer size allocated by cmd_size might be not as expected. Possible buffer overflow could happen. CRs-Fixed: 1084210 Change-Id: I9556f18dd6a9fdf3f76c133ae75c04ecce171f08 Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/q6asm.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 31bd1d7f5657..11a94e423c4a 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -4054,7 +4054,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, struct asm_buffer_node *buffer_node = NULL; int rc = 0; int i = 0; - int cmd_size = 0; + uint32_t cmd_size = 0; uint32_t bufcnt_t; uint32_t bufsz_t; @@ -4076,10 +4076,25 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, bufsz_t = PAGE_ALIGN(bufsz_t); } + if (bufcnt_t > (UINT_MAX + - sizeof(struct avs_cmd_shared_mem_map_regions)) + / sizeof(struct avs_shared_map_region_payload)) { + pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n", + __func__, bufcnt_t); + return -EINVAL; + } + cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) + (sizeof(struct avs_shared_map_region_payload) * bufcnt_t); + + if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) { + pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n", + __func__, bufcnt); + return -EINVAL; + } + buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt, GFP_KERNEL); if (!buffer_node) { From e34966bfc1770f48e7cdf89b59e62795111cc81b Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Tue, 31 Jan 2017 12:07:10 -0800 Subject: [PATCH 252/281] crypto: msm: check length before copying to buf in _debug_stats_read Make sure that `len` is not larger than `count` before copying data to userspace `buf` in _debug_stats_read(). Change-Id: Iafb7cfa3828653f8c28183c812797c3d9a183da1 Signed-off-by: Zhen Kong --- drivers/crypto/msm/ota_crypto.c | 6 +++--- drivers/crypto/msm/qcedev.c | 4 ++-- drivers/crypto/msm/qcrypto.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c index 9fc548d73e60..80e810dbeb64 100644 --- a/drivers/crypto/msm/ota_crypto.c +++ b/drivers/crypto/msm/ota_crypto.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -880,8 +880,8 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf, int len; len = _disp_stats(); - - rc = simple_read_from_buffer((void __user *) buf, len, + if (len <= count) + rc = simple_read_from_buffer((void __user *) buf, len, ppos, (void *) _debug_read_buf, len); return rc; diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 1941594101f2..5dcae6117114 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -2076,9 +2076,9 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf, len = _disp_stats(qcedev); - rc = simple_read_from_buffer((void __user *) buf, len, + if (len <= count) + rc = simple_read_from_buffer((void __user *) buf, len, ppos, (void *) _debug_read_buf, len); - return rc; } diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c index 778e79212202..6f0f9fad95e8 100644 --- a/drivers/crypto/msm/qcrypto.c +++ b/drivers/crypto/msm/qcrypto.c @@ -1,6 +1,6 @@ /* Qualcomm Crypto driver * - * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -5036,9 +5036,9 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf, len = _disp_stats(qcrypto); - rc = simple_read_from_buffer((void __user *) buf, len, + if (len <= count) + rc = simple_read_from_buffer((void __user *) buf, len, ppos, (void *) _debug_read_buf, len); - return rc; } From f77a75ba663d591b15e0f56abe07f12d4a84032b Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 3 Feb 2017 13:24:19 +0530 Subject: [PATCH 253/281] uio: fix potential use after free issue when accessing debug_buffer The variable debug_buffer is a global variable which is allocated and free'd when open/close is called on debugfs file - "/sys/kernel/debug/rmt_storage/info". The current code doesn't have locks to handle concurrent accesses to the above file. This results into use after free issue when debug_buffer is accessed by two threads at the same time. Fix this by adding a mutex lock to protect this global variable. Change-Id: I6bc3f0ae2d7fca3ca9fe8561612f5863b6c3268a Signed-off-by: Sahitya Tummala --- drivers/uio/msm_sharedmem/sharedmem_qmi.c | 26 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/uio/msm_sharedmem/sharedmem_qmi.c b/drivers/uio/msm_sharedmem/sharedmem_qmi.c index 018c37aa8042..25b3fd183e3f 100644 --- a/drivers/uio/msm_sharedmem/sharedmem_qmi.c +++ b/drivers/uio/msm_sharedmem/sharedmem_qmi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -221,12 +221,17 @@ static int sharedmem_qmi_req_cb(struct qmi_handle *handle, void *conn_h, #define DEBUG_BUF_SIZE (2048) static char *debug_buffer; static u32 debug_data_size; +static struct mutex dbg_buf_lock; /* mutex for debug_buffer */ static ssize_t debug_read(struct file *file, char __user *buf, size_t count, loff_t *file_pos) { - return simple_read_from_buffer(buf, count, file_pos, debug_buffer, - debug_data_size); + size_t ret; + mutex_lock(&dbg_buf_lock); + ret = simple_read_from_buffer(buf, count, file_pos, + debug_buffer, debug_data_size); + mutex_unlock(&dbg_buf_lock); + return ret; } static u32 fill_debug_info(char *buffer, u32 buffer_size) @@ -276,21 +281,30 @@ static u32 fill_debug_info(char *buffer, u32 buffer_size) static int debug_open(struct inode *inode, struct file *file) { u32 buffer_size; - if (debug_buffer != NULL) + + mutex_lock(&dbg_buf_lock); + if (debug_buffer != NULL) { + mutex_unlock(&dbg_buf_lock); return -EBUSY; + } buffer_size = DEBUG_BUF_SIZE; debug_buffer = kzalloc(buffer_size, GFP_KERNEL); - if (debug_buffer == NULL) + if (debug_buffer == NULL) { + mutex_unlock(&dbg_buf_lock); return -ENOMEM; + } debug_data_size = fill_debug_info(debug_buffer, buffer_size); + mutex_unlock(&dbg_buf_lock); return 0; } static int debug_close(struct inode *inode, struct file *file) { + mutex_lock(&dbg_buf_lock); kfree(debug_buffer); debug_buffer = NULL; debug_data_size = 0; + mutex_unlock(&dbg_buf_lock); return 0; } @@ -321,6 +335,7 @@ static void debugfs_init(void) { struct dentry *f_ent; + mutex_init(&dbg_buf_lock); dir_ent = debugfs_create_dir("rmt_storage", NULL); if (IS_ERR(dir_ent)) { pr_err("Failed to create debug_fs directory"); @@ -349,6 +364,7 @@ static void debugfs_init(void) static void debugfs_exit(void) { debugfs_remove_recursive(dir_ent); + mutex_destroy(&dbg_buf_lock); } static void sharedmem_qmi_svc_recv_msg(struct work_struct *work) From 2167e26a75179405bdf64d7648e2f1c9834035cd Mon Sep 17 00:00:00 2001 From: Sathish Ambley Date: Wed, 25 Jan 2017 10:51:55 -0800 Subject: [PATCH 254/281] msm: ADSPRPC: Check for buffer overflow condition The buffer length that is being passed could result in overflow condition causing invalid memory to be accessed. Change-Id: I3e23f31b8cb61f8e77d09a39fab4a2d4c222cf25 Signed-off-by: Sathish Ambley --- drivers/char/adsprpc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 9999ff5cd838..3c6573136a87 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -464,6 +464,11 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx) for (i = 0; i < nbufs; ++i) { ctx->overs[i].start = (uintptr_t)pra[i].buf.pv; ctx->overs[i].end = ctx->overs[i].start + pra[i].buf.len; + if (pra[i].buf.len) { + VERIFY(err, ctx->overs[i].end > ctx->overs[i].start); + if (err) + goto bail; + } ctx->overs[i].raix = i; ctx->overps[i] = &ctx->overs[i]; } From 39ee5158f7927561204159083aafb58ab9a55974 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Wed, 11 Jan 2017 12:12:31 -0800 Subject: [PATCH 255/281] qseecom: improve input validatation for qseecom_send_service_cmd Make change to improve input validation on request and response buffers' address and length for qseecom_send_service_cmd. Change-Id: I047e3264333d767541e43b7dadd1727232fd48ef Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 152 ++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 64 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 339cef6ab1f0..d1c40e67ceb0 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,6 @@ /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1596,11 +1596,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) { - pr_err("Invalid req/resp buffer, exiting\n"); - return -EINVAL; - } - /* Clients need to ensure req_buf is at base offset of shared buffer */ if ((uintptr_t)req_ptr->cmd_req_buf != data_ptr->client.user_virt_sb_base) { @@ -1608,15 +1603,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if (((uintptr_t)req_ptr->resp_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->resp_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))){ - pr_err("response buffer address not within shared bufffer\n"); + if (data_ptr->client.sb_length < + sizeof(struct qseecom_rpmb_provision_key)) { + pr_err("shared buffer is too small to hold key type\n"); return -EINVAL; } - req_buf = data_ptr->client.sb_virt; send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id; @@ -1643,36 +1634,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if (((uintptr_t)req_ptr->cmd_req_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->cmd_req_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))) { - pr_err("cmd buffer address not within shared bufffer\n"); - return -EINVAL; - } - - if (((uintptr_t)req_ptr->resp_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->resp_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))){ - pr_err("response buffer address not within shared bufffer\n"); - return -EINVAL; - } - - if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) || - req_ptr->cmd_req_len > data_ptr->client.sb_length || - req_ptr->resp_len > data_ptr->client.sb_length) { - pr_err("cmd buffer length or response buffer length not valid\n"); - return -EINVAL; - } - - if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) { - pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n"); - return -EINVAL; - } - reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len; if (reqd_len_sb_in > data_ptr->client.sb_length) { pr_err("Not enough memory to fit cmd_buf and resp_buf. "); @@ -1694,28 +1655,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr, return ret; } -static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, - void __user *argp) +static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data, + struct qseecom_send_svc_cmd_req *req) { - int ret = 0; - struct qseecom_client_send_service_ireq send_svc_ireq; - struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq; - struct qseecom_command_scm_resp resp; - struct qseecom_send_svc_cmd_req req; - void *send_req_ptr; - size_t req_buf_size; - - /*struct qseecom_command_scm_resp resp;*/ - - if (copy_from_user(&req, - (void __user *)argp, - sizeof(req))) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - - if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) { - pr_err("cmd buffer or response buffer is null\n"); + if (!req || !req->resp_buf || !req->cmd_req_buf) { + pr_err("req or cmd buffer or response buffer is null\n"); return -EINVAL; } @@ -1739,6 +1683,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } + if (((uintptr_t)req->cmd_req_buf < + data->client.user_virt_sb_base) || + ((uintptr_t)req->cmd_req_buf >= + (data->client.user_virt_sb_base + data->client.sb_length))) { + pr_err("cmd buffer address not within shared bufffer\n"); + return -EINVAL; + } + if (((uintptr_t)req->resp_buf < + data->client.user_virt_sb_base) || + ((uintptr_t)req->resp_buf >= + (data->client.user_virt_sb_base + data->client.sb_length))) { + pr_err("response buffer address not within shared bufffer\n"); + return -EINVAL; + } + if ((req->cmd_req_len == 0) || (req->resp_len == 0) || + (req->cmd_req_len > data->client.sb_length) || + (req->resp_len > data->client.sb_length)) { + pr_err("cmd buf length or response buf length not valid\n"); + return -EINVAL; + } + if (req->cmd_req_len > UINT_MAX - req->resp_len) { + pr_err("Integer overflow detected in req_len & rsp_len\n"); + return -EINVAL; + } + + if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) { + pr_debug("Not enough memory to fit cmd_buf.\n"); + pr_debug("resp_buf. Required: %u, Available: %zu\n", + (req->cmd_req_len + req->resp_len), + data->client.sb_length); + return -ENOMEM; + } + if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) { + pr_err("Integer overflow in req_len & cmd_req_buf\n"); + return -EINVAL; + } + if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) { + pr_err("Integer overflow in resp_len & resp_buf\n"); + return -EINVAL; + } + if (data->client.user_virt_sb_base > + (ULONG_MAX - data->client.sb_length)) { + pr_err("Integer overflow in user_virt_sb_base & sb_length\n"); + return -EINVAL; + } + if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) > + ((uintptr_t)data->client.user_virt_sb_base + + data->client.sb_length)) || + (((uintptr_t)req->resp_buf + req->resp_len) > + ((uintptr_t)data->client.user_virt_sb_base + + data->client.sb_length))) { + pr_err("cmd buf or resp buf is out of shared buffer region\n"); + return -EINVAL; + } + return 0; +} + +static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, + void __user *argp) +{ + int ret = 0; + struct qseecom_client_send_service_ireq send_svc_ireq; + struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq; + struct qseecom_command_scm_resp resp; + struct qseecom_send_svc_cmd_req req; + void *send_req_ptr; + size_t req_buf_size; + + /*struct qseecom_command_scm_resp resp;*/ + + if (copy_from_user(&req, + (void __user *)argp, + sizeof(req))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + if (__validate_send_service_cmd_inputs(data, &req)) + return -EINVAL; + data->type = QSEECOM_SECURE_SERVICE; switch (req.cmd_id) { From ab7aa707fa7e225945ebde90d92fd1523cadb654 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Tue, 25 Oct 2016 16:35:23 -0700 Subject: [PATCH 256/281] soc: qcom: scm: add check to avoid buffer overflow There is a posibility of a buffer overflow in scm_call, adding check to avoid the same. Change-Id: Iee908c56ec530569b35dafa060139e0428efc781 Signed-off-by: Satya Durga Srinivasu Prabhala --- drivers/soc/qcom/scm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index c5a6cc8602d1..9cf324623493 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -46,9 +46,16 @@ static DEFINE_MUTEX(scm_lock); #define SMC_ATOMIC_MASK 0x80000000 #define IS_CALL_AVAIL_CMD 1 -#define SCM_BUF_LEN(__cmd_size, __resp_size) \ - (sizeof(struct scm_command) + sizeof(struct scm_response) + \ - __cmd_size + __resp_size) +#define SCM_BUF_LEN(__cmd_size, __resp_size) ({ \ + size_t x = __cmd_size + __resp_size; \ + size_t y = sizeof(struct scm_command) + sizeof(struct scm_response); \ + size_t result; \ + if (x < __cmd_size || (x + y) < x) \ + result = 0; \ + else \ + result = x + y; \ + result; \ + }) /** * struct scm_command - one SCM command buffer * @len: total available memory for command and response @@ -345,8 +352,7 @@ int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf, int ret; size_t len = SCM_BUF_LEN(cmd_len, resp_len); - if (cmd_len > scm_buf_len || resp_len > scm_buf_len || - len > scm_buf_len) + if (len == 0) return -EINVAL; if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE)) @@ -742,7 +748,7 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, int ret; size_t len = SCM_BUF_LEN(cmd_len, resp_len); - if (cmd_len > len || resp_len > len) + if (len == 0 || PAGE_ALIGN(len) < len) return -EINVAL; cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); From 47917515ad042886485ad3ea65d4a3ee297e3575 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 4 Dec 2014 19:17:17 +0900 Subject: [PATCH 257/281] regulator: core: Fix regualtor_ena_gpio_free not to access pin after freeing After freeing pin from regulator_ena_gpio_free, loop can access the pin. So this patch fixes not to access pin after freeing. Change-Id: Ibffe7b69608a2a662548f7ffbaf73726760ceba4 Signed-off-by: Seung-Woo Kim Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 040c5dcdbff4..e4753f0fceee 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1566,6 +1566,8 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) gpio_free(pin->gpio); list_del(&pin->list); kfree(pin); + rdev->ena_pin = NULL; + return; } else { pin->request_count--; } From 436ebaa4925f951b54a7caa2f41a8de9056fe84c Mon Sep 17 00:00:00 2001 From: Rajesh Bondugula Date: Mon, 4 May 2015 12:05:20 -0700 Subject: [PATCH 258/281] msm: camera: sensor: Fix the improper pointer dereference Pass flash_ctrl to msm_torch_create_classdev instead of &flash_ctrl. This change will fix the improper pointer dereference issue. msm_torch_create_classdev needs flash_ctrl pointer to retrieve torch informaiton. Change-Id: I05bf130b2161336e93122d7e918a4c48a6b381e2 Signed-off-by: Rajesh Bondugula --- drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index bbf4a2de98f7..d1eeae50a47f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -1017,7 +1017,7 @@ static int32_t msm_flash_platform_probe(struct platform_device *pdev) flash_ctrl->msm_sd.sd.devnode->fops = &msm_flash_v4l2_subdev_fops; if (flash_ctrl->flash_driver_type == FLASH_DRIVER_PMIC) - rc = msm_torch_create_classdev(pdev, &flash_ctrl); + rc = msm_torch_create_classdev(pdev, flash_ctrl); CDBG("probe success\n"); return rc; From 1b34cc25dddbf9bf42b0051c9efdd83807306c81 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Tue, 3 Jan 2017 12:11:18 +0200 Subject: [PATCH 259/281] msm: rndis_ipa: Remove rndis_ipa loopback functionality Rndis_ipa loopback functionality at rndis_ipa driver is a debug functionality that is not used. Change-Id: Ibbcb26d3871cffeb46b028efcf4d428e88eb9e10 CRs-fixed: 1104431 Signed-off-by: Ghanim Fodi --- drivers/net/ethernet/msm/rndis_ipa.c | 432 +-------------------------- 1 file changed, 1 insertion(+), 431 deletions(-) diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c index 623e5fb8e711..0050d7e7d3ba 100644 --- a/drivers/net/ethernet/msm/rndis_ipa.c +++ b/drivers/net/ethernet/msm/rndis_ipa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -132,29 +132,6 @@ enum rndis_ipa_operation { RNDIS_IPA_DEBUG("Driver state: %s\n",\ rndis_ipa_state_string(ctx->state)); -/** - * struct rndis_loopback_pipe - hold all information needed for - * pipe loopback logic - */ -struct rndis_loopback_pipe { - struct sps_pipe *ipa_sps; - struct ipa_sps_params ipa_sps_connect; - struct ipa_connect_params ipa_connect_params; - - struct sps_pipe *dma_sps; - struct sps_connect dma_connect; - - struct sps_alloc_dma_chan dst_alloc; - struct sps_dma_chan ipa_sps_channel; - enum sps_mode mode; - u32 ipa_peer_bam_hdl; - u32 peer_pipe_index; - u32 ipa_drv_ep_hdl; - u32 ipa_pipe_index; - enum ipa_client_type ipa_client; - ipa_notify_cb ipa_callback; - struct ipa_ep_cfg *ipa_ep_cfg; -}; /** * struct rndis_ipa_dev - main driver context parameters @@ -169,13 +146,9 @@ struct rndis_loopback_pipe { * @rx_dump_enable: dump all Rx packets * @icmp_filter: allow all ICMP packet to pass through the filters * @rm_enable: flag that enable/disable Resource manager request prior to Tx - * @loopback_enable: flag that enable/disable USB stub loopback * @deaggregation_enable: enable/disable IPA HW deaggregation logic * @during_xmit_error: flags that indicate that the driver is in a middle * of error handling in Tx path - * @usb_to_ipa_loopback_pipe: usb to ipa (Rx) pipe representation for loopback - * @ipa_to_usb_loopback_pipe: ipa to usb (Tx) pipe representation for loopback - * @bam_dma_hdl: handle representing bam-dma, used for loopback logic * @directory: holds all debug flags used by the driver to allow cleanup * for driver unload * @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table @@ -205,12 +178,8 @@ struct rndis_ipa_dev { u32 rx_dump_enable; u32 icmp_filter; u32 rm_enable; - bool loopback_enable; u32 deaggregation_enable; u32 during_xmit_error; - struct rndis_loopback_pipe usb_to_ipa_loopback_pipe; - struct rndis_loopback_pipe ipa_to_usb_loopback_pipe; - u32 bam_dma_hdl; struct dentry *directory; uint32_t eth_ipv4_hdr_hdl; uint32_t eth_ipv6_hdr_hdl; @@ -274,31 +243,12 @@ static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx); static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx); static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb, struct net_device *net); -static int rndis_ipa_loopback_pipe_create( - struct rndis_ipa_dev *rndis_ipa_ctx, - struct rndis_loopback_pipe *loopback_pipe); -static void rndis_ipa_destroy_loopback_pipe( - struct rndis_loopback_pipe *loopback_pipe); -static int rndis_ipa_create_loopback(struct rndis_ipa_dev *rndis_ipa_ctx); -static void rndis_ipa_destroy_loopback(struct rndis_ipa_dev *rndis_ipa_ctx); -static int rndis_ipa_setup_loopback(bool enable, - struct rndis_ipa_dev *rndis_ipa_ctx); -static int rndis_ipa_debugfs_loopback_open(struct inode *inode, - struct file *file); static int rndis_ipa_debugfs_atomic_open(struct inode *inode, struct file *file); static int rndis_ipa_debugfs_aggr_open(struct inode *inode, struct file *file); static ssize_t rndis_ipa_debugfs_aggr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos); -static ssize_t rndis_ipa_debugfs_loopback_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static ssize_t rndis_ipa_debugfs_enable_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static ssize_t rndis_ipa_debugfs_enable_read(struct file *file, - char __user *ubuf, size_t count, loff_t *ppos); -static ssize_t rndis_ipa_debugfs_loopback_read(struct file *file, - char __user *ubuf, size_t count, loff_t *ppos); static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos); static void rndis_ipa_dump_skb(struct sk_buff *skb); @@ -333,12 +283,6 @@ const struct file_operations rndis_ipa_debugfs_atomic_ops = { .read = rndis_ipa_debugfs_atomic_read, }; -const struct file_operations rndis_ipa_loopback_ops = { - .open = rndis_ipa_debugfs_loopback_open, - .read = rndis_ipa_debugfs_loopback_read, - .write = rndis_ipa_debugfs_loopback_write, -}; - const struct file_operations rndis_ipa_aggr_ops = { .open = rndis_ipa_debugfs_aggr_open, .write = rndis_ipa_debugfs_aggr_write, @@ -2182,14 +2126,6 @@ static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx) goto fail_file; } - file = debugfs_create_file("loopback_enable", flags_read_write, - rndis_ipa_ctx->directory, - rndis_ipa_ctx, &rndis_ipa_loopback_ops); - if (!file) { - RNDIS_IPA_ERROR("could not create outstanding file\n"); - goto fail_file; - } - file = debugfs_create_u8("state", flags_read_only, rndis_ipa_ctx->directory, (u8 *)&rndis_ipa_ctx->state); if (!file) { @@ -2345,59 +2281,6 @@ static ssize_t rndis_ipa_debugfs_aggr_write(struct file *file, return count; } -static int rndis_ipa_debugfs_loopback_open(struct inode *inode, - struct file *file) -{ - struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private; - file->private_data = rndis_ipa_ctx; - - return 0; -} - -static ssize_t rndis_ipa_debugfs_loopback_read(struct file *file, - char __user *ubuf, size_t count, loff_t *ppos) -{ - int cnt; - struct rndis_ipa_dev *rndis_ipa_ctx = file->private_data; - - file->private_data = &rndis_ipa_ctx->loopback_enable; - - cnt = rndis_ipa_debugfs_enable_read(file, - ubuf, count, ppos); - - return cnt; -} - -static ssize_t rndis_ipa_debugfs_loopback_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - int retval; - int cnt; - struct rndis_ipa_dev *rndis_ipa_ctx = file->private_data; - bool old_state = rndis_ipa_ctx->loopback_enable; - - file->private_data = &rndis_ipa_ctx->loopback_enable; - - cnt = rndis_ipa_debugfs_enable_write(file, - buf, count, ppos); - - RNDIS_IPA_DEBUG("loopback_enable was set to:%d->%d\n", - old_state, rndis_ipa_ctx->loopback_enable); - - if (old_state == rndis_ipa_ctx->loopback_enable) { - RNDIS_IPA_ERROR("NOP - same state\n"); - return cnt; - } - - retval = rndis_ipa_setup_loopback( - rndis_ipa_ctx->loopback_enable, - rndis_ipa_ctx); - if (retval) - rndis_ipa_ctx->loopback_enable = old_state; - - return cnt; -} - static int rndis_ipa_debugfs_atomic_open(struct inode *inode, struct file *file) { struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private; @@ -2428,319 +2311,6 @@ static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file, return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes); } -static ssize_t rndis_ipa_debugfs_enable_read(struct file *file, - char __user *ubuf, size_t count, loff_t *ppos) -{ - int nbytes; - int size = 0; - int ret; - loff_t pos; - u8 enable_str[sizeof(char)*3] = {0}; - bool *enable = file->private_data; - pos = *ppos; - nbytes = scnprintf(enable_str, sizeof(enable_str), "%d\n", *enable); - ret = simple_read_from_buffer(ubuf, count, ppos, enable_str, nbytes); - if (ret < 0) { - RNDIS_IPA_ERROR("simple_read_from_buffer problem\n"); - return ret; - } - size += ret; - count -= nbytes; - *ppos = pos + size; - return size; -} - -static ssize_t rndis_ipa_debugfs_enable_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long missing; - char input; - bool *enable = file->private_data; - if (count != sizeof(input) + 1) { - RNDIS_IPA_ERROR("wrong input length(%zd)\n", count); - return -EINVAL; - } - if (!buf) { - RNDIS_IPA_ERROR("Bad argument\n"); - return -EINVAL; - } - missing = copy_from_user(&input, buf, 1); - if (missing) - return -EFAULT; - RNDIS_IPA_DEBUG("input received %c\n", input); - *enable = input - '0'; - RNDIS_IPA_DEBUG("value was set to %d\n", *enable); - return count; -} - -/** - * Connects IPA->BAMDMA - * This shall simulate the path from IPA to USB - * Allowing the driver TX path - */ -static int rndis_ipa_loopback_pipe_create( - struct rndis_ipa_dev *rndis_ipa_ctx, - struct rndis_loopback_pipe *loopback_pipe) -{ - int retval; - - RNDIS_IPA_LOG_ENTRY(); - - /* SPS pipe has two side handshake - * This is the first handshake of IPA->BAMDMA, - * This is the IPA side - */ - loopback_pipe->ipa_connect_params.client = loopback_pipe->ipa_client; - loopback_pipe->ipa_connect_params.client_bam_hdl = - rndis_ipa_ctx->bam_dma_hdl; - loopback_pipe->ipa_connect_params.client_ep_idx = - loopback_pipe->peer_pipe_index; - loopback_pipe->ipa_connect_params.desc_fifo_sz = BAM_DMA_DESC_FIFO_SIZE; - loopback_pipe->ipa_connect_params.data_fifo_sz = BAM_DMA_DATA_FIFO_SIZE; - loopback_pipe->ipa_connect_params.notify = loopback_pipe->ipa_callback; - loopback_pipe->ipa_connect_params.priv = rndis_ipa_ctx; - loopback_pipe->ipa_connect_params.ipa_ep_cfg = - *(loopback_pipe->ipa_ep_cfg); - - /* loopback_pipe->ipa_sps_connect is out param */ - retval = ipa_connect(&loopback_pipe->ipa_connect_params, - &loopback_pipe->ipa_sps_connect, - &loopback_pipe->ipa_drv_ep_hdl); - if (retval) { - RNDIS_IPA_ERROR("ipa_connect() fail (%d)", retval); - return retval; - } - RNDIS_IPA_DEBUG("ipa_connect() succeeded, ipa_drv_ep_hdl=%d", - loopback_pipe->ipa_drv_ep_hdl); - - /* SPS pipe has two side handshake - * This is the second handshake of IPA->BAMDMA, - * This is the BAMDMA side - */ - loopback_pipe->dma_sps = sps_alloc_endpoint(); - if (!loopback_pipe->dma_sps) { - RNDIS_IPA_ERROR("sps_alloc_endpoint() failed "); - retval = -ENOMEM; - goto fail_sps_alloc; - } - - retval = sps_get_config(loopback_pipe->dma_sps, - &loopback_pipe->dma_connect); - if (retval) { - RNDIS_IPA_ERROR("sps_get_config() failed (%d)", retval); - goto fail_get_cfg; - } - - /* Start setting the non IPA ep for SPS driver*/ - loopback_pipe->dma_connect.mode = loopback_pipe->mode; - - /* SPS_MODE_DEST: DMA end point is the dest (consumer) IPA->DMA */ - if (loopback_pipe->mode == SPS_MODE_DEST) { - - loopback_pipe->dma_connect.source = - loopback_pipe->ipa_sps_connect.ipa_bam_hdl; - loopback_pipe->dma_connect.src_pipe_index = - loopback_pipe->ipa_sps_connect.ipa_ep_idx; - loopback_pipe->dma_connect.destination = - rndis_ipa_ctx->bam_dma_hdl; - loopback_pipe->dma_connect.dest_pipe_index = - loopback_pipe->peer_pipe_index; - - /* SPS_MODE_SRC: DMA end point is the source (producer) DMA->IPA */ - } else { - - loopback_pipe->dma_connect.source = - rndis_ipa_ctx->bam_dma_hdl; - loopback_pipe->dma_connect.src_pipe_index = - loopback_pipe->peer_pipe_index; - loopback_pipe->dma_connect.destination = - loopback_pipe->ipa_sps_connect.ipa_bam_hdl; - loopback_pipe->dma_connect.dest_pipe_index = - loopback_pipe->ipa_sps_connect.ipa_ep_idx; - - } - - loopback_pipe->dma_connect.desc = loopback_pipe->ipa_sps_connect.desc; - loopback_pipe->dma_connect.data = loopback_pipe->ipa_sps_connect.data; - loopback_pipe->dma_connect.event_thresh = 0x10; - /* BAM-to-BAM */ - loopback_pipe->dma_connect.options = SPS_O_AUTO_ENABLE; - - RNDIS_IPA_DEBUG("doing sps_connect() with - "); - RNDIS_IPA_DEBUG("src bam_hdl:0x%lx, src_pipe#:%d", - loopback_pipe->dma_connect.source, - loopback_pipe->dma_connect.src_pipe_index); - RNDIS_IPA_DEBUG("dst bam_hdl:0x%lx, dst_pipe#:%d", - loopback_pipe->dma_connect.destination, - loopback_pipe->dma_connect.dest_pipe_index); - - retval = sps_connect(loopback_pipe->dma_sps, - &loopback_pipe->dma_connect); - if (retval) { - RNDIS_IPA_ERROR("sps_connect() fail for BAMDMA side (%d)", - retval); - goto fail_sps_connect; - } - - RNDIS_IPA_LOG_EXIT(); - - return 0; - -fail_sps_connect: -fail_get_cfg: - sps_free_endpoint(loopback_pipe->dma_sps); -fail_sps_alloc: - ipa_disconnect(loopback_pipe->ipa_drv_ep_hdl); - return retval; -} - -static void rndis_ipa_destroy_loopback_pipe( - struct rndis_loopback_pipe *loopback_pipe) -{ - sps_disconnect(loopback_pipe->dma_sps); - sps_free_endpoint(loopback_pipe->dma_sps); -} - -/** - * rndis_ipa_create_loopback() - create a BAM-DMA loopback - * in order to replace the USB core - */ -static int rndis_ipa_create_loopback(struct rndis_ipa_dev *rndis_ipa_ctx) -{ - /* The BAM handle should be use as - * source/destination in the sps_connect() - */ - int retval; - - RNDIS_IPA_LOG_ENTRY(); - - - retval = sps_ctrl_bam_dma_clk(true); - if (retval) { - RNDIS_IPA_ERROR("fail on enabling BAM-DMA clocks"); - return -ENODEV; - } - - /* Get BAM handle instead of USB handle */ - rndis_ipa_ctx->bam_dma_hdl = sps_dma_get_bam_handle(); - if (!rndis_ipa_ctx->bam_dma_hdl) { - RNDIS_IPA_ERROR("sps_dma_get_bam_handle() failed"); - return -ENODEV; - } - RNDIS_IPA_DEBUG("sps_dma_get_bam_handle() succeeded (0x%x)", - rndis_ipa_ctx->bam_dma_hdl); - - /* IPA<-BAMDMA, NetDev Rx path (BAMDMA is the USB stub) */ - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_client = - IPA_CLIENT_USB_PROD; - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.peer_pipe_index = - FROM_USB_TO_IPA_BAMDMA; - /*DMA EP mode*/ - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.mode = SPS_MODE_SRC; - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_ep_cfg = - &usb_to_ipa_ep_cfg_deaggr_en; - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_callback = - rndis_ipa_packet_receive_notify; - RNDIS_IPA_DEBUG("setting up IPA<-BAMDAM pipe (RNDIS_IPA RX path)"); - retval = rndis_ipa_loopback_pipe_create(rndis_ipa_ctx, - &rndis_ipa_ctx->usb_to_ipa_loopback_pipe); - if (retval) { - RNDIS_IPA_ERROR("fail to close IPA->BAMDAM pipe"); - goto fail_to_usb; - } - RNDIS_IPA_DEBUG("IPA->BAMDAM pipe successfully connected (TX path)"); - - /* IPA->BAMDMA, NetDev Tx path (BAMDMA is the USB stub)*/ - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_client = - IPA_CLIENT_USB_CONS; - /*DMA EP mode*/ - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.mode = SPS_MODE_DEST; - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_ep_cfg = &ipa_to_usb_ep_cfg; - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.peer_pipe_index = - FROM_IPA_TO_USB_BAMDMA; - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_callback = - rndis_ipa_tx_complete_notify; - RNDIS_IPA_DEBUG("setting up IPA->BAMDAM pipe (RNDIS_IPA TX path)"); - retval = rndis_ipa_loopback_pipe_create(rndis_ipa_ctx, - &rndis_ipa_ctx->ipa_to_usb_loopback_pipe); - if (retval) { - RNDIS_IPA_ERROR("fail to close IPA<-BAMDAM pipe"); - goto fail_from_usb; - } - RNDIS_IPA_DEBUG("IPA<-BAMDAM pipe successfully connected(RX path)"); - - RNDIS_IPA_LOG_EXIT(); - - return 0; - -fail_from_usb: - rndis_ipa_destroy_loopback_pipe( - &rndis_ipa_ctx->usb_to_ipa_loopback_pipe); -fail_to_usb: - - return retval; -} - -static void rndis_ipa_destroy_loopback(struct rndis_ipa_dev *rndis_ipa_ctx) -{ - rndis_ipa_destroy_loopback_pipe( - &rndis_ipa_ctx->ipa_to_usb_loopback_pipe); - rndis_ipa_destroy_loopback_pipe( - &rndis_ipa_ctx->usb_to_ipa_loopback_pipe); - sps_dma_free_bam_handle(rndis_ipa_ctx->bam_dma_hdl); - if (sps_ctrl_bam_dma_clk(false)) - RNDIS_IPA_ERROR("fail to disable BAM-DMA clocks"); -} - -/** - * rndis_ipa_setup_loopback() - create/destroy a loopback on IPA HW - * (as USB pipes loopback) and notify RNDIS_IPA netdev for pipe connected - * @enable: flag that determines if the loopback should be created or destroyed - * @rndis_ipa_ctx: driver main context - * - * This function is the main loopback logic. - * It shall create/destory the loopback by using BAM-DMA and notify - * the netdev accordingly. - */ -static int rndis_ipa_setup_loopback(bool enable, - struct rndis_ipa_dev *rndis_ipa_ctx) -{ - int retval; - - if (!enable) { - rndis_ipa_destroy_loopback(rndis_ipa_ctx); - RNDIS_IPA_DEBUG("loopback destroy done"); - retval = rndis_ipa_pipe_disconnect_notify(rndis_ipa_ctx); - if (retval) { - RNDIS_IPA_ERROR("connect notify fail"); - return -ENODEV; - } - return 0; - } - - RNDIS_IPA_DEBUG("creating loopback (instead of USB core)"); - retval = rndis_ipa_create_loopback(rndis_ipa_ctx); - RNDIS_IPA_DEBUG("creating loopback- %s", (retval ? "FAIL" : "OK")); - if (retval) { - RNDIS_IPA_ERROR("Fail to connect loopback"); - return -ENODEV; - } - retval = rndis_ipa_pipe_connect_notify( - rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_drv_ep_hdl, - rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_drv_ep_hdl, - BAM_DMA_DATA_FIFO_SIZE, - 15, - BAM_DMA_DATA_FIFO_SIZE - rndis_ipa_ctx->net->mtu, - rndis_ipa_ctx); - if (retval) { - RNDIS_IPA_ERROR("connect notify fail"); - return -ENODEV; - } - - return 0; - -} - static int rndis_ipa_init_module(void) { pr_info("RNDIS_IPA module is loaded."); From 7be3576c6ca3dc1fa836af898e81963716541895 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 22 Mar 2017 07:29:31 +0000 Subject: [PATCH 260/281] xfrm_user: validate XFRM_MSG_NEWAE XFRMA_REPLAY_ESN_VAL replay_window When a new xfrm state is created during an XFRM_MSG_NEWSA call we validate the user supplied replay_esn to ensure that the size is valid and to ensure that the replay_window size is within the allocated buffer. However later it is possible to update this replay_esn via a XFRM_MSG_NEWAE call. There we again validate the size of the supplied buffer matches the existing state and if so inject the contents. We do not at this point check that the replay_window is within the allocated memory. This leads to out-of-bounds reads and writes triggered by netlink packets. This leads to memory corruption and the potential for priviledge escalation. We already attempt to validate the incoming replay information in xfrm_new_ae() via xfrm_replay_verify_len(). This confirms that the user is not trying to change the size of the replay state buffer which includes the replay_esn. It however does not check the replay_window remains within that buffer. Add validation of the contained replay_window. CVE-2017-7184 Signed-off-by: Andy Whitcroft Acked-by: Steffen Klassert Signed-off-by: Linus Torvalds Change-Id: I7c69dd5a6150eded4546eb5ef7f67b816175e52e --- net/xfrm/xfrm_user.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7a70a5a5671a..8b55d42076d2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -393,6 +393,9 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) return -EINVAL; + if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) + return -EINVAL; + return 0; } From a160d046ed4ba7fe93fe7f58c4d434329496d6e6 Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Mon, 19 Dec 2016 18:12:06 +0530 Subject: [PATCH 261/281] msm: crypto: set CLR_CNTXT bit for crypto operations HLOS Crypto driver needs to set CLR_CNTXT bit for operations with legacy software key registers. Change-Id: Iff482f726d106e99a4006f7077a171da3c7ca9c3 Signed-off-by: Zhen Kong Signed-off-by: AnilKumar Chimata --- drivers/crypto/msm/qce50.c | 45 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 5522be9488ec..3d1fb4205fbd 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1264,7 +1264,8 @@ static int _ce_setup_hash_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* issue go to crypto */ if (use_hw_key == false) { - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); } else { QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), @@ -1446,7 +1447,8 @@ static int _ce_setup_aead_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* issue go to crypto */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) @@ -1766,7 +1768,8 @@ static int _ce_setup_cipher_direct(struct qce_device *pce_dev, CRYPTO_CONFIG_REG)); /* issue go to crypto */ if (use_hw_key == false) { - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); } else { QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), @@ -1854,8 +1857,8 @@ static int _ce_f9_setup_direct(struct qce_device *pce_dev, QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase + CRYPTO_CONFIG_REG)); /* write go */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - pce_dev->iobase + CRYPTO_GOPROC_REG); + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) * was completed before issuing a DMA transfer request @@ -1931,8 +1934,8 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev, QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase + CRYPTO_CONFIG_REG)); /* write go */ - QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - pce_dev->iobase + CRYPTO_GOPROC_REG); + QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), pce_dev->iobase + CRYPTO_GOPROC_REG); /* * Ensure previous instructions (setting the GO register) * was completed before issuing a DMA transfer request @@ -3083,8 +3086,8 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3196,8 +3199,8 @@ static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3374,8 +3377,8 @@ static int _setup_auth_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3589,8 +3592,8 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3721,8 +3724,8 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3806,8 +3809,8 @@ static int _setup_f8_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; @@ -3887,8 +3890,8 @@ static int _setup_f9_cmdlistptrs(struct qce_device *pdev, pdev->reg.crypto_cfg_le, NULL); qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG, - ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)), - &pcl_info->go_proc); + ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) | + (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc); pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start; *pvaddr = (unsigned char *) ce_vaddr; From bc8149cc5a544be1d00841d48caaa296cb7bf280 Mon Sep 17 00:00:00 2001 From: VijayaKumar T M Date: Tue, 22 Nov 2016 12:51:12 +0530 Subject: [PATCH 262/281] msm: camera: sensor: Validate i2c_freq_mode in msm_cci_set_clk_param i2c_freq_mode in msm_cci_set_clk_param is populated from userspace. Validate to make sure it has valid values. If a large number is sent from userspace to avoid a buffer over write. CRs-Fixed: 1086833 Change-Id: I237f60dca3e3dbad4e6188bf047cf7ec5163d159 Signed-off-by: Rajesh Bondugula Signed-off-by: VijayaKumar T M --- .../msm/camera_v2/sensor/cci/msm_cci.c | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index 91a4b8240327..47679af5cb4b 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -47,15 +47,21 @@ static struct v4l2_subdev *g_cci_subdev; static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX]; -static void msm_cci_set_clk_param(struct cci_device *cci_dev, +static int32_t msm_cci_set_clk_param(struct cci_device *cci_dev, struct msm_camera_cci_ctrl *c_ctrl) { struct msm_cci_clk_params_t *clk_params = NULL; enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + int32_t rc = 0; + if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { + pr_err("%s:%d Invalid i2c_freq_mode =%d\n", + __func__, __LINE__, i2c_freq_mode); + return -EINVAL; + } if (cci_dev->master_clk_init[master]) - return; + return rc; clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; if (MASTER_0 == master) { @@ -90,7 +96,7 @@ static void msm_cci_set_clk_param(struct cci_device *cci_dev, cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR); } cci_dev->master_clk_init[master] = 1; - return; + return rc; } static void msm_cci_flush_queue(struct cci_device *cci_dev, @@ -755,7 +761,12 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count); master = c_ctrl->cci_info->cci_i2c_master; CDBG("%s:%d master %d\n", __func__, __LINE__, master); - msm_cci_set_clk_param(cci_dev, c_ctrl); + rc = msm_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + pr_err("%s:%d msm_cci_set_clk_parm failed rc = %d\n", + __func__, __LINE__, rc); + return rc; + } if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); /* Set reset pending flag to TRUE */ @@ -843,7 +854,13 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd, } for (i = 0; i < MASTER_MAX; i++) cci_dev->master_clk_init[i] = 0; - msm_cci_set_clk_param(cci_dev, c_ctrl); + rc = msm_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + pr_err("%s:%d msm_cci_set_clk_parm failed rc = %d\n", + __func__, __LINE__, rc); + return rc; + } + msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, cci_dev->base + CCI_IRQ_MASK_0_ADDR); msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, From 8deee17d6d093615a4836d811d226018f579ea56 Mon Sep 17 00:00:00 2001 From: Rajesh Bondugula Date: Tue, 22 Nov 2016 11:04:04 -0800 Subject: [PATCH 263/281] msm: camera: flash: Validate the power setting size Validate the power setting size before copying. If userspace sends a value which is greater than MAX_POWER_CONFIG, then the driver accesses unintended memory. This change will fix the issue. CRs-Fixed: 1093232 Signed-off-by: Rajesh Bondugula Change-Id: Ia49963248a94765baa19695294b197ea6f3bb8e2 --- .../platform/msm/camera_v2/sensor/flash/msm_flash.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index d1eeae50a47f..1b9d31297429 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -239,6 +239,16 @@ static int32_t msm_flash_i2c_init( flash_ctrl->power_info.power_down_setting_size = flash_ctrl->power_setting_array.size_down; + if ((flash_ctrl->power_info.power_setting_size > MAX_POWER_CONFIG) || + (flash_ctrl->power_info.power_down_setting_size > MAX_POWER_CONFIG)) { + pr_err("%s:%d invalid power setting size=%d size_down=%d\n", + __func__, __LINE__, + flash_ctrl->power_info.power_setting_size, + flash_ctrl->power_info.power_down_setting_size); + rc = -EINVAL; + goto msm_flash_i2c_init_fail; + } + rc = msm_camera_power_up(&flash_ctrl->power_info, flash_ctrl->flash_device_type, &flash_ctrl->flash_i2c_client); From a75955a0b05bac5b87ac37a5372234ca3be51afd Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Fri, 16 Dec 2016 16:25:27 +0800 Subject: [PATCH 264/281] ASoC: soc: msm: initialize buffer to prevent kernel data leakage To prevent potential kernel stack data leakage, initialize channel_map[]. CRs-Fixed: 1100878 Change-Id: I7b81cea20485bc7514551672bb54c7fd455049e3 Signed-off-by: Xiaojun Sang --- sound/soc/msm/qdsp6v2/msm-qti-pp-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index efbe95372b00..642c9387e900 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -469,7 +469,7 @@ static int msm_qti_pp_set_auxpcm_lb_vol_mixer(struct snd_kcontrol *kcontrol, static int msm_qti_pp_get_channel_map_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL]; + char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL] = {0}; int i; adm_get_multi_ch_map(channel_map); From 45189a886718437e30b79833569e65745c3418aa Mon Sep 17 00:00:00 2001 From: Aravind Kumar Date: Mon, 11 May 2015 18:19:11 +0530 Subject: [PATCH 265/281] ASoC: msm8x16-wcd: prevent out of bounds access Hardcoding the third argument in strnstr function is resulting in out of bounds access. Set the third argument to sizeof the character string passed as the first argument to prevent out of bounds access. CRs-Fixed: 832915 Change-Id: I61be88701340e271fd866e0e1801722dbe7d63ac Signed-off-by: Aravind Kumar --- sound/soc/codecs/msm8x16-wcd.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 69fad945fac6..e5e00560e37e 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -2525,30 +2525,30 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, micbias2 = (snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN) & 0x80); switch (event) { case SND_SOC_DAPM_PRE_PMU: - if (strnstr(w->name, internal1_text, 30)) { + if (strnstr(w->name, internal1_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80); - } else if (strnstr(w->name, internal2_text, 30)) { + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10); snd_soc_update_bits(codec, w->reg, 0x60, 0x00); - } else if (strnstr(w->name, internal3_text, 30)) { + } else if (strnstr(w->name, internal3_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2); } - if (!strnstr(w->name, external_text, 30)) + if (!strnstr(w->name, external_text, strlen(w->name))) snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN, 0x05, 0x04); break; case SND_SOC_DAPM_POST_PMU: usleep_range(20000, 20100); - if (strnstr(w->name, internal1_text, 30)) { + if (strnstr(w->name, internal1_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x40, 0x40); - } else if (strnstr(w->name, internal2_text, 30)) { + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x08, 0x08); msm8x16_notifier_call(codec, WCD_EVENT_PRE_MICBIAS_2_ON); - } else if (strnstr(w->name, internal3_text, 30)) { + } else if (strnstr(w->name, internal3_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01); - } else if (strnstr(w->name, external2_text, 30)) { + } else if (strnstr(w->name, external2_text, strlen(w->name))) { msm8x16_notifier_call(codec, WCD_EVENT_PRE_MICBIAS_2_ON); } @@ -2556,14 +2556,14 @@ static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w, msm8x16_wcd_configure_cap(codec, true, micbias2); break; case SND_SOC_DAPM_POST_PMD: - if (strnstr(w->name, internal1_text, 30)) { + if (strnstr(w->name, internal1_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0xC0, 0x40); - } else if (strnstr(w->name, internal2_text, 30)) { + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { msm8x16_notifier_call(codec, WCD_EVENT_PRE_MICBIAS_2_OFF); - } else if (strnstr(w->name, internal3_text, 30)) { + } else if (strnstr(w->name, internal3_text, strlen(w->name))) { snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0); - } else if (strnstr(w->name, external2_text, 30)) { + } else if (strnstr(w->name, external2_text, strlen(w->name))) { /* * send micbias turn off event to mbhc driver and then * break, as no need to set MICB_1_EN register. From e9ca7ab3307f1a3843091e0e05185d8f877d942f Mon Sep 17 00:00:00 2001 From: David Keitel Date: Mon, 20 Apr 2015 15:51:33 -0700 Subject: [PATCH 266/281] bcl: fix allocation for BCL attribute The size of the BCL attribute is incorrect due to a precedence bug: This was observed while booting with Kernel Address Sanitizer(KASan) enabled. ============================================================================= BUG kmalloc-64 (Tainted: G B ): kasan: bad access detected ----------------------------------------------------------------------------- INFO: Slab 0xffffffbc0661c6e0 objects=64 used=64 fp=0x (null) flags=0x0080 INFO: Object 0xffffffc0a360bb00 @offset=2816 fp=0xffffffc0a3454728 Bytes b4 ffffffc0a360baf0: 3f 37 9c 1c 00 00 00 00 02 00 02 00 a9 4e ad de ?7...........N.. Object ffffffc0a360bb00: 28 47 45 a3 c0 ff ff ff 48 47 45 a3 c0 ff ff ff (GE.....HGE..... Object ffffffc0a360bb10: 68 47 45 a3 c0 ff ff ff 00 00 00 00 00 00 00 00 hGE............. Object ffffffc0a360bb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Object ffffffc0a360bb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ CPU: 0 PID: 1 Comm: swapper/0 Tainted: G B 3.10.49-g465b172-00133-gb931dc1 #134 Call trace: [] dump_backtrace+0x0/0x1d4 [] show_stack+0x10/0x1c [] dump_stack+0x1c/0x28 [] print_trailer+0x144/0x158 [] object_err+0x38/0x4c [] kasan_report_error+0x210/0x3b0 [] kasan_report+0x68/0x78 [] __asan_load8+0x90/0x9c [] internal_create_group+0x1a0/0x2f4 [] sysfs_create_group+0x10/0x1c [] msm_bcl_register_param+0x384/0x450 [] bcl_probe+0x840/0xb84 [] spmi_drv_probe+0x2c/0x3c [] driver_probe_device+0x1f4/0x47c [] __driver_attach+0x88/0xc0 [] bus_for_each_dev+0xdc/0x11c [] driver_attach+0x2c/0x3c [] bus_add_driver+0x1bc/0x32c [] driver_register+0x10c/0x1d8 [] spmi_driver_register+0x98/0xa8 [] bcl_perph_init+0x2c/0x38 [] do_one_initcall+0xcc/0x188 [] kernel_init_freeable+0x1c0/0x264 [] kernel_init+0x10/0xcc Memory state around the buggy address: ffffffc0a360ba00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffffffc0a360ba80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffffffc0a360bb00: 00 00 00 01 fc fc fc fc fc fc fc fc fc fc fc fc ^ ffffffc0a360bb80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffffffc0a360bc00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ================================================================== Fix this by adding parantheses to fix precedence. CRs-Fixed: 826589 Change-Id: Ia58b6e52c491b89b10a2b8fe45445372bfe9fa20 Signed-off-by: David Keitel --- drivers/power/msm_bcl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/msm_bcl.c b/drivers/power/msm_bcl.c index d36dfd2a2eb3..6b7cefdc0250 100644 --- a/drivers/power/msm_bcl.c +++ b/drivers/power/msm_bcl.c @@ -301,7 +301,7 @@ static int bcl_add_sysfs_nodes(enum bcl_param param_type) return ret; } bcl[param_type]->bcl_attr_gp.attrs = kzalloc(sizeof(struct attribute *) - * BCL_PARAM_MAX_ATTR + 1, GFP_KERNEL); + * (BCL_PARAM_MAX_ATTR + 1), GFP_KERNEL); if (!bcl[param_type]->bcl_attr_gp.attrs) { pr_err("Sysfs attribute create failed.\n"); ret = -ENOMEM; From 60c22667504b79630c7c60ad22b011ee2b4c059d Mon Sep 17 00:00:00 2001 From: Walter Yang Date: Wed, 21 Dec 2016 14:43:46 +0800 Subject: [PATCH 267/281] FROMLIST: ASoC: msm-cpe-lsm: cleanup ioctl functions Some of the ioctl command handling is not properly using the copy_from_user interface. Fix these issues and cleanup the ioctl functions to make sure there is no illegal memory access. Bug: 35399801 CRs-Fixed: 1090482 Change-Id: Ib18e4b132d3487a3103335768aad5df2ebe13f2d Signed-off-by: Walter Yang Signed-off-by: Siqi Lin (am from https://source.codeaurora.org/quic/la//kernel/msm-3.10/commit/?id=07e4006db8b3bf4ada64ec7c87f27df38ea77a81) --- sound/soc/msm/msm-cpe-lsm.c | 47 ++++++++++++------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c index e06d39c94d0e..d3d5e79bc4ae 100644 --- a/sound/soc/msm/msm-cpe-lsm.c +++ b/sound/soc/msm/msm-cpe-lsm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2017 Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -656,13 +656,6 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_dbg(rtd->dev, "%s: %s\n", __func__, "SNDRV_LSM_REG_SND_MODEL_V2"); - if (!arg) { - dev_err(rtd->dev, - "%s: Invalid argument to ioctl %s\n", - __func__, - "SNDRV_LSM_REG_SND_MODEL_V2"); - return -EINVAL; - } memcpy(&snd_model, arg, sizeof(struct snd_lsm_sound_model_v2)); @@ -774,13 +767,6 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_dbg(rtd->dev, "%s: %s\n", __func__, "SNDRV_LSM_EVENT_STATUS"); - if (!arg) { - dev_err(rtd->dev, - "%s: Invalid argument to ioctl %s\n", - __func__, - "SNDRV_LSM_EVENT_STATUS"); - return -EINVAL; - } user = arg; rc = wait_event_interruptible(lsm_d->event_wait, @@ -863,12 +849,6 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, break; case SNDRV_LSM_SET_PARAMS: - if (!arg) { - dev_err(rtd->dev, - "%s: %s Invalid argument\n", - __func__, "SNDRV_LSM_SET_PARAMS"); - return -EINVAL; - } memcpy(&det_params, arg, sizeof(det_params)); if (det_params.num_confidence_levels <= 0) { @@ -1093,12 +1073,6 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream, } #ifdef CONFIG_COMPAT -struct snd_lsm_event_status32 { - u16 status; - u16 payload_size; - u8 payload[0]; -}; - struct snd_lsm_sound_model_v2_32 { compat_uptr_t data; compat_uptr_t confidence_level; @@ -1116,8 +1090,6 @@ struct snd_lsm_detection_params_32 { }; enum { - SNDRV_LSM_EVENT_STATUS32 = - _IOW('U', 0x02, struct snd_lsm_event_status32), SNDRV_LSM_REG_SND_MODEL_V2_32 = _IOW('U', 0x07, struct snd_lsm_sound_model_v2_32), SNDRV_LSM_SET_PARAMS32 = @@ -1200,7 +1172,7 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream, err); } break; - case SNDRV_LSM_EVENT_STATUS32: { + case SNDRV_LSM_EVENT_STATUS: { struct snd_lsm_event_status *event_status = NULL; struct snd_lsm_event_status u_event_status32; struct snd_lsm_event_status *udata_32 = NULL; @@ -1240,7 +1212,6 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream, } else { event_status->payload_size = u_event_status32.payload_size; - cmd = SNDRV_LSM_EVENT_STATUS; err = msm_cpe_lsm_ioctl_shared(substream, cmd, event_status); if (err) @@ -1314,7 +1285,19 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream, break; } - + case SNDRV_LSM_REG_SND_MODEL_V2: + case SNDRV_LSM_SET_PARAMS: + case SNDRV_LSM_SET_MODULE_PARAMS: + /* + * In ideal cases, the compat_ioctl should never be called + * with the above unlocked ioctl commands. Print error + * and return error if it does. + */ + dev_err(rtd->dev, + "%s: Invalid cmd for compat_ioctl\n", + __func__); + err = -EINVAL; + break; default: err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg); break; From 927986a70b4bd8bf63fd92320c14a49146624aa9 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 22 Mar 2016 17:30:58 -0400 Subject: [PATCH 268/281] UPSTREAM: tracing: Fix trace_printk() to print when not using bprintk() The trace_printk() code will allocate extra buffers if the compile detects that a trace_printk() is used. To do this, the format of the trace_printk() is saved to the __trace_printk_fmt section, and if that section is bigger than zero, the buffers are allocated (along with a message that this has happened). If trace_printk() uses a format that is not a constant, and thus something not guaranteed to be around when the print happens, the compiler optimizes the fmt out, as it is not used, and the __trace_printk_fmt section is not filled. This means the kernel will not allocate the special buffers needed for the trace_printk() and the trace_printk() will not write anything to the tracing buffer. Adding a "__used" to the variable in the __trace_printk_fmt section will keep it around, even though it is set to NULL. This will keep the string from being printed in the debugfs/tracing/printk_formats section as it is not needed. Reported-by: Vlastimil Babka Fixes: 07d777fe8c398 "tracing: Add percpu buffers for trace_printk()" Cc: stable@vger.kernel.org # v3.5+ Bug: 34277115 Signed-off-by: Steven Rostedt Change-Id: I10ce56caa41c7644d9d290d9ed272a6d156c938c --- include/linux/kernel.h | 6 +++--- kernel/trace/trace_printk.c | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6d0f8600c727..0228d010f895 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -554,7 +554,7 @@ do { \ #define do_trace_printk(fmt, args...) \ do { \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(fmt) ? fmt : NULL; \ \ @@ -601,7 +601,7 @@ extern int __trace_puts(unsigned long ip, const char *str, int size); */ #define trace_puts(str) ({ \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(str) ? str : NULL; \ \ @@ -621,7 +621,7 @@ extern void trace_dump_stack(int skip); #define ftrace_vprintk(fmt, vargs) \ do { \ if (__builtin_constant_p(fmt)) { \ - static const char *trace_printk_fmt \ + static const char *trace_printk_fmt __used \ __attribute__((section("__trace_printk_fmt"))) = \ __builtin_constant_p(fmt) ? fmt : NULL; \ \ diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index a9077c1b4ad3..fdb23e84b011 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -272,6 +272,9 @@ static int t_show(struct seq_file *m, void *v) const char *str = *fmt; int i; + if (!*fmt) + return 0; + seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); /* From 8635124f6d1546e05fc27640a4e18386426f0a82 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 3 Mar 2017 15:40:12 -0800 Subject: [PATCH 269/281] tracing: do not leak kernel addresses This likely breaks tracing tools like trace-cmd. It logs in the same format but now addresses are all 0x0. Bug: 34277115 Change-Id: Ifb0d4d2a184bf0d95726de05b1acee0287a375d9 --- kernel/trace/trace_printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index fdb23e84b011..f423e8d551c0 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -275,7 +275,7 @@ static int t_show(struct seq_file *m, void *v) if (!*fmt) return 0; - seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); + seq_printf(m, "0x%lx : \"", 0L); /* * Tabs and new lines need to be converted. From b995662ede002ce3d8c3174dd7dc10e19fac3684 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 1 Feb 2017 16:24:01 -0500 Subject: [PATCH 270/281] msm: mdss: Install sync fences after user copy If userspace closes the fd after an error on copying to userspace, the fences may be freed incorrectly. Make sure fences are installed after all checks pass. Bug: 32402303 Change-Id: Ieb50296c87e09549db2734bd70bb6ee8d311ad40 CRs-Fixed: 2000664 Signed-off-by: Naseer Ahmed Signed-off-by: Steve Pfetsch --- drivers/video/msm/mdss/mdss_fb.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 94498dbea740..60113a390a58 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -2,7 +2,7 @@ * Core MDSS framebuffer driver. * * Copyright (C) 2007 Google Incorporated - * Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -3513,8 +3513,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_2; } - sync_fence_install(rel_fence, rel_fen_fd); - ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int)); if (ret) { pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name); @@ -3551,8 +3549,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_3; } - sync_fence_install(retire_fence, retire_fen_fd); - ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd, sizeof(int)); if (ret) { @@ -3563,6 +3559,9 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data, goto buf_sync_err_3; } + sync_fence_install(rel_fence, rel_fen_fd); + sync_fence_install(retire_fence, retire_fen_fd); + skip_retire_fence: mutex_unlock(&sync_pt_data->sync_mutex); From 5f4c010c48a2b4680b369c6c69f63bd48968e03e Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Thu, 23 Mar 2017 07:45:44 +0000 Subject: [PATCH 271/281] xfrm_user: validate XFRM_MSG_NEWAE incoming ESN size harder Kees Cook has pointed out that xfrm_replay_state_esn_len() is subject to wrapping issues. To ensure we are correctly ensuring that the two ESN structures are the same size compare both the overall size as reported by xfrm_replay_state_esn_len() and the internal length are the same. CVE-2017-7184 Signed-off-by: Andy Whitcroft Acked-by: Steffen Klassert Signed-off-by: Linus Torvalds Change-Id: Ieca2af8ac5cc721117a11baa501c3a5fc14ab4b0 --- net/xfrm/xfrm_user.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8b55d42076d2..91a6a2903e8d 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -390,7 +390,11 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es up = nla_data(rp); ulen = xfrm_replay_state_esn_len(up); - if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) + /* Check the overall length and the internal bitmap length to avoid + * potential overflow. */ + if (nla_len(rp) < ulen || + xfrm_replay_state_esn_len(replay_esn) != ulen || + replay_esn->bmp_len != up->bmp_len) return -EINVAL; if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) From cac1b9026b9bbb113d35ecfbab937d4602e9af48 Mon Sep 17 00:00:00 2001 From: Abdulla Anam Date: Wed, 22 Mar 2017 14:00:10 +0530 Subject: [PATCH 272/281] msm: vidc: Protect debug_buffer access in core_info_read with lock. Serialize core_info_read with lock so that multiple concurrent threads do not cause the write to overflow. Also have the bound check to avoid overflow in write_str function. CRs-Fixed: 2013361 Change-Id: Ia18a4b94cafd69af1d367861f2499fc202f18e9f Signed-off-by: Abdulla Anam Signed-off-by: Sanjay Singh --- .../media/platform/msm/vidc/msm_v4l2_vidc.c | 5 ++- .../media/platform/msm/vidc/msm_vidc_debug.c | 37 ++++++++++++++++--- .../media/platform/msm/vidc/msm_vidc_debug.h | 3 +- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 68592e779b8b..a1602f3e54fe 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -737,6 +737,8 @@ static int __init msm_vidc_init(void) if (rc) { dprintk(VIDC_ERR, "Failed to register platform driver\n"); + msm_vidc_debugfs_deinit_drv(); + debugfs_remove_recursive(vidc_driver->debugfs_root); kfree(vidc_driver); vidc_driver = NULL; } @@ -747,6 +749,7 @@ static int __init msm_vidc_init(void) static void __exit msm_vidc_exit(void) { platform_driver_unregister(&msm_vidc_driver); + msm_vidc_debugfs_deinit_drv(); debugfs_remove_recursive(vidc_driver->debugfs_root); kfree(vidc_driver); vidc_driver = NULL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 509ea440cf6e..e66fc8bc7573 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ int msm_vidc_sys_idle_indicator = 0x0; u32 msm_vidc_firmware_unload_delay = 15000; struct debug_buffer { + struct mutex lock; char ptr[MAX_DBG_BUF_SIZE]; char *curr; u32 filled_size; @@ -54,8 +55,12 @@ static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...) { va_list args; u32 size; + + char *curr = buffer->curr; + char *end = buffer->ptr + MAX_DBG_BUF_SIZE; + va_start(args, fmt); - size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args); + size = vscnprintf(curr, end - curr, fmt, args); va_end(args); buffer->curr += size; buffer->filled_size += size; @@ -69,12 +74,15 @@ static ssize_t core_info_read(struct file *file, char __user *buf, struct hfi_device *hdev; struct hal_fw_info fw_info; int i = 0, rc = 0; + ssize_t len = 0; if (!core || !core->device) { dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core); return 0; } hdev = core->device; + + mutex_lock(&dbg_buf.lock); INIT_DBG_BUF(dbg_buf); write_str(&dbg_buf, "===============================\n"); write_str(&dbg_buf, "CORE %d: 0x%pK\n", core->id, core); @@ -98,8 +106,11 @@ static ssize_t core_info_read(struct file *file, char __user *buf, completion_done(&core->completions[SYS_MSG_INDEX(i)]) ? "pending" : "done"); } - return simple_read_from_buffer(buf, count, ppos, + len = simple_read_from_buffer(buf, count, ppos, dbg_buf.ptr, dbg_buf.filled_size); + + mutex_unlock(&dbg_buf.lock); + return len; } static const struct file_operations core_info_fops = { @@ -136,7 +147,10 @@ static const struct file_operations ssr_fops = { struct dentry *msm_vidc_debugfs_init_drv(void) { - struct dentry *dir = debugfs_create_dir("msm_vidc", NULL); + struct dentry *dir = NULL; + + mutex_init(&dbg_buf.lock); + dir = debugfs_create_dir("msm_vidc", NULL); if (IS_ERR_OR_NULL(dir)) { dir = NULL; goto failed_create_dir; @@ -219,6 +233,7 @@ struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); goto failed_create_dir; } + if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) { dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); goto failed_create_dir; @@ -272,10 +287,14 @@ static ssize_t inst_info_read(struct file *file, char __user *buf, { struct msm_vidc_inst *inst = file->private_data; int i, j; + ssize_t len = 0; + if (!inst) { dprintk(VIDC_ERR, "Invalid params, core: %pK\n", inst); return 0; } + + mutex_lock(&dbg_buf.lock); INIT_DBG_BUF(dbg_buf); write_str(&dbg_buf, "===============================\n"); write_str(&dbg_buf, "INSTANCE: 0x%pK (%s)\n", inst, @@ -332,9 +351,10 @@ static ssize_t inst_info_read(struct file *file, char __user *buf, write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd); publish_unreleased_reference(inst); - - return simple_read_from_buffer(buf, count, ppos, + len = simple_read_from_buffer(buf, count, ppos, dbg_buf.ptr, dbg_buf.filled_size); + mutex_unlock(&dbg_buf.lock); + return len; } static const struct file_operations inst_info_fops = { @@ -411,3 +431,8 @@ void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, } } +void msm_vidc_debugfs_deinit_drv(void) +{ + mutex_destroy(&dbg_buf.lock); +} + diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index bd8e3f6dec65..e1a7ab358714 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -121,6 +121,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, struct dentry *parent); void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, enum msm_vidc_debugfs_event e); +void msm_vidc_debugfs_deinit_drv(void); static inline void tic(struct msm_vidc_inst *i, enum profiling_points p, char *b) From 63c7ce7e5ce51c0f9e04d66b00654ee66b117205 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Tue, 28 Feb 2017 12:52:30 -0800 Subject: [PATCH 273/281] drivers: soc: add size check Add size check to ensure the payload fits inside the declared payload size to prevent loss of data when copying. CRs-Fixed: 2009224 Signed-off-by: Siena Richard Change-Id: I4275c626605272941143b54a7b8861b25f8e750a --- drivers/soc/qcom/qdsp6v2/voice_svc.c | 57 +++++++++++++++++++++------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 4ffaad6547e6..d428255f1383 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -361,6 +361,9 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, struct voice_svc_prvt *prtd; struct voice_svc_write_msg *data = NULL; uint32_t cmd; + struct voice_svc_register *register_data = NULL; + struct voice_svc_cmd_request *request_data = NULL; + uint32_t request_payload_size; pr_debug("%s\n", __func__); @@ -409,12 +412,19 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, */ if (count == (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_register))) { - ret = process_reg_cmd( - (struct voice_svc_register *)data->payload, prtd); + register_data = + (struct voice_svc_register *)data->payload; + if (register_data == NULL) { + pr_err("%s: register data is NULL", __func__); + ret = -EINVAL; + goto done; + } + ret = process_reg_cmd(register_data, prtd); if (!ret) ret = count; } else { - pr_err("%s: invalid payload size\n", __func__); + pr_err("%s: invalid data payload size for register command\n", + __func__); ret = -EINVAL; goto done; } @@ -423,19 +433,40 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, /* * Check that count reflects the expected size to ensure * sufficient memory was allocated. Since voice_svc_cmd_request - * has a variable size, check the minimum value count must be. + * has a variable size, check the minimum value count must be to + * parse the message request then check the minimum size to hold + * the payload of the message request. */ if (count >= (sizeof(struct voice_svc_write_msg) + sizeof(struct voice_svc_cmd_request))) { - ret = voice_svc_send_req( - (struct voice_svc_cmd_request *)data->payload, prtd); - if (!ret) - ret = count; - } else { - pr_err("%s: invalid payload size\n", __func__); - ret = -EINVAL; - goto done; - } + request_data = + (struct voice_svc_cmd_request *)data->payload; + if (request_data == NULL) { + pr_err("%s: request data is NULL", __func__); + ret = -EINVAL; + goto done; + } + + request_payload_size = request_data->payload_size; + + if (count >= (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_cmd_request) + + request_payload_size)) { + ret = voice_svc_send_req(request_data, prtd); + if (!ret) + ret = count; + } else { + pr_err("%s: invalid request payload size\n", + __func__); + ret = -EINVAL; + goto done; + } + } else { + pr_err("%s: invalid data payload size for request command\n", + __func__); + ret = -EINVAL; + goto done; + } break; default: pr_debug("%s: Invalid command: %u\n", __func__, cmd); From 86c0630c3f59b21ba9a5bcf499c9c07da81679a0 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Fri, 24 Feb 2017 16:13:20 +0800 Subject: [PATCH 274/281] ASoC : msm: qdsp6v2: set pointer to NULL after free. Pointer after kfree is not sanitized. Set pointer to NULL. CRs-Fixed: 2008031 Change-Id: Ia59a57fcd142a6ed18d168992b8da4019314afa4 Signed-off-by: Xiaojun Sang Signed-off-by: Bikshapathi Kothapeta --- sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 1 + sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c | 3 ++- sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c | 3 ++- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 5 ++++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 42be0f521310..dce018facc65 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -1158,6 +1158,7 @@ static int msm_compr_free(struct snd_compr_stream *cstream) kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]); kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); kfree(prtd); + runtime->private_data = NULL; return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c index 2a0bbcdd99bc..03154fb4fdf9 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -493,6 +493,7 @@ static int msm_afe_close(struct snd_pcm_substream *substream) mutex_unlock(&prtd->lock); prtd->prepared--; kfree(prtd); + runtime->private_data = NULL; return 0; } static int msm_afe_prepare(struct snd_pcm_substream *substream) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c index 3d31e1eea430..e203f69b5252 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -497,6 +497,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) pr_debug("%s\n", __func__); kfree(prtd); + runtime->private_data = NULL; return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 1a7542d83132..0015c642e7b5 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -693,6 +693,8 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); kfree(prtd); + runtime->private_data = NULL; + return 0; } @@ -796,6 +798,7 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream) msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_CAPTURE); kfree(prtd); + runtime->private_data = NULL; return 0; } From df347fe9d9b5c1a4fb3e26e0577768302647dc8e Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 15 Jul 2016 15:08:19 -0400 Subject: [PATCH 275/281] mm: migrate dirty page without clear_page_dirty_for_io etc commit 42cb14b110a5698ccf26ce59c4441722605a3743 upstream. clear_page_dirty_for_io() has accumulated writeback and memcg subtleties since v2.6.16 first introduced page migration; and the set_page_dirty() which completed its migration of PageDirty, later had to be moderated to __set_page_dirty_nobuffers(); then PageSwapBacked had to skip that too. No actual problems seen with this procedure recently, but if you look into what the clear_page_dirty_for_io(page)+set_page_dirty(newpage) is actually achieving, it turns out to be nothing more than moving the PageDirty flag, and its NR_FILE_DIRTY stat from one zone to another. It would be good to avoid a pile of irrelevant decrementations and incrementations, and improper event counting, and unnecessary descent of the radix_tree under tree_lock (to set the PAGECACHE_TAG_DIRTY which radix_tree_replace_slot() left in place anyway). Do the NR_FILE_DIRTY movement, like the other stats movements, while interrupts still disabled in migrate_page_move_mapping(); and don't even bother if the zone is the same. Do the PageDirty movement there under tree_lock too, where old page is frozen and newpage not yet visible: bearing in mind that as soon as newpage becomes visible in radix_tree, an un-page-locked set_page_dirty() might interfere (or perhaps that's just not possible: anything doing so should already hold an additional reference to the old page, preventing its migration; but play safe). But we do still need to transfer PageDirty in migrate_page_copy(), for those who don't go the mapping route through migrate_page_move_mapping(). CVE-2016-3070 Signed-off-by: Hugh Dickins Cc: Christoph Lameter Cc: "Kirill A. Shutemov" Cc: Rik van Riel Cc: Vlastimil Babka Cc: Davidlohr Bueso Cc: Oleg Nesterov Cc: Sasha Levin Cc: Dmitry Vyukov Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [ciwillia@brocade.com: backported to 3.10: adjusted context] Signed-off-by: Charles (Chas) Williams Signed-off-by: Willy Tarreau Change-Id: I95d3cb66fe662ff9c169f51571ebeeda6c2d66c5 --- mm/migrate.c | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/mm/migrate.c b/mm/migrate.c index 9fe247a6df4a..c6e32aa4fccc 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -312,6 +313,8 @@ static int migrate_page_move_mapping(struct address_space *mapping, struct page *newpage, struct page *page, struct buffer_head *head, enum migrate_mode mode) { + struct zone *oldzone, *newzone; + int dirty; int expected_count = 0; void **pslot; @@ -322,6 +325,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, return MIGRATEPAGE_SUCCESS; } + oldzone = page_zone(page); + newzone = page_zone(newpage); + spin_lock_irq(&mapping->tree_lock); pslot = radix_tree_lookup_slot(&mapping->page_tree, @@ -362,6 +368,13 @@ static int migrate_page_move_mapping(struct address_space *mapping, set_page_private(newpage, page_private(page)); } + /* Move dirty while page refs frozen and newpage not yet exposed */ + dirty = PageDirty(page); + if (dirty) { + ClearPageDirty(page); + SetPageDirty(newpage); + } + radix_tree_replace_slot(pslot, newpage); /* @@ -371,6 +384,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, */ page_unfreeze_refs(page, expected_count - 1); + spin_unlock(&mapping->tree_lock); + /* Leave irq disabled to prevent preemption while updating stats */ + /* * If moved to a different zone then also account * the page for that zone. Other VM counters will be @@ -381,13 +397,19 @@ static int migrate_page_move_mapping(struct address_space *mapping, * via NR_FILE_PAGES and NR_ANON_PAGES if they * are mapped to swap space. */ - __dec_zone_page_state(page, NR_FILE_PAGES); - __inc_zone_page_state(newpage, NR_FILE_PAGES); - if (!PageSwapCache(page) && PageSwapBacked(page)) { - __dec_zone_page_state(page, NR_SHMEM); - __inc_zone_page_state(newpage, NR_SHMEM); + if (newzone != oldzone) { + __dec_zone_state(oldzone, NR_FILE_PAGES); + __inc_zone_state(newzone, NR_FILE_PAGES); + if (PageSwapBacked(page) && !PageSwapCache(page)) { + __dec_zone_state(oldzone, NR_SHMEM); + __inc_zone_state(newzone, NR_SHMEM); + } + if (dirty && mapping_cap_account_dirty(mapping)) { + __dec_zone_state(oldzone, NR_FILE_DIRTY); + __inc_zone_state(newzone, NR_FILE_DIRTY); + } } - spin_unlock_irq(&mapping->tree_lock); + local_irq_enable(); return MIGRATEPAGE_SUCCESS; } @@ -461,20 +483,9 @@ void migrate_page_copy(struct page *newpage, struct page *page) if (PageMappedToDisk(page)) SetPageMappedToDisk(newpage); - if (PageDirty(page)) { - clear_page_dirty_for_io(page); - /* - * Want to mark the page and the radix tree as dirty, and - * redo the accounting that clear_page_dirty_for_io undid, - * but we can't use set_page_dirty because that function - * is actually a signal that all of the page has become dirty. - * Whereas only part of our page may be dirty. - */ - if (PageSwapBacked(page)) - SetPageDirty(newpage); - else - __set_page_dirty_nobuffers(newpage); - } + /* Move dirty on pages not done by migrate_page_move_mapping() */ + if (PageDirty(page)) + SetPageDirty(newpage); mlock_migrate_page(newpage, page); ksm_migrate_page(newpage, page); From 70c2df800f50d5f18d69ed91146c4d9d221c9f18 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 18 Apr 2017 15:31:07 +0100 Subject: [PATCH 276/281] KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings commit ee8f844e3c5a73b999edf733df1c529d6503ec2f upstream. This fixes CVE-2016-9604. Keyrings whose name begin with a '.' are special internal keyrings and so userspace isn't allowed to create keyrings by this name to prevent shadowing. However, the patch that added the guard didn't fix KEYCTL_JOIN_SESSION_KEYRING. Not only can that create dot-named keyrings, it can also subscribe to them as a session keyring if they grant SEARCH permission to the user. This, for example, allows a root process to set .builtin_trusted_keys as its session keyring, at which point it has full access because now the possessor permissions are added. This permits root to add extra public keys, thereby bypassing module verification. This also affects kexec and IMA. This can be tested by (as root): keyctl session .builtin_trusted_keys keyctl add user a a @s keyctl list @s which on my test box gives me: 2 keys in keyring: 180010936: ---lswrv 0 0 asymmetric: Build time autogenerated kernel key: ae3d4a31b82daa8e1a75b49dc2bba949fd992a05 801382539: --alswrv 0 0 user: a Fix this by rejecting names beginning with a '.' in the keyctl. Change-Id: I3e2d9907d61eba3b39b97415dc344f8186ebc817 Signed-off-by: David Howells Acked-by: Mimi Zohar cc: linux-ima-devel@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman --- security/keys/keyctl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3242195bfa95..1324b2e10286 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -271,7 +271,8 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) * Create and join an anonymous session keyring or join a named session * keyring, creating it if necessary. A named session keyring must have Search * permission for it to be joined. Session keyrings without this permit will - * be skipped over. + * be skipped over. It is not permitted for userspace to create or join + * keyrings whose name begin with a dot. * * If successful, the ID of the joined session keyring will be returned. */ @@ -288,12 +289,16 @@ long keyctl_join_session_keyring(const char __user *_name) ret = PTR_ERR(name); goto error; } + + ret = -EPERM; + if (name[0] == '.') + goto error_name; } /* join the session */ ret = join_session_keyring(name); +error_name: kfree(name); - error: return ret; } From 228d70aadaff55fb58de7daa41d9bb32cd0f8afb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 18 Apr 2017 15:31:09 +0100 Subject: [PATCH 277/281] KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings commit c9f838d104fed6f2f61d68164712e3204bf5271b upstream. This fixes CVE-2017-7472. Running the following program as an unprivileged user exhausts kernel memory by leaking thread keyrings: #include int main() { for (;;) keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING); } Fix it by only creating a new thread keyring if there wasn't one before. To make things more consistent, make install_thread_keyring_to_cred() and install_process_keyring_to_cred() both return 0 if the corresponding keyring is already present. Change-Id: I1355f6043290f23132d123c37c2c0fb3b5a7f671 Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials") Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman --- security/keys/keyctl.c | 11 ++++----- security/keys/process_keys.c | 44 ++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 1324b2e10286..066baa1926bb 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1245,8 +1245,8 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error, * Read or set the default keyring in which request_key() will cache keys and * return the old setting. * - * If a process keyring is specified then this will be created if it doesn't - * yet exist. The old setting will be returned if successful. + * If a thread or process keyring is specified then it will be created if it + * doesn't yet exist. The old setting will be returned if successful. */ long keyctl_set_reqkey_keyring(int reqkey_defl) { @@ -1271,11 +1271,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) case KEY_REQKEY_DEFL_PROCESS_KEYRING: ret = install_process_keyring_to_cred(new); - if (ret < 0) { - if (ret != -EEXIST) - goto error; - ret = 0; - } + if (ret < 0) + goto error; goto set; case KEY_REQKEY_DEFL_DEFAULT: diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 28380e5ba086..7a5abb2b9d56 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -125,13 +125,18 @@ int install_user_keyrings(void) } /* - * Install a fresh thread keyring directly to new credentials. This keyring is - * allowed to overrun the quota. + * Install a thread keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ int install_thread_keyring_to_cred(struct cred *new) { struct key *keyring; + if (new->thread_keyring) + return 0; + keyring = keyring_alloc("_tid", new->uid, new->gid, new, KEY_POS_ALL | KEY_USR_VIEW, KEY_ALLOC_QUOTA_OVERRUN, NULL); @@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struct cred *new) } /* - * Install a fresh thread keyring, discarding the old one. + * Install a thread keyring to the current task if it didn't have one already. + * + * Return: 0 if a thread keyring is now present; -errno on failure. */ static int install_thread_keyring(void) { @@ -154,8 +161,6 @@ static int install_thread_keyring(void) if (!new) return -ENOMEM; - BUG_ON(new->thread_keyring); - ret = install_thread_keyring_to_cred(new); if (ret < 0) { abort_creds(new); @@ -166,17 +171,17 @@ static int install_thread_keyring(void) } /* - * Install a process keyring directly to a credentials struct. + * Install a process keyring to the given credentials struct if it didn't have + * one already. This is allowed to overrun the quota. * - * Returns -EEXIST if there was already a process keyring, 0 if one installed, - * and other value on any other error + * Return: 0 if a process keyring is now present; -errno on failure. */ int install_process_keyring_to_cred(struct cred *new) { struct key *keyring; if (new->process_keyring) - return -EEXIST; + return 0; keyring = keyring_alloc("_pid", new->uid, new->gid, new, KEY_POS_ALL | KEY_USR_VIEW, @@ -189,11 +194,9 @@ int install_process_keyring_to_cred(struct cred *new) } /* - * Make sure a process keyring is installed for the current process. The - * existing process keyring is not replaced. + * Install a process keyring to the current task if it didn't have one already. * - * Returns 0 if there is a process keyring by the end of this function, some - * error otherwise. + * Return: 0 if a process keyring is now present; -errno on failure. */ static int install_process_keyring(void) { @@ -207,14 +210,18 @@ static int install_process_keyring(void) ret = install_process_keyring_to_cred(new); if (ret < 0) { abort_creds(new); - return ret != -EEXIST ? ret : 0; + return ret; } return commit_creds(new); } /* - * Install a session keyring directly to a credentials struct. + * Install the given keyring as the session keyring of the given credentials + * struct, replacing the existing one if any. If the given keyring is NULL, + * then install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) { @@ -249,8 +256,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) } /* - * Install a session keyring, discarding the old one. If a keyring is not - * supplied, an empty one is invented. + * Install the given keyring as the session keyring of the current task, + * replacing the existing one if any. If the given keyring is NULL, then + * install a new anonymous session keyring. + * + * Return: 0 on success; -errno on failure. */ static int install_session_keyring(struct key *keyring) { From 13ae260e3ffd4fd9d8df5b0a19e500f8204c05ea Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 18 Apr 2017 15:31:08 +0100 Subject: [PATCH 278/281] KEYS: Change the name of the dead type to ".dead" to prevent user access commit c1644fe041ebaf6519f6809146a77c3ead9193af upstream. This fixes CVE-2017-6951. Userspace should not be able to do things with the "dead" key type as it doesn't have some of the helper functions set upon it that the kernel needs. Attempting to use it may cause the kernel to crash. Fix this by changing the name of the type to ".dead" so that it's rejected up front on userspace syscalls by key_get_type_from_user(). Though this doesn't seem to affect recent kernels, it does affect older ones, certainly those prior to: commit c06cfb08b88dfbe13be44a69ae2fdc3a7c902d81 Author: David Howells Date: Tue Sep 16 17:36:06 2014 +0100 KEYS: Remove key_type::match in favour of overriding default by match_preparse which went in before 3.18-rc1. Change-Id: I724617d072ec6e84e23b3bf93b55f8d2b3ad792a Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman --- security/keys/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/keys/gc.c b/security/keys/gc.c index de34c290bd6f..2e01e23295aa 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -46,7 +46,7 @@ static unsigned long key_gc_flags; * immediately unlinked. */ struct key_type key_type_dead = { - .name = "dead", + .name = ".dead", }; /* From 841b65741be90969dfa5bb72f113b19be6c3e760 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 6 Jun 2014 07:57:37 -0600 Subject: [PATCH 279/281] BACKPORT: block: add blk_rq_set_block_pc() With the optimizations around not clearing the full request at alloc time, we are leaving some of the needed init for REQ_TYPE_BLOCK_PC up to the user allocating the request. Add a blk_rq_set_block_pc() that sets the command type to REQ_TYPE_BLOCK_PC, and properly initializes the members associated with this type of request. Update callers to use this function instead of manipulating rq->cmd_type directly. Includes fixes from Christoph Hellwig for my half-assed attempt. Change-Id: Ifc386dfb951c5d6adebf48ff38135dda28e4b1ce Signed-off-by: Jens Axboe --- block/blk-core.c | 18 ++++++++++++++++++ block/bsg.c | 3 ++- block/scsi_ioctl.c | 6 +++--- drivers/block/pktcdvd.c | 2 +- drivers/cdrom/cdrom.c | 2 +- drivers/scsi/device_handler/scsi_dh_alua.c | 2 +- drivers/scsi/device_handler/scsi_dh_emc.c | 2 +- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 ++-- drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +- drivers/scsi/osd/osd_initiator.c | 4 ++-- drivers/scsi/osst.c | 2 +- drivers/scsi/scsi_error.c | 3 ++- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/sg.c | 3 +-- drivers/scsi/st.c | 2 +- drivers/target/target_core_pscsi.c | 3 ++- include/linux/blkdev.h | 1 + 17 files changed, 41 insertions(+), 20 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index a155d5992f19..702f5255f27f 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1189,6 +1189,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio, if (unlikely(!rq)) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(rq); + for_each_bio(bio) { struct bio *bounce_bio = bio; int ret; @@ -1205,6 +1207,22 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio, } EXPORT_SYMBOL(blk_make_request); +/** + * blk_rq_set_block_pc - initialize a requeest to type BLOCK_PC + * @rq: request to be initialized + * + */ +void blk_rq_set_block_pc(struct request *rq) +{ + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->__data_len = 0; + rq->__sector = (sector_t) -1; + rq->bio = rq->biotail = NULL; + memset(rq->__cmd, 0, sizeof(rq->__cmd)); + rq->cmd = rq->__cmd; +} +EXPORT_SYMBOL(blk_rq_set_block_pc); + /** * blk_requeue_request - put a request back on queue * @q: request queue where request should be inserted diff --git a/block/bsg.c b/block/bsg.c index 76801e57f556..0ed26bce6655 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -196,7 +196,6 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, * fill in request structure */ rq->cmd_len = hdr->request_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = msecs_to_jiffies(hdr->timeout); if (!rq->timeout) @@ -273,6 +272,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, rq = blk_get_request(q, rw, GFP_KERNEL); if (!rq) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(rq); + ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm); if (ret) goto out; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index a5ffcc988f0b..7979cdf859db 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -233,7 +233,6 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, * fill in request structure */ rq->cmd_len = hdr->cmd_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = msecs_to_jiffies(hdr->timeout); if (!rq->timeout) @@ -314,6 +313,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; + blk_rq_set_block_pc(rq); if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { blk_put_request(rq); @@ -512,7 +512,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; - rq->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(rq); blk_execute_rq(q, disk, rq, 0); @@ -545,7 +545,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); - rq->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index f5d0ea11d9fd..caddb5dba3e0 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -712,6 +712,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, __GFP_WAIT); + blk_rq_set_block_pc(rq); if (cgc->buflen) { if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT)) @@ -722,7 +723,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); rq->timeout = 60*HZ; - rq->cmd_type = REQ_TYPE_BLOCK_PC; if (cgc->quiet) rq->cmd_flags |= REQ_QUIET; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 8a3aff724d98..1ca0772c713f 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2165,6 +2165,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ret = -ENOMEM; break; } + blk_rq_set_block_pc(rq); ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL); if (ret) { @@ -2184,7 +2185,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->cmd[9] = 0xf8; rq->cmd_len = 12; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = 60 * HZ; bio = rq->bio; diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 68adb8955d2d..28bf7fb7e175 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -120,6 +120,7 @@ static struct request *get_alua_req(struct scsi_device *sdev, "%s: blk_get_request failed\n", __func__); return NULL; } + blk_rq_set_block_pc(rq); if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { blk_put_request(rq); @@ -128,7 +129,6 @@ static struct request *get_alua_req(struct scsi_device *sdev, return NULL; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->retries = ALUA_FAILOVER_RETRIES; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index e1c8be06de9d..6f07f7fe3aa1 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -280,6 +280,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, return NULL; } + blk_rq_set_block_pc(rq); rq->cmd_len = COMMAND_SIZE(cmd); rq->cmd[0] = cmd; @@ -304,7 +305,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, break; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->timeout = CLARIION_TIMEOUT; diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 084062bb8ee9..e9d9fea9e272 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -120,7 +120,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) if (!req) return SCSI_DH_RES_TEMP_UNAVAIL; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); @@ -250,7 +250,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h) if (!req) return SCSI_DH_RES_TEMP_UNAVAIL; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(START_STOP); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 69c915aa77c2..3916c31aaae5 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -279,6 +279,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev, "get_rdac_req: blk_get_request failed.\n"); return NULL; } + blk_rq_set_block_pc(rq); if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { blk_put_request(rq); @@ -287,7 +288,6 @@ static struct request *get_rdac_req(struct scsi_device *sdev, return NULL; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->retries = RDAC_RETRIES; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index aa66361ed44b..11bd87eaf01c 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1570,6 +1570,7 @@ static struct request *_make_request(struct request_queue *q, bool has_write, if (unlikely(!req)) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(req); return req; } } @@ -1590,7 +1591,6 @@ static int _init_blk_request(struct osd_request *or, } or->request = req; - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= REQ_QUIET; req->timeout = or->timeout; @@ -1608,7 +1608,7 @@ static int _init_blk_request(struct osd_request *or, ret = PTR_ERR(req); goto out; } - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); or->in.req = or->request->next_rq = req; } } else if (has_in) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 21883a2d6324..0727ea7cc387 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -365,7 +365,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, if (!req) return DRIVER_ERROR << 24; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_QUIET; SRpnt->bio = NULL; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f43de1e56420..0d76aa13cb43 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1653,6 +1653,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); + blk_rq_set_block_pc(req); + req->cmd[0] = ALLOW_MEDIUM_REMOVAL; req->cmd[1] = 0; req->cmd[2] = 0; @@ -1662,7 +1664,6 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) req->cmd_len = COMMAND_SIZE(req->cmd[0]); - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= REQ_QUIET; req->timeout = 10 * HZ; req->retries = 5; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 86d522004a20..8dc8309bc099 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -238,6 +238,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); if (!req) return ret; + blk_rq_set_block_pc(req); if (bufflen && blk_rq_map_kern(sdev->request_queue, req, buffer, bufflen, __GFP_WAIT)) @@ -249,7 +250,6 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req->sense_len = 0; req->retries = retries; req->timeout = timeout; - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT; /* diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7668c9cd4155..6fcbe53eb06c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1661,10 +1661,9 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) if (!rq) return -ENOMEM; + blk_rq_set_block_pc(rq); memcpy(rq->cmd, cmd, hp->cmd_len); - rq->cmd_len = hp->cmd_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; srp->rq = rq; rq->end_io_data = srp; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 2a32036a9404..7d74f838c241 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -484,7 +484,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, if (!req) return DRIVER_ERROR << 24; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_QUIET; mdata->null_mapped = 1; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 3250ba2594e0..0f5a96cb7d9f 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1056,6 +1056,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto fail; } + + blk_rq_set_block_pc(req); } else { BUG_ON(!cmd->data_length); @@ -1072,7 +1074,6 @@ pscsi_execute_cmd(struct se_cmd *cmd) } } - req->cmd_type = REQ_TYPE_BLOCK_PC; req->end_io = pscsi_req_done; req->end_io_data = cmd; req->cmd_len = scsi_command_size(pt->pscsi_cdb); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a3160b537eab..8df215996cd7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -742,6 +742,7 @@ extern void __blk_put_request(struct request_queue *, struct request *); extern struct request *blk_get_request(struct request_queue *, int, gfp_t); extern struct request *blk_make_request(struct request_queue *, struct bio *, gfp_t); +extern void blk_rq_set_block_pc(struct request *); extern void blk_requeue_request(struct request_queue *, struct request *); extern int blk_reinsert_request(struct request_queue *q, struct request *rq); extern bool blk_reinsert_req_sup(struct request_queue *q); From 8941f7cd906d2af1fe72417f3fce94268fc30bdd Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Tue, 3 Jun 2014 13:18:18 -0400 Subject: [PATCH 280/281] BACKPORT: sg: relax 16 byte cdb restriction - remove the 16 byte CDB (SCSI command) length limit from the sg driver by handling longer CDBs the same way as the bsg driver. Remove comment from sg.h public interface about the cmd_len field being limited to 16 bytes. - remove some dead code caused by this change - cleanup comment block at the top of sg.h, fix urls Change-Id: Ie8150e5375b3316d5d5206f079c4a50f1c50b755 Signed-off-by: Douglas Gilbert Reviewed-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig --- drivers/scsi/sg.c | 46 +++++++++++++-------- include/uapi/scsi/sg.h | 91 +++++++++++------------------------------- 2 files changed, 53 insertions(+), 84 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6fcbe53eb06c..7adde6c8d68c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -7,9 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2005 Douglas Gilbert - * - * Modified 19-JAN-1998 Richard Gooch Devfs support + * Copyright (C) 1998 - 2014 Douglas Gilbert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,11 +16,11 @@ * */ -static int sg_version_num = 30534; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.34" +static int sg_version_num = 30536; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.36" /* - * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: + * D. P. Gilbert (dgilbert@interlog.com), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * the kernel/module needs to be built with CONFIG_SCSI_LOGGING * (otherwise the macros compile to empty statements). @@ -64,7 +62,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20061027"; +static char *sg_version_date = "20140603"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -74,6 +72,12 @@ static void sg_proc_cleanup(void); #define SG_MAX_DEVS 32768 +/* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type + * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater + * than 16 bytes are "variable length" whose length is a multiple of 4 + */ +#define SG_MAX_CDB_SIZE 252 + /* * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d) * Then when using 32 bit integers x * m may overflow during the calculation. @@ -161,7 +165,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ - char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ + unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ char mmap_called; /* 0 -> mmap() never called on this fd */ struct kref f_ref; @@ -566,7 +570,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) Sg_request *srp; struct sg_header old_hdr; sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned char cmnd[SG_MAX_CDB_SIZE]; if (unlikely(segment_eq(get_fs(), KERNEL_DS))) return -EINVAL; @@ -601,12 +605,6 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) buf += SZ_SG_HEADER; __get_user(opcode, buf); if (sfp->next_cmd_len > 0) { - if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); - sfp->next_cmd_len = 0; - sg_remove_request(sfp, srp); - return -EIO; - } cmd_size = sfp->next_cmd_len; sfp->next_cmd_len = 0; /* reset so only this write() effected */ } else { @@ -678,7 +676,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, int k; Sg_request *srp; sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned char cmnd[SG_MAX_CDB_SIZE]; int timeout; unsigned long ul_timeout; @@ -1653,15 +1651,27 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) struct request_queue *q = sfp->parentdp->device->request_queue; struct rq_map_data *md, map_data; int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ; + unsigned char *long_cmdp = NULL; SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n", dxfer_len)); + if (hp->cmd_len > BLK_MAX_CDB) { + long_cmdp = kzalloc(hp->cmd_len, GFP_KERNEL); + if (!long_cmdp) + return -ENOMEM; + } + rq = blk_get_request(q, rw, GFP_ATOMIC); - if (!rq) + if (!rq) { + kfree(long_cmdp); return -ENOMEM; + } blk_rq_set_block_pc(rq); + + if (hp->cmd_len > BLK_MAX_CDB) + rq->cmd = long_cmdp; memcpy(rq->cmd, cmd, hp->cmd_len); rq->cmd_len = hp->cmd_len; @@ -1749,6 +1759,8 @@ static int sg_finish_rem_req(Sg_request * srp) if (srp->bio) ret = blk_rq_unmap_user(srp->bio); + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); blk_put_request(srp->rq); } diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h index a9f3c6fc3f57..d8c0c4307fca 100644 --- a/include/uapi/scsi/sg.h +++ b/include/uapi/scsi/sg.h @@ -4,77 +4,34 @@ #include /* - History: - Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - process control of SCSI devices. - Development Sponsored by Killy Corp. NY NY -Original driver (sg.h): -* Copyright (C) 1992 Lawrence Foard -Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2006 Douglas Gilbert - - Version: 3.5.34 (20060920) - This version is for 2.6 series kernels. - - For a full changelog see http://www.torque.net/sg - -Map of SG verions to the Linux kernels in which they appear: - ---------- ---------------------------------- - original all kernels < 2.2.6 - 2.1.40 2.2.20 - 3.0.x optional version 3 sg driver for 2.2 series - 3.1.17++ 2.4.0++ - 3.5.30++ 2.6.0++ - -Major new features in SG 3.x driver (cf SG 2.x drivers) - - SG_IO ioctl() combines function if write() and read() - - new interface (sg_io_hdr_t) but still supports old interface - - scatter/gather in user space, direct IO, and mmap supported - - The normal action of this driver is to use the adapter (HBA) driver to DMA - data into kernel buffers and then use the CPU to copy the data into the - user space (vice versa for writes). That is called "indirect" IO due to - the double handling of data. There are two methods offered to remove the - redundant copy: 1) direct IO and 2) using the mmap() system call to map - the reserve buffer (this driver has one reserve buffer per fd) into the - user space. Both have their advantages. - In terms of absolute speed mmap() is faster. If speed is not a concern, - indirect IO should be fine. Read the documentation for more information. - - ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or - 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed. - That attribute is 0 by default. ** - - Historical note: this SCSI pass-through driver has been known as "sg" for - a decade. In broader kernel discussions "sg" is used to refer to scatter - gather techniques. The context should clarify which "sg" is referred to. - - Documentation - ============= - A web site for the SG device driver can be found at: - http://www.torque.net/sg [alternatively check the MAINTAINERS file] - The documentation for the sg version 3 driver can be found at: - http://www.torque.net/sg/p/sg_v3_ho.html - This is a rendering from DocBook source [change the extension to "sgml" - or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). - The SG_IO ioctl is now found in other parts kernel (e.g. the block layer). - For more information see http://www.torque.net/sg/sg_io.html - - The older, version 2 documents discuss the original sg interface in detail: - http://www.torque.net/sg/p/scsi-generic.txt - http://www.torque.net/sg/p/scsi-generic_long.txt - Also available: /Documentation/scsi/scsi-generic.txt - - Utility and test programs are available at the sg web site. They are - packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils - (for the lk 2.2 series). -*/ + * History: + * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user + * process control of SCSI devices. + * Development Sponsored by Killy Corp. NY NY + * + * Original driver (sg.h): + * Copyright (C) 1992 Lawrence Foard + * Version 2 and 3 extensions to driver: + * Copyright (C) 1998 - 2014 Douglas Gilbert + * + * Version: 3.5.36 (20140603) + * This version is for 2.6 and 3 series kernels. + * + * Documentation + * ============= + * A web site for the SG device driver can be found at: + * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file] + * The documentation for the sg version 3 driver can be found at: + * http://sg.danny.cz/sg/p/sg_v3_ho.html + * Also see: /Documentation/scsi/scsi-generic.txt + * + * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html + */ #ifdef __KERNEL__ extern int sg_big_buff; /* for sysctl */ #endif -/* New interface introduced in the 3.x SG drivers follows */ typedef struct sg_iovec /* same structure as used by readv() Linux system */ { /* call. It defines one scatter-gather element. */ @@ -87,7 +44,7 @@ typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ - unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char cmd_len; /* [i] SCSI command length */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ From b1a7db1b595e33a0ea7eaec59ed4476225fcb0f3 Mon Sep 17 00:00:00 2001 From: peter chang Date: Wed, 15 Feb 2017 14:11:54 -0800 Subject: [PATCH 281/281] scsi: sg: check length passed to SG_NEXT_CMD_LEN The user can control the size of the next command passed along, but the value passed to the ioctl isn't checked against the usable max command size. Change-Id: I9e8eb8ca058c0103a22f5d99d77919432893aa4c Cc: Signed-off-by: Peter Chang Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7adde6c8d68c..6a052e98e112 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -983,6 +983,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; + if (val > SG_MAX_CDB_SIZE) + return -ENOMEM; sfp->next_cmd_len = (val > 0) ? val : 0; return 0; case SG_GET_VERSION_NUM: