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/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) 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/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>; diff --git a/arch/arm/configs/harpia_defconfig b/arch/arm/configs/harpia_defconfig index 72b7cf0f407e..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" @@ -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 @@ -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 5568e24ae81d..6ee36e64f230 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 @@ -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 @@ -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 a455c9f3767a..31b011df4976 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 @@ -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 @@ -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 9e4bc5138d51..6b65d90df4e1 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 @@ -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 @@ -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 b97be818bdf6..b4b6ad95f2c7 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 @@ -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 @@ -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 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 { 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 420a5a9f1b23..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; @@ -675,6 +676,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/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/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/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"); 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/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]; } 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/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; } diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 9e5afc724df1..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; @@ -4481,6 +4484,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) { diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 09914b971138..5dcae6117114 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)) @@ -1487,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) { @@ -1522,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__); @@ -1549,36 +1534,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 +1630,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 +1643,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 +1663,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 +1675,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 +1698,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 +1718,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 +1732,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 +1741,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 +1760,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; } @@ -2133,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; } 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..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 @@ -1370,16 +1369,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; } @@ -2585,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); @@ -2902,7 +2906,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; @@ -3936,7 +3941,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; } @@ -4810,6 +4816,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 +4879,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..2839dee3c287 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; }; @@ -397,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); } /* 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; } 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)); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 45d20ac3ae37..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; @@ -627,6 +634,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) { 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; 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/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); 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..0b87bece2db7 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; @@ -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: 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..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; @@ -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 b76ee2d01f44..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 @@ -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); @@ -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; } @@ -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), @@ -1802,8 +1809,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 +1827,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"); @@ -1848,12 +1861,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 +1889,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; } @@ -1890,16 +1903,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 +1943,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: { @@ -2076,8 +2124,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; } @@ -2368,14 +2415,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; @@ -2587,7 +2634,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..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; @@ -1466,7 +1473,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 +1720,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..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, @@ -467,7 +473,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 +752,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; @@ -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, @@ -1330,7 +1347,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 +1359,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 +1424,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..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__); @@ -188,7 +195,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 +990,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/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index bbf4a2de98f7..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); @@ -1017,7 +1027,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; 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); 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.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/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) 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; } 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, 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++) { diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index e4264c3270f4..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 @@ -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: @@ -1587,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) { @@ -1599,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; @@ -1634,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. "); @@ -1685,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; } @@ -1730,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) { @@ -2318,7 +2351,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 +2377,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 +2401,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 +2420,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 +2440,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 +2527,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 +2620,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; 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."); diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index 0a5aece5ab68..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 @@ -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,19 @@ 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); + 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; + } + + 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"); 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; 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--; } 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 8d92436820dc..6a052e98e112 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,10 @@ 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; if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; @@ -598,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 { @@ -675,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; @@ -982,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: @@ -1650,18 +1653,29 @@ 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; + } - memcpy(rq->cmd, cmd, hp->cmd_len); + 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; - rq->cmd_type = REQ_TYPE_BLOCK_PC; srp->rq = rq; rq->end_io_data = srp; @@ -1699,6 +1713,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; @@ -1744,6 +1761,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/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/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index bbc2550e8629..d428255f1383 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 { @@ -216,8 +222,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 +337,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; } @@ -355,10 +361,23 @@ 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__); - 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 +395,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,31 +405,68 @@ 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))) { - ret = process_reg_cmd( - (struct voice_svc_register *)data->payload, prtd); + /* + * 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))) { + 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; } break; case MSG_REQUEST: - if (count >= (sizeof(struct voice_svc_cmd_request) + - sizeof(*data))) { - 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; - } + /* + * 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 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))) { + 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); @@ -441,6 +497,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)) { @@ -454,7 +511,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__); @@ -462,7 +519,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); @@ -481,7 +538,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)) { @@ -489,7 +546,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, @@ -499,7 +556,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); @@ -513,6 +570,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; } @@ -568,6 +627,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 @@ -618,6 +678,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)) { @@ -631,6 +692,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; diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 938d3bfe6016..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)) @@ -640,10 +646,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 +665,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); @@ -748,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); 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; } diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c old mode 100755 new mode 100644 index 6ac8661e1233..f8161016d137 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -16,6 +16,8 @@ * */ +#include +#include #include #include #include @@ -111,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; @@ -406,6 +409,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; @@ -427,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) { @@ -451,9 +505,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, @@ -506,9 +560,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 +663,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 +674,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) @@ -634,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); @@ -1360,7 +1442,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; } @@ -1450,13 +1532,13 @@ 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); - + pass_to_user(handle); data.allocation.handle = handle->id; cleanup_handle = handle; @@ -1472,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; @@ -1495,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: @@ -1529,11 +1616,17 @@ 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); + if (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; } } + if (cleanup_handle) + ion_handle_put(cleanup_handle); return ret; } 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, 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; 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/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_cfg.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_cfg.h index 5a51247fbc65..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. * @@ -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 @@ -2025,7 +2033,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) @@ -2042,6 +2050,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 @@ -2852,6 +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_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 @@ -3075,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; @@ -3252,6 +3276,8 @@ typedef struct v_BOOL_t fEnableActiveModeOffload; #endif v_U32_t enableLpwrImgTransition; + v_U32_t enable_conc_bmiss; + v_U32_t enable_units_bwait; v_U8_t scanAgingTimeout; v_BOOL_t enableTxLdpc; v_U8_t disableLDPCWithTxbfAP; @@ -3410,6 +3436,7 @@ typedef struct uint32_t edca_be_aifs; v_BOOL_t sendMgmtPktViaWQ5; v_BOOL_t sap_probe_resp_offload; + v_BOOL_t sap_internal_restart; } 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 b673717dc9c9..d1ca157f87ea 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,6 +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; @@ -189,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 { @@ -224,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 @@ -1430,4 +1500,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..ed52105fc372 100644 --- a/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h +++ b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_hostapd.h @@ -87,8 +87,28 @@ 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 ); +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); @@ -96,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_timers(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 9f773184e585..6ce324a48b28 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. * @@ -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 @@ -131,6 +132,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 @@ -236,6 +240,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 @@ -296,6 +301,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 @@ -371,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 tx_arp_req_count; + uint16 rx_arp_rsp_count; + 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; @@ -381,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 @@ -539,8 +575,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; @@ -666,7 +708,6 @@ typedef enum{ HDD_SSR_DISABLED, }e_hdd_ssr_required; -#ifdef WLAN_FEATURE_RMC /*--------------------------------------------------------------------------- hdd_ibss_peer_info_params_t ---------------------------------------------------------------------------*/ @@ -725,7 +766,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 { @@ -754,9 +794,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; @@ -954,6 +992,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; @@ -1193,6 +1247,9 @@ struct hdd_adapter_s /* Currently used antenna Index*/ int antennaIndex; + bool nud_set_arp_stats; + bool con_status; + bool dad; }; #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) @@ -1250,6 +1307,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" @@ -1297,6 +1358,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 @@ -1438,6 +1508,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; @@ -1520,6 +1595,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; @@ -1575,6 +1652,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; @@ -1605,7 +1683,11 @@ 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; + + uint32_t track_arp_ip; }; typedef enum { @@ -1704,6 +1786,14 @@ 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, + 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 ); @@ -1766,7 +1856,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); @@ -1914,6 +2005,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); @@ -1933,4 +2037,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/inc/wlan_hdd_power.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_power.h index 87756d480305..70c700ab4261 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. @@ -135,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/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/inc/wlan_hdd_wmm.h b/drivers/staging/prima/CORE/HDD/inc/wlan_hdd_wmm.h index 76c2837b45f0..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-2015 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. * @@ -407,4 +407,20 @@ 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); + +/**============================================================================ + @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 933a2df781d1..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 ); @@ -1500,7 +1501,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 +1538,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 +1791,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 +1804,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))) { @@ -1815,11 +1833,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 +1875,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 +2074,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 ); @@ -2441,79 +2459,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(); -} /**============================================================================ * @@ -2730,7 +2675,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 +2709,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_cfg.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg.c index a14cca2c216e..27e4d6ca47da 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. * @@ -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, @@ -2860,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, @@ -3719,6 +3741,14 @@ 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_SAP_INTERNAL_RESTART_NAME, WLAN_PARAM_Integer, + hdd_config_t, sap_internal_restart, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_INTERNAL_RESTART_DEFAULT, + CFG_SAP_INTERNAL_RESTART_MIN, + CFG_SAP_INTERNAL_RESTART_MAX), + }; /* @@ -4103,6 +4133,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); @@ -4258,6 +4290,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); @@ -4274,6 +4310,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 = [gEnableSapInternalRestart] Value = [%u] ", + pHddCtx->cfg_ini->sap_internal_restart); } @@ -5270,6 +5309,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) */ @@ -5864,6 +5906,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, @@ -6075,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/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c index 529c5b17f6a3..547d6ad72120 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. * @@ -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) @@ -1439,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, @@ -1477,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) || @@ -3758,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)) { @@ -3800,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); @@ -7442,6 +7464,455 @@ 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_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 + * @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__); + 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__); + } + 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); + v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(adapter))->pvosContext; + 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; + 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) { + 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)); + } + + 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; + + 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 }, +}; + +/** + * 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; +} + +/** + * 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) +{ + + 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; + + 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; + + 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.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, + 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.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, + 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); + adapter->con_status = false; + hdd_con_test_DELBA(adapter); + } + if (adapter->dad) + nla_put_flag(skb, AP_LINK_DAD); + + hdd_ctx->track_arp_ip = 0; + 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[] = { { @@ -7687,7 +8158,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 */ @@ -7818,7 +8305,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, + }, }; /* @@ -8357,7 +8847,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) @@ -8394,20 +8885,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, @@ -8416,12 +8937,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; @@ -8429,31 +8950,28 @@ 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; - - 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); - } + beacon->proberesp_ies_len = proberesp_ies_len; + beacon->assocresp_ies_len= 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; kfree(old); return 0; - } v_U8_t* wlan_hdd_cfg80211_get_ie_ptr( @@ -8668,18 +9186,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); @@ -8688,6 +9201,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)) { @@ -8745,9 +9259,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 @@ -8775,7 +9289,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) { @@ -8791,7 +9306,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) { @@ -8807,7 +9323,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) { @@ -8864,11 +9381,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, @@ -9186,10 +9703,9 @@ 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_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; @@ -9201,6 +9717,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; @@ -9340,14 +9858,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. @@ -9359,8 +9881,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 ) { @@ -9382,17 +9904,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, @@ -9400,8 +9934,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 ) { @@ -9419,7 +9953,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; } @@ -9546,7 +10080,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; @@ -9614,12 +10148,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, @@ -9662,6 +10199,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)) @@ -9941,6 +10481,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 @@ -10020,6 +10562,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) @@ -10516,7 +11060,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, @@ -10586,7 +11130,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 ); @@ -12114,15 +12661,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 { @@ -12221,7 +12762,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); @@ -12684,6 +13231,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")); @@ -12864,7 +13416,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; @@ -12894,6 +13447,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) && @@ -12902,6 +13460,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) || @@ -12917,6 +13480,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; } } @@ -12942,6 +13510,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; } } @@ -12998,6 +13571,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; @@ -13104,20 +13679,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 = jiffies_to_msecs(jiffies); + } + else { + if ((jiffies_to_msecs(jiffies) - + 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)); @@ -13565,7 +14160,6 @@ int wlan_hdd_cfg80211_connect_start( hdd_adapter_t *pAdapter, v_U32_t roamId; tCsrRoamProfile *pRoamProfile; eCsrAuthType RSNAuthType; - const u8 *pValidBssid = NULL; ENTER(); @@ -13613,31 +14207,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) || @@ -14557,6 +15159,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) { @@ -14752,6 +15359,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); @@ -16452,15 +17065,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 @@ -19150,6 +19763,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) { 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..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 @@ -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 } } @@ -816,6 +830,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 +871,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++) @@ -913,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); @@ -1010,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)) @@ -1026,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(); } @@ -1323,6 +1339,135 @@ 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, + FL("offload: can't pass 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) +{ + 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 + * 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))) + ) + { + 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; + } +} + +/** + * 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); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + !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); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + 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); + hddLog(VOS_TRACE_LEVEL_INFO, + FL("offload: setting mc_list_cfg_in_fwr: %d"), + pHddCtx->cfg_ini->fEnableMCAddrList); + } + } +} + static void hdd_conf_suspend_ind(hdd_context_t* pHddCtx, hdd_adapter_t *pAdapter) { @@ -1330,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, @@ -1377,6 +1512,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); @@ -1422,6 +1561,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 = @@ -1549,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, @@ -1569,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__); @@ -1974,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 */ @@ -2125,7 +2317,35 @@ 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) { + 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; + } + + EXIT(); +} /* the HDD interface to WLAN driver re-init. * This is called to initialize/start WLAN driver after a shutdown. @@ -2174,7 +2394,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) @@ -2305,7 +2526,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 = 0xFF; + pHddCtx->last_scan_reject_reason = 0; + pHddCtx->last_scan_reject_timestamp = 0; pHddCtx->hdd_mcastbcast_filter_set = FALSE; pHddCtx->btCoexModeSet = FALSE; hdd_register_mcast_bcast_filter(pHddCtx); @@ -2423,5 +2646,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 e67db4d09044..ffe7cbae158b 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. * @@ -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 @@ -1065,21 +1064,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 { @@ -1285,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_internal_restart) + netif_tx_disable(dev); + else + hdd_hostapd_stop(dev); /* reclaim all resources allocated to the BSS */ vos_status = hdd_softap_stop_bss(pHostapdAdapter); @@ -1486,6 +1504,56 @@ 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; + + + if (hdd_ctx->cfg_ini->sap_internal_restart) { + netif_tx_disable(adapter->dev); + schedule_work(&hdd_ctx->sap_start_work); + } else { + hdd_hostapd_stop(adapter->dev); + } + + return; + } + return; +} + + /**--------------------------------------------------------------------------- \brief hdd_hostapd_ch_avoid_cb() - @@ -1502,7 +1570,7 @@ void hdd_hostapd_update_unsafe_channel_list(hdd_context_t *pHddCtx, --------------------------------------------------------------------------*/ void hdd_hostapd_ch_avoid_cb ( - void *pAdapter, + void *context, void *indParam ) { @@ -1528,14 +1596,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; @@ -1660,7 +1728,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. @@ -2507,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__ ); @@ -2517,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__ ); @@ -4112,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: @@ -4602,18 +4678,19 @@ 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; 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; #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; @@ -4666,7 +4743,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__); @@ -4683,10 +4760,21 @@ VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter ) 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: - hdd_softap_deinit_tx_rx( pAdapter ); + hdd_softap_deinit_tx_rx(pAdapter, re_init); EXIT(); return status; } @@ -4782,7 +4870,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 @@ -4803,3 +4891,121 @@ 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 (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; + } + + 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_timers() - Destroy sap timers + * @adapter: sap adapter context + * + * Return: nothing + */ +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 (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; + } + + 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_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 6f2ae14eec45..0a38b2d48eb7 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 */ @@ -8222,7 +8228,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; } @@ -8677,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; @@ -9216,6 +9224,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; @@ -9298,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, true); + hdd_sap_destroy_timers(pAdapter); + } else { + netif_carrier_off(pAdapter->dev); + } pAdapter->sessionCtx.station.hdd_ReassocScenario = VOS_FALSE; @@ -9347,6 +9497,113 @@ 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 + * @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 = 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, + 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; @@ -9403,7 +9660,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); @@ -9411,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, true); + 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: @@ -10563,6 +10828,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 */ @@ -11518,7 +11784,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 = 0xFF; + pHddCtx->last_scan_reject_reason = 0; + pHddCtx->last_scan_reject_timestamp = 0; init_completion(&pHddCtx->full_pwr_comp_var); init_completion(&pHddCtx->standby_comp_var); @@ -11533,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); @@ -11545,11 +11814,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 @@ -12293,6 +12564,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) { @@ -14567,6 +14845,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); 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/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 6e02ec36b306..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 @@ -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. * @@ -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) @@ -314,10 +318,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 +329,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; @@ -386,7 +390,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__); @@ -562,6 +566,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. @@ -840,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; @@ -892,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__ ); @@ -909,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__ ); @@ -1735,6 +1748,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 5404e1ad6769..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 @@ -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; @@ -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,17 @@ 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) + { + 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. qid = hdd_QdiscAcToTlAC[skb->queue_mapping]; ac = qid; @@ -852,6 +864,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 +916,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 +996,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 +1065,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]; @@ -1039,6 +1086,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 @@ -1929,6 +1985,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 ) || @@ -2066,10 +2123,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; @@ -2081,6 +2148,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; @@ -2139,6 +2216,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; @@ -2534,6 +2617,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 @@ -2560,6 +2677,8 @@ 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; + bool track_arp_resp = false; //Sanity check on inputs if ( ( NULL == vosContext ) || @@ -2600,6 +2719,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__); @@ -2610,6 +2737,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__); @@ -2671,6 +2807,25 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, } } + arp_pkt = vos_is_arp_pkt(skb, false); + + if (arp_pkt) + { + 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) { + 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); @@ -2687,6 +2842,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, @@ -2703,11 +2866,30 @@ VOS_STATUS hdd_rx_packet_cbk( v_VOID_t *vosContext, if (NET_RX_SUCCESS == rxstat) { + + if (arp_pkt) + { + 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; ++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/HDD/src/wlan_hdd_wext.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_wext.c index d181ed768449..5cadb459d21f 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. * @@ -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 *, @@ -1539,6 +1538,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; @@ -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: @@ -3798,7 +3808,6 @@ static int iw_get_rssi(struct net_device *dev, (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) @@ -4025,6 +4034,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++) { @@ -6907,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, @@ -6927,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, @@ -7000,7 +7018,16 @@ static int __iw_get_char_setnone(struct net_device *dev, pResetStats->totalMutexReadFailures, pResetStats->totalMIFErrorFailures, pResetStats->totalFWHearbeatFailures, - pResetStats->totalUnknownExceptions + pResetStats->totalUnknownExceptions, + + parpStats->tx_arp_req_count, + parpStats->txDropped, + + parpStats->rx_arp_rsp_count, + parpStats->rxDropped, + parpStats->rxDelivered, + parpStats->rxRefused, + parpStats->reason ); wrqu->data.length = strlen(extra); @@ -8617,8 +8644,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) { @@ -8633,6 +8661,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 = @@ -8655,11 +8694,8 @@ 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); } } @@ -8712,8 +8748,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) @@ -8729,11 +8767,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)) @@ -8745,12 +8794,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; @@ -8957,12 +9002,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); + hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; 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) { @@ -8970,6 +9059,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); @@ -9024,26 +9119,55 @@ 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__); return -EINVAL; } + WLANTL_SetDataPktFilter((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, + pHddStaCtx->conn_info.staId[0], true); break; case HDD_RCV_FILTER_CLEAR: 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; + 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; + } + + WLANTL_SetDataPktFilter((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, + pHddStaCtx->conn_info.staId[0], false); break; default : @@ -9373,7 +9497,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(); @@ -9643,8 +9767,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; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -9689,12 +9814,24 @@ 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)); + 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; } @@ -9710,9 +9847,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; } @@ -9720,13 +9859,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); @@ -9767,7 +9907,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) @@ -9793,7 +9933,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), @@ -9837,19 +9977,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)) { @@ -9857,6 +10004,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", @@ -9866,7 +10019,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)) { @@ -9883,7 +10036,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); @@ -9906,7 +10059,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); @@ -9940,7 +10093,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*/ @@ -9974,6 +10127,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: @@ -9986,6 +10140,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*/ 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..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-2015 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. * @@ -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,112 @@ 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_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 @@ -2120,7 +2232,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; 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/MAC/inc/qwlan_version.h b/drivers/staging/prima/CORE/MAC/inc/qwlan_version.h index b885a07c01ea..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 61 +#define QWLAN_VERSION_BUILD 66 -#define QWLAN_VERSIONSTR "3.0.11.61" +#define QWLAN_VERSIONSTR "3.0.11.66" #endif /* QWLAN_VERSION_H */ diff --git a/drivers/staging/prima/CORE/MAC/inc/sirApi.h b/drivers/staging/prima/CORE/MAC/inc/sirApi.h index 08f6c2253d7d..af6bf0393142 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; @@ -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; @@ -3767,6 +3766,12 @@ typedef struct sSirWlanSetRxpFilters tANI_U8 setMcstBcstFilter; }tSirWlanSetRxpFilters,*tpSirWlanSetRxpFilters; + +typedef struct sSirUpdateCfgIntParam +{ + tANI_U32 cfgId; +}tSirUpdateCfgIntParam,*tpSirUpdateCfgIntParam; + typedef struct { //FW mail box address @@ -3783,9 +3788,56 @@ 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 { @@ -4227,6 +4279,8 @@ typedef struct sSirRcvFltPktClearParam tANI_U8 filterId; tSirMacAddr selfMacAddr; tSirMacAddr bssId; + pktFilterReqCb pktFilterCallback; + void *cbCtx; }tSirRcvFltPktClearParam, *tpSirRcvFltPktClearParam; // @@ -6054,5 +6108,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/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/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..39a53fc1b367 100644 --- a/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c +++ b/drivers/staging/prima/CORE/MAC/src/cfg/cfgProcMsg.c @@ -1703,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/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/include/sirParams.h b/drivers/staging/prima/CORE/MAC/src/include/sirParams.h index 1f6473698ca4..5dfe0eaf51a1 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; @@ -764,6 +765,13 @@ 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) +/* 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_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/MAC/src/pe/lim/limAssocUtils.c b/drivers/staging/prima/CORE/MAC/src/pe/lim/limAssocUtils.c index 44c301ed75ec..188f2e578688 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; } } @@ -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..7a60cac737e5 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); @@ -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/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; 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/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/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/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/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..cead21d75b15 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 @@ -1863,9 +1856,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 +2061,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); @@ -2195,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; @@ -2352,16 +2342,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) @@ -5530,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() * @@ -5876,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/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/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/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 8d3483b49ca8..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. * @@ -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); } @@ -655,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/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/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/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; } 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; } /*========================================================================== diff --git a/drivers/staging/prima/CORE/SME/inc/csrApi.h b/drivers/staging/prima/CORE/SME/inc/csrApi.h index ef7f97d3dd37..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; @@ -1191,6 +1192,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/inc/sme_Api.h b/drivers/staging/prima/CORE/SME/inc/sme_Api.h index 842f9981495f..cf65a45270b4 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. * @@ -3960,4 +3960,16 @@ 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); + +/* ARP DEBUG STATS */ +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); +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/csr/csrApiRoam.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiRoam.c index 6b36c8a73fdd..9e8e305f80b7 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. * @@ -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; @@ -6944,7 +6949,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); @@ -9559,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 @@ -13218,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. @@ -13231,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))) @@ -14602,16 +14608,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/csr/csrApiScan.c b/drivers/staging/prima/CORE/SME/src/csr/csrApiScan.c index 7ae5f941580c..23ab858c355f 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. * @@ -2208,10 +2208,11 @@ 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 " + 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; } @@ -2280,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; @@ -2689,6 +2702,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 +2720,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( + pTmpResult->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); @@ -3253,36 +3282,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; @@ -3319,8 +3354,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; @@ -4051,8 +4086,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) { @@ -6818,98 +6851,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. @@ -6920,16 +6915,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 @@ -6939,8 +6935,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 } @@ -7017,14 +7014,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); } } @@ -7913,6 +7913,39 @@ 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")); + return eHAL_STATUS_FAILURE; + } + + 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) @@ -7922,6 +7955,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 @@ -7949,13 +7983,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); @@ -8464,7 +8508,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, @@ -8476,6 +8519,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 @@ -9007,8 +9054,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; @@ -9328,3 +9375,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, tANI_U32 *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 b297d3d45e58..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. * @@ -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)) @@ -1092,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, tANI_U32 *new_index, tANI_U8 ch144_support); #endif 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) { 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..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 @@ -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) { @@ -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 @@ -14355,3 +14419,167 @@ 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; +} + +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; +} + +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; +} 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 ], 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; } 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/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. 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..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 @@ -906,6 +906,10 @@ 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); + 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/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], 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..35d9f7d976b2 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,37 @@ 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); + +/* + * 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); + +/** + * 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 7902ac7df434..09754b8a967a 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,18 @@ WLANTL_STATxAuth #endif /* FEATURE_WLAN_TDLS */ if( tlMetaInfo.ucIsArp ) { + if (pTLCb->track_arp) + { + 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__)); + } + } + if (pStaClient->arpOnWQ5) { ucTxFlag |= HAL_USE_FW_IN_TX_PATH; @@ -8331,7 +8343,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)) @@ -13775,6 +13787,69 @@ 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; + } +} + +/** + * 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 @@ -14389,3 +14464,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..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 @@ -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. * @@ -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) { @@ -1164,6 +1165,12 @@ 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)) + { + 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)) { @@ -1299,7 +1306,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..fdb5898b8fb1 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; @@ -966,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 3cb282ec34d2..898a039c4b76 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,8 +205,20 @@ 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, }; +/** + * 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 ------------------------------------------------------------------------*/ @@ -510,5 +523,14 @@ 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); + +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 3aa0a33b55eb..06e8e2c9ef2c 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. * @@ -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 ------------------------------------------------------------------------*/ @@ -1170,4 +1180,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 747851ff770c..881a2b59bd64 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 * ------------------------------------------------------------------------*/ @@ -269,8 +282,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) { @@ -900,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; @@ -1748,7 +1765,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); @@ -3611,3 +3629,303 @@ 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); + } +} +/** + * 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(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_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: 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 + 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 + * + * 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/VOSS/src/vos_sched.c b/drivers/staging/prima/CORE/VOSS/src/vos_sched.c index 95f551bd12dd..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. * @@ -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 @@ -2196,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 e73cf39aa808..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-2015 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. * @@ -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 @@ -535,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/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); } 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 */ 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..fdc768d8ca41 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. * @@ -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 */ @@ -524,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 @@ -1187,6 +1192,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 @@ -1289,6 +1295,12 @@ 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 +#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); eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId, @@ -1596,6 +1608,7 @@ WDA_DS_FinishULA txFlag timeStamp ucIsEapol + ucIsArp ucUP OUT @@ -1625,6 +1638,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.c b/drivers/staging/prima/CORE/WDA/src/wlan_qct_wda.c index 7563dc04ce9e..f88a83b8398b 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. * @@ -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))) @@ -163,7 +165,12 @@ 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_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 @@ -1689,9 +1696,10 @@ 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); + #ifdef WLAN_SOFTAP_VSTA_FEATURE tlvStruct->type = QWLAN_HAL_CFG_MAX_ASSOC_LIMIT; tlvStruct->length = sizeof(tANI_U32); @@ -2396,6 +2404,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 { @@ -2645,6 +2683,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 +2694,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; } /* @@ -5200,7 +5241,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) { @@ -5302,14 +5343,20 @@ 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; + 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; } } } @@ -5365,7 +5412,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, @@ -5373,7 +5419,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) @@ -5393,7 +5439,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); @@ -5437,6 +5483,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, @@ -11066,6 +11272,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 = @@ -14215,12 +14422,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; @@ -15089,6 +15307,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 @@ -15321,6 +15799,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) @@ -15692,16 +16189,26 @@ 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 */ case WDA_TIMER_TRAFFIC_STATS_IND: { WDA_TimerTrafficStatsInd(pWDA); break; } + /* Connection status related messages */ + case WDA_TRIGGER_ADD_BA_REQ: + { + WDA_BaCheckActivity(pWDA, true); + break; + } + case WDA_GET_CON_STATUS: + { + WDA_GetConnectionStatus(pWDA, (getConStatusParams *)pMsg->bodyptr); + break; + } #ifdef WLAN_FEATURE_VOWIFI_11R case WDA_AGGR_QOS_REQ: { @@ -16058,6 +16565,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, @@ -17407,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 ; @@ -17420,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) { @@ -17463,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))) @@ -17470,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 ; } @@ -17573,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"); } @@ -17592,6 +18165,7 @@ void WDA_BaCheckActivity(tWDA_CbContext *pWDA) } return ; } + /* * WDA common routine to create timer used by WDA. */ @@ -17675,6 +18249,7 @@ static VOS_STATUS wdaCreateTimers(tWDA_CbContext *pWDA) } return VOS_STATUS_SUCCESS ; } + /* * WDA common routine to destroy timer used by WDA. */ @@ -19166,6 +19741,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); */ @@ -19176,7 +19753,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) ; @@ -19193,6 +19777,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); @@ -19207,6 +19792,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); @@ -19264,6 +19856,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); 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.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_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/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 46bd75813eab..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 @@ -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. * @@ -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++ = ' '; @@ -16764,6 +16864,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); @@ -18779,8 +18885,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); @@ -22641,6 +22751,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); @@ -24739,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; } @@ -25108,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; } @@ -38184,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*/ 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..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 @@ -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]); @@ -211,9 +213,16 @@ 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, &staId, - pTxMetadata->txBdToken); + &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, ucProtMgmtFrame, 0, isEapol, isArp, + &staId, pTxMetadata->txBdToken); if(WDI_STATUS_SUCCESS != wdiStatus) { 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); +} 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..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. * @@ -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); @@ -1282,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..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 @@ -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,20 @@ int wpalIsDxeSSREnable(void) return vos_get_dxeSSREnable(); } +bool wpalIsArpPkt(void *pPacket) +{ + vos_pkt_t *pkt = (vos_pkt_t*)pPacket; + + 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) +{ + vos_update_arp_fw_tx_delivered(); +} 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 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) 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/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) 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; } 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 */ 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" 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_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 627496d3ffa8..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 @@ -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)); @@ -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); 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; 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; } 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; 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/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 */ 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/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/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/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, 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/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/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/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) 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); 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/fs_struct.c b/fs/fs_struct.c index 8e19779c9d5e..5a1bb8242a56 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -127,8 +127,8 @@ 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/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/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/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/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/namei.c b/fs/namei.c index 022771a0e3b7..827f0eb25bf3 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; @@ -2405,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); } @@ -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/namespace.c b/fs/namespace.c index e4f1f9c071b8..af3860342847 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); + root = mount_fs(type, flags, name, &mnt->mnt, 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 - err = do_remount_sb(sb, flags, data, 0); + else { + err = do_remount_sb2(path->mnt, 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/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/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/open.c b/fs/open.c index b1fd2c1d55f4..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,17 +57,24 @@ 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) { 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 +86,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; @@ -103,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); @@ -152,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; @@ -168,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)) @@ -187,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); @@ -302,6 +311,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 +342,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 +354,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 +398,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 +418,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 +426,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 +451,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; @@ -476,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); @@ -550,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/pnode.c b/fs/pnode.c index 9af0df15256e..46a71f920a69 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -359,3 +359,32 @@ int propagate_umount(struct list_head *list) __propagate_umount(mnt); return 0; } + +/* + * 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; + + if (sb->s_op->copy_mnt_data) { + m = next_descendent(mnt, m); + while (m) { + sb->s_op->copy_mnt_data(m->mnt.data, mnt->mnt.data); + m = next_descendent(mnt, m); + } + } +} diff --git a/fs/pnode.h b/fs/pnode.h index b091445c1c4a..b0709096de7c 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); +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); 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/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), 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/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/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index b2fa36f13e73..f58ba5908ff6 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; @@ -76,17 +77,13 @@ 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) { - __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; } @@ -110,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, @@ -132,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); @@ -152,35 +145,25 @@ 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 (strncasecmp(name->name, str, len) == 0) + if (str_n_case_eq(name->name, str, len)) return 0; } 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 b4cc97c47bce..9a281b68c408 100755 --- a/fs/sdcardfs/derived_perm.c +++ b/fs/sdcardfs/derived_perm.c @@ -30,12 +30,15 @@ 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; + ci->under_cache = pi->under_cache; + ci->under_obb = pi->under_obb; + 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, struct inode *top) + uid_t uid, bool under_android, + struct inode *top) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); @@ -43,137 +46,269 @@ 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; + 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) +/* 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_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); + 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"); + 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 * 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: - /* 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->top = &info->vfs_inode; - break; - case PERM_ROOT: - /* Assume masked off by default. */ - if (!strcasecmp(newdentry->d_name.name, "Android")) { - /* 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: - case PERM_ANDROID_OBB: - case PERM_ANDROID_MEDIA: - appid = get_appid(sbi->pkgl_id, newdentry->d_name.name); - if (appid != 0) { - info->d_uid = multiuser_get_uid(parent_info->userid, appid); - } - info->top = &info->vfs_inode; - break; + 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; + 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: + /* 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); + 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; } } 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); } -static int descendant_may_need_fixup(perm_t perm) { - if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID) +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->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_PACKAGE_CACHE: + if (info->d_uid != 0) + gid = multiuser_get_ext_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); + 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_debug("sdcardfs: Failed to touch up lower fs gid/uid for %s\n", name); + } + sdcardfs_put_lower_path(dentry, &path); +} + +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; } -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; } -void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) { +static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit, int depth) +{ struct dentry *child; struct sdcardfs_inode_info *info; - if (!dentry || !dentry->d_inode) + + /* + * 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) { + spin_unlock(&dentry->d_lock); 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); + 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) || qstr_case_eq(&child->d_name, &limit->name)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fixup_tmp_permissions(child->d_inode); + spin_unlock(&child->d_lock); + break; + } } - dput(child); + spin_unlock(&child->d_lock); } - } else if (descendant_may_need_fixup(info->perm)) { - mutex_lock(&dentry->d_inode->i_mutex); + } else if (descendant_may_need_fixup(info, limit)) { list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { - fixup_perms_recursive(child, name, len); + __fixup_perms_recursive(child, limit, depth + 1); } - mutex_unlock(&dentry->d_inode->i_mutex); } + spin_unlock(&dentry->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); - fix_derived_permission(dentry->d_inode); - fixup_top_recursive(dentry); - } - } - } - spin_unlock(&parent->d_lock); +void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) +{ + __fixup_perms_recursive(dentry, limit, 0); } /* main function for updating derived permission */ @@ -181,38 +316,37 @@ 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__); + if (!dentry || !dentry->d_inode) { + pr_err("sdcardfs: %s: invalid dentry\n", __func__); return; } /* FIXME: * 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) { + if (parent) { get_derived_permission(parent, dentry); dput(parent); } } - fix_derived_permission(dentry->d_inode); + fixup_tmp_permissions(dentry->d_inode); } 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 && - !strcasecmp(dentry->d_name.name, "obb")) { + 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; } @@ -227,36 +361,40 @@ 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. - * 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__); + 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) || - strcasecmp(sbi->obbpath_s, obbpath_s)) { + !str_case_eq(sbi->obbpath_s, obbpath_s)) { ret = 1; } kfree(path_buf); } - //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; } @@ -264,17 +402,18 @@ 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 && - !strcasecmp(dentry->d_name.name, "obb")) { + if (parent_info->perm == PERM_PRE_ROOT && + 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); @@ -284,7 +423,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; @@ -293,23 +433,24 @@ 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, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &obbpath); - if(!err) { + 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 * 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. */ - printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); + * a lookup fail. + */ + 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 2b3aa03ab271..8943bef34096 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; } @@ -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; } @@ -160,8 +164,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,16 +176,10 @@ 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); - goto out; - } } /* @@ -195,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; @@ -216,18 +216,14 @@ 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)) { - 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; goto out_err; } /* 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 = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { @@ -252,9 +248,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); @@ -322,11 +317,29 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag) return err; } -static struct file *sdcardfs_get_lower_file(struct file *f) +/* + * 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) { - return sdcardfs_lower_file(f); + 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, @@ -341,12 +354,11 @@ 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 */ 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, @@ -358,5 +370,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/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 597dcf912e9a..71694c0e9f14 100755 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -20,18 +20,24 @@ #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) +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(); 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); @@ -40,9 +46,9 @@ const struct cred * override_fsids(struct sdcardfs_sb_info* sbi) } /* 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); @@ -54,25 +60,24 @@ 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; 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" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } /* 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; + lower_dentry_mnt = lower_path.mnt; lower_parent_dentry = lock_parent(lower_dentry); /* set last 16bytes of mode field to 0664 */ @@ -81,9 +86,13 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, /* 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); + err = vfs_create2(lower_dentry_mnt, lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -92,10 +101,12 @@ 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; free_fs_struct(copied_fs); +out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); REVERT_CRED(saved_cred); @@ -149,28 +160,27 @@ 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; const struct cred *saved_cred = NULL; - 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" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } /* 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; + 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. @@ -230,14 +240,15 @@ 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 { - printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n", + } else { + pr_err("sdcardfs: failed to open(%s): %ld\n", abs_path, PTR_ERR(filp)); return PTR_ERR(filp); } @@ -251,6 +262,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); @@ -259,21 +271,20 @@ 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)) { - 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(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } /* 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)) { - printk(KERN_INFO "sdcardfs: No minimum free space.\n"); + pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; goto out_revert; } @@ -281,6 +292,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 */ @@ -289,52 +301,66 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* temporarily change umask for lower fs write */ saved_fs = current->fs; 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); + err = vfs_mkdir2(lower_mnt, 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)) { + 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; } 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); - - if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb")) + fixup_lower_ownership(dentry, dentry->d_name.name); + unlock_dir(lower_parent_dentry); + 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); 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; } @@ -342,7 +368,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode out: current->fs = saved_fs; free_fs_struct(copied_fs); - unlock_dir(lower_parent_dentry); +out_unlock: sdcardfs_put_lower_path(dentry, &lower_path); out_revert: REVERT_CRED(saved_cred); @@ -354,29 +380,29 @@ 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; - 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" - " dentry: %s, task:%s\n", - __func__, dentry->d_name.name, current->comm); + if (!check_caller_access_to_name(dir, &dentry->d_name)) { err = -EACCES; goto out_eacces; } /* 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. */ + * the dentry on the original path should be deleted. + */ 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; @@ -440,27 +466,25 @@ 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; 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)) { - 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); + 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; } /* 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); 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); @@ -476,7 +500,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; @@ -488,23 +513,11 @@ 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.*/ - 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_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); + 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); @@ -586,23 +599,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_RATELIMIT(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 *top = SDCARDFS_I(inode)->top; + struct inode tmp; + struct inode *top = grab_top(SDCARDFS_I(inode)); - /* 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); + if (!top) { + release_top(SDCARDFS_I(inode)); + WARN(1, "Top value was null!\n"); + 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. */ - 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)) + pr_warn("%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 @@ -619,6 +672,7 @@ static int sdcardfs_permission(struct inode *inode, int mask) * we check it with AID_MEDIA_RW permission */ struct inode *lower_inode; + OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); lower_inode = sdcardfs_lower_inode(inode); @@ -631,99 +685,86 @@ static int sdcardfs_permission(struct inode *inode, int mask) } -static void sdcardfs_fillattr(struct inode *inode, struct kstat *stat) +static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia) { - 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) -{ - 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); - - sdcardfs_fillattr(inode, stat); - sdcardfs_put_lower_path(dentry, &lower_path); - return 0; + WARN_RATELIMIT(1, "sdcardfs does not support setattr. User setattr2.\n"); + return -EINVAL; } -static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) +static int sdcardfs_setattr(struct vfsmount *mnt, 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; 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); + /* 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); - /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ if (!err) { /* check the Android group ID */ 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); + if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) err = -EACCES; - } dput(parent); } if (err) goto out_err; + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode)); + 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) */ - memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); @@ -740,7 +781,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); @@ -763,7 +804,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); @@ -781,13 +823,68 @@ 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 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; + + stat->dev = inode->i_sb->s_dev; + stat->ino = inode->i_ino; + 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(mnt, 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 kstat lower_stat; + 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)) { + dput(parent); + return -EACCES; + } + dput(parent); + + sdcardfs_get_lower_path(dentry, &lower_path); + 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; +} + 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. @@ -800,12 +897,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 @@ -817,7 +916,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 4c3b2e831e6a..3ac40fead490 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) @@ -73,6 +72,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 */ @@ -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; @@ -102,26 +104,23 @@ 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) { - 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++; @@ -164,27 +163,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 +193,54 @@ 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 { + struct dir_context ctx; + const struct qstr *to_find; + char *name; + bool found; +}; + +static int sdcardfs_name_match(void *__buf, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct sdcardfs_name_data *buf = (struct sdcardfs_name_data *) __buf; + struct qstr candidate = QSTR_INIT(name, namelen); + + if (qstr_case_eq(buf->to_find, &candidate)) { + memcpy(buf->name, name, namelen); + buf->name[namelen] = 0; + buf->found = true; + return 1; + } + return 0; } /* @@ -219,9 +256,10 @@ 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 qstr dname; + struct dentry *ret_dentry = NULL; struct sdcardfs_sb_info *sbi; sbi = SDCARDFS_SB(dentry->d_sb); @@ -231,68 +269,90 @@ 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) { - struct dentry *child; - struct dentry *match = NULL; - 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) { - 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); - 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 */ 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. */ - printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); + * a lookup fail. + */ + pr_info("sdcardfs: base obbpath is not available\n"); sdcardfs_put_reset_orig_path(dentry); goto out; } } 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; } @@ -304,14 +364,14 @@ 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); + 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, &this); + lower_dentry = d_alloc(lower_dir_dentry, &dname); if (!lower_dentry) { err = -ENOMEM; goto out; @@ -332,14 +392,16 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, err = 0; out: - return ERR_PTR(err); + if (err) + return ERR_PTR(err); + return ret_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. @@ -356,16 +418,13 @@ 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", - __func__, dentry->d_name.name, current->comm); goto out_err; - } + } /* 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); @@ -378,9 +437,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) { @@ -388,7 +445,8 @@ 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); + 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/main.c b/fs/sdcardfs/main.c index 3666aef3e0f0..bf3d3ab9395e 100755 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -28,9 +28,8 @@ enum { Opt_fsgid, Opt_gid, Opt_debug, - Opt_lower_fs, Opt_mask, - Opt_multiuser, // May need? + Opt_multiuser, Opt_userid, Opt_reserved_mb, Opt_err, @@ -49,7 +48,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,10 +58,10 @@ 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; - opts->mask = 0; + vfsopts->mask = 0; opts->multiuser = false; opts->fs_user_id = 0; - opts->gid = 0; + vfsopts->gid = 0; /* by default, 0MB is reserved */ opts->reserved_mb = 0; @@ -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; @@ -94,7 +95,7 @@ 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: if (match_int(&args[0], &option)) @@ -104,7 +105,7 @@ 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: opts->multiuser = true; @@ -116,25 +117,81 @@ 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); } 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: + pr_warn("Option \"%s\" can't be changed during remount\n", p); + break; + /* unknown option */ + default: + if (!silent) + pr_err("Unrecognized mount option \"%s\" or missing value", p); + return -EINVAL; + } + } + + if (debug) { + 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; +} + #if 0 /* * our custom d_alloc_root work-alike @@ -164,57 +221,58 @@ 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); /* * 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"); + 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); + 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; } 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"); + pr_err("sdcardfs: invalid options\n"); goto out_freesbi; } @@ -223,6 +281,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, 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; @@ -267,23 +332,24 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, /* 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); } - 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); 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 */ @@ -306,9 +372,11 @@ 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 +387,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,19 +396,34 @@ 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_kill_sb(struct super_block *sb) { +void *sdcardfs_alloc_mnt_data(void) +{ + return kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); +} + +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); @@ -353,10 +436,13 @@ 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, }; +MODULE_ALIAS_FS(SDCARDFS_NAME); static int __init init_sdcardfs_fs(void) { @@ -392,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); diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c index c807d7f18f8b..96759ca827e3 100755 --- a/fs/sdcardfs/mmap.c +++ b/fs/sdcardfs/mmap.c @@ -23,28 +23,46 @@ 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; + const struct vm_operations_struct *lower_vm_ops; + + 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; + + err = lower_vm_ops->page_mkwrite(vma, vmf); +out: return err; } @@ -53,30 +71,20 @@ 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, }; const struct vm_operations_struct sdcardfs_vm_ops = { .fault = sdcardfs_fault, + .page_mkwrite = sdcardfs_page_mkwrite, + .open = sdcardfs_vm_open, + .close = sdcardfs_vm_close, }; diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h index 923ba101dfa9..d0c925cda299 100755 --- a/fs/sdcardfs/multiuser.h +++ b/fs/sdcardfs/multiuser.h @@ -18,20 +18,29 @@ * 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_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; 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_ext_cache_gid(uid_t uid) +{ + return uid - AID_APP_START + AID_EXT_CACHE_GID_START; } -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(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 d1961cf5677a..27205cdb8cad 100755 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -20,8 +20,10 @@ #include "sdcardfs.h" #include +#include #include - +#include +#include #include #include @@ -29,387 +31,840 @@ #include -#define STRING_BUF_SIZE (512) - struct hashtable_entry { struct hlist_node hlist; - void *key; - unsigned int value; + struct hlist_node dlist; /* for deletion cleanup */ + struct qstr key; + atomic_t value; }; -struct sb_list { - struct super_block *sb; - struct list_head list; -}; +static DEFINE_HASHTABLE(package_to_appid, 8); +static DEFINE_HASHTABLE(package_to_userid, 8); +static DEFINE_HASHTABLE(ext_to_groupid, 8); -struct packagelist_data { - DECLARE_HASHTABLE(package_to_appid,8); - spinlock_t hashtable_lock; -}; +static struct kmem_cache *hashtable_entry_cachep; -static struct packagelist_data *pkgl_data_all; +static unsigned int full_name_case_hash(const unsigned char *name, unsigned int len) +{ + unsigned long hash = init_name_hash(); -static struct kmem_cache *hashtable_entry_cachep; + while (len--) + hash = partial_name_hash(tolower(*name++), hash); + return end_name_hash(hash); +} -static unsigned int str_hash(const char *key) { - int i; - unsigned int h = strlen(key); - char *data = (char *)key; +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); +} + +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; +} + + +static appid_t __get_appid(const struct qstr *key) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + appid_t ret_id; - for (i = 0; i < strlen(key); i++) { - h = h * 31 + *data; - data++; + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); + return ret_id; + } } - return h; + rcu_read_unlock(); + return 0; +} + +appid_t get_appid(const char *key) +{ + struct qstr q; + + qstr_init(&q, key); + return __get_appid(&q); } -appid_t get_appid(void *pkgl_id, const char *app_name) +static appid_t __get_ext_gid(const struct qstr *key) { - struct packagelist_data *pkgl_dat = pkgl_data_all; struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(app_name); + unsigned int hash = key->hash; appid_t ret_id; - spin_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); + rcu_read_lock(); + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); return ret_id; } } - spin_unlock(&pkgl_dat->hashtable_lock); + rcu_read_unlock(); return 0; } +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 = 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 && + qstr_case_eq(app_name, &hash_cur->key)) { + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + return 0; +} + +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 char* 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"); /* 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; } } /* 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, + appid_t value) +{ + struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, + 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); + return NULL; } + + atomic_set(&ret->value, value); + return ret; } -static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key, - unsigned int 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(pkgl_dat->package_to_appid, hash_cur, hlist, hash) { - if (!strcasecmp(key, hash_cur->key)) { - hash_cur->value = value; + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + atomic_set(&hash_cur->value, value); return 0; } } - new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_ATOMIC); + new_entry = alloc_hashtable_entry(key, value); if (!new_entry) return -ENOMEM; - new_entry->key = kstrdup(key, GFP_ATOMIC); - 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, const char *key) { - if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) { - fixup_perms_recursive(sb->s_root, key, strlen(key)); +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 = key->hash; + + /* An extension can only belong to one gid */ + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (qstr_case_eq(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_str_to_int(struct packagelist_data *pkgl_dat, char *key, - unsigned int value) { - int ret; +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 = 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 && + qstr_case_eq(key, &hash_cur->key)) + return 0; + } + new_entry = alloc_hashtable_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 struct qstr *key) +{ struct sdcardfs_sb_info *sbinfo; - mutex_lock(&sdcardfs_super_list_lock); - spin_lock(&pkgl_dat->hashtable_lock); - ret = insert_str_to_int_lock(pkgl_dat, key, value); - spin_unlock(&pkgl_dat->hashtable_lock); + struct limit_search limit = { + .flags = BY_NAME, + .name = QSTR_INIT(key->name, key->len), + }; + 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_name_userid(const struct qstr *key, userid_t userid) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_NAME | BY_USERID, + .name = QSTR_INIT(key->name, key->len), + .userid = userid, + }; list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { - if (sbinfo) { - fixup_perms(sbinfo->sb, key); - } + 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 struct qstr *key, appid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_packagelist_appid_entry_locked(key, value); + if (!err) + fixup_all_perms_name(key); 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 int insert_ext_gid_entry(const struct qstr *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 void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key) +static int insert_userid_exclude_entry(const struct qstr *key, userid_t value) { - struct sdcardfs_sb_info *sbinfo; - struct hashtable_entry *hash_cur; - unsigned int hash = str_hash(key); + int err; + mutex_lock(&sdcardfs_super_list_lock); - spin_lock(&pkgl_data_all->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); + 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; +} + +static void free_hashtable_entry(struct hashtable_entry *entry) +{ + kfree(entry->key.name); + kmem_cache_free(hashtable_entry_cachep, entry); +} + +static void remove_packagelist_entry_locked(const struct qstr *key) +{ + struct hashtable_entry *hash_cur; + 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 (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 (qstr_case_eq(key, &hash_cur->key)) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); break; } } - spin_unlock(&pkgl_data_all->hashtable_lock); - list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { - if (sbinfo) { - fixup_perms(sbinfo->sb, key); + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) + free_hashtable_entry(hash_cur); +} + +static void remove_packagelist_entry(const struct qstr *key) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_packagelist_entry_locked(key); + fixup_all_perms_name(key); + mutex_unlock(&sdcardfs_super_list_lock); +} + +static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + 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); + break; } } +} + +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_all_hashentrys(struct packagelist_data *pkgl_dat) +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; - spin_lock(&pkgl_data_all->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); - hash_init(pkgl_dat->package_to_appid); + + 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_hashtable_entry(hash_cur); + } } -static struct packagelist_data * packagelist_create(void) +static void remove_userid_all_entry(userid_t userid) { - struct packagelist_data *pkgl_dat; + mutex_lock(&sdcardfs_super_list_lock); + remove_userid_all_entry_locked(userid); + fixup_all_perms_userid(userid); + mutex_unlock(&sdcardfs_super_list_lock); +} - 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); +static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t userid) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key) && + atomic_read(&hash_cur->value) == userid) { + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_hashtable_entry(hash_cur); + break; + } } +} - spin_lock_init(&pkgl_dat->hashtable_lock); - hash_init(pkgl_dat->package_to_appid); - - return pkgl_dat; +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); + fixup_all_perms_name_userid(key, userid); + mutex_unlock(&sdcardfs_super_list_lock); } -static void packagelist_destroy(struct packagelist_data *pkgl_dat) +static void packagelist_destroy(void) { - remove_all_hashentrys(pkgl_dat); - printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); - kfree(pkgl_dat); + struct hashtable_entry *hash_cur; + 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); + 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, dlist) + free_hashtable_entry(hash_cur); + mutex_unlock(&sdcardfs_super_list_lock); + pr_info("sdcardfs: destroyed packagelist pkgld\n"); } -struct package_appid { +struct package_details { struct config_item item; - int add_pid; + struct qstr 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, -}; +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 struct configfs_attribute *package_appid_attrs[] = { - &package_appid_attr_add_pid, - NULL, -}; +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)); +} -static ssize_t package_appid_attr_show(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) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + + ret = insert_packagelist_entry(&package_details->name, tmp); + + if (ret) + return ret; + + return count; +} + +static ssize_t package_details_excluded_userids_show(struct package_details *package_details, char *page) { - ssize_t count; - count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name)); + struct hashtable_entry *hash_cur; + 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 (qstr_case_eq(&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_appid_attr_store(struct config_item *item, - struct configfs_attribute *attr, +static ssize_t package_details_excluded_userids_store(struct package_details *package_details, 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; + + ret = insert_userid_exclude_entry(&package_details->name, tmp); - if (tmp > INT_MAX) - return -ERANGE; - ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp); - package_appid->add_pid = tmp; if (ret) return ret; return count; } -static void package_appid_release(struct config_item *item) +static ssize_t package_details_clear_userid_store(struct package_details *package_details, + const char *page, size_t count) { - 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); - kfree(to_package_appid(item)); + 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 struct configfs_item_operations package_appid_item_ops = { - .release = package_appid_release, - .show_attribute = package_appid_attr_show, - .store_attribute = package_appid_attr_store, +static void package_details_release(struct config_item *item) +{ + struct package_details *package_details = to_package_details(item); + + pr_info("sdcardfs: removing %s\n", package_details->name.name); + remove_packagelist_entry(&package_details->name); + kfree(package_details->name.name); + kfree(package_details); +} + +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_ATTRIBUTE(appid), + PACKAGE_DETAILS_ATTRIBUTE(excluded_userids), + PACKAGE_DETAILS_ATTRIBUTE(clear_userid), + 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 extensions_value { struct config_group group; + unsigned int num; +}; + +struct extension_details { + struct config_item item; + struct qstr 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); + + 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); + kfree(extension_details); +} + +static struct configfs_item_operations extension_details_item_ops = { + .release = extension_details_release, }; -static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item) +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) { - return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL; + 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); + + tmp = kstrdup(name, GFP_KERNEL); + if (!tmp) { + kfree(extension_details); + return ERR_PTR(-ENOMEM); + } + qstr_init(&extension_details->name, tmp); + ret = insert_ext_gid_entry(&extension_details->name, extensions_value->num); + + if (ret) { + kfree(extension_details->name.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 config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name) +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 package_appid *package_appid; + struct extensions_value *extensions_value; + unsigned int tmp; + int ret; - package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL); - if (!package_appid) + 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); + } - config_item_init_type_name(&package_appid->item, name, - &package_appid_type); + extensions_value->num = tmp; + config_group_init_type_name(&extensions_value->group, name, + &extensions_name_type); + return &extensions_value->group; +} - package_appid->add_pid = 0; +static void extensions_drop_group(struct config_group *group, struct config_item *item) +{ + struct extensions_value *value = to_extensions_value(item); - return &package_appid->item; + pr_info("sdcardfs: No longer mapping any files to gid %d\n", value->num); + kfree(value); } -static struct configfs_attribute sdcardfs_packages_attr_description = { - .ca_owner = THIS_MODULE, - .ca_name = "packages_gid.list", - .ca_mode = S_IRUGO, +static struct configfs_group_operations extensions_group_ops = { + .make_group = extensions_make_group, + .drop_item = extensions_drop_group, }; -static struct configfs_attribute *sdcardfs_packages_attrs[] = { - &sdcardfs_packages_attr_description, - NULL, +static struct config_item_type extensions_type = { + .ct_group_ops = &extensions_group_ops, + .ct_owner = THIS_MODULE, }; -static ssize_t packages_attr_show(struct config_item *item, - struct configfs_attribute *attr, +struct config_group extension_group = { + .cg_item = { + .ci_namebuf = "extensions", + .ci_type = &extensions_type, + }, +}; + +struct packages { + struct configfs_subsystem subsystem; +}; + +static inline struct packages *to_packages(struct config_item *item) +{ + return item ? container_of(to_configfs_subsystem(to_config_group(item)), struct packages, subsystem) : NULL; +} + +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_details *package_details; + const char *tmp; + + package_details = kzalloc(sizeof(struct package_details), GFP_KERNEL); + if (!package_details) + return ERR_PTR(-ENOMEM); + 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); + + return &package_details->item; +} + +static ssize_t packages_list_show(struct packages *packages, char *page) { - struct hashtable_entry *hash_cur; - struct hlist_node *h_t; + struct hashtable_entry *hash_cur_app; + struct hashtable_entry *hash_cur_user; int i; int count = 0, written = 0; - char errormsg[] = "\n"; - - spin_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)) { + const char errormsg[] = "\n"; + unsigned int hash; + + 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.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 (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; + } + } + if (count + written == PAGE_SIZE - sizeof(errormsg) - 1) { count += scnprintf(page + count, PAGE_SIZE - count, errormsg); break; } count += written; } - spin_unlock(&pkgl_data_all->hashtable_lock); + rcu_read_unlock(); return count; } -static void sdcardfs_packages_release(struct config_item *item) +static ssize_t packages_remove_userid_store(struct packages *packages, + const char *page, size_t count) { + unsigned int tmp; + int ret; - printk(KERN_INFO "sdcardfs: destroyed something?\n"); - kfree(to_sdcardfs_packages(item)); + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + remove_userid_all_entry(tmp); + return count; } -static struct configfs_item_operations sdcardfs_packages_item_ops = { - .release = sdcardfs_packages_release, - .show_attribute = packages_attr_show, +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, +}; + +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, +struct config_group *sd_default_groups[] = { + &extension_group, + NULL, +}; + +static struct packages sdcardfs_packages = { + .subsystem = { + .su_group = { + .cg_item = { + .ci_namebuf = "sdcardfs", + .ci_type = &packages_type, + }, + .default_groups = sd_default_groups, }, }, }; static int configfs_sdcardfs_init(void) { - int ret; - struct configfs_subsystem *subsys = &sdcardfs_packages_subsys; + 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); 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); } @@ -418,7 +873,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) @@ -427,19 +882,17 @@ 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; } - pkgl_data_all = packagelist_create(); configfs_sdcardfs_init(); - return 0; + return 0; } void packagelist_exit(void) { configfs_sdcardfs_exit(); - packagelist_destroy(pkgl_data_all); - if (hashtable_entry_cachep) - kmem_cache_destroy(hashtable_entry_cachep); + packagelist_destroy(); + kmem_cache_destroy(hashtable_entry_cachep); } diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 113d722b803b..41483adc852a 100755 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -52,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 @@ -65,71 +66,87 @@ #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 -#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 - * 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. */ -#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred) \ - saved_cred = override_fsids(sdcardfs_sbi); \ - if (!saved_cred) { return -ENOMEM; } +#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \ + do { \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ + if (!saved_cred) \ + return -ENOMEM; \ + } while (0) -#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred) \ - saved_cred = override_fsids(sdcardfs_sbi); \ - if (!saved_cred) { return ERR_PTR(-ENOMEM); } +#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \ + 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 - * 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, + /* 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; 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); +void revert_fsids(const struct cred *old_cred); /* operations vectors defined in specific files */ extern const struct file_operations sdcardfs_main_fops; @@ -169,6 +186,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; @@ -187,18 +206,25 @@ 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; }; +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; 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; @@ -309,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; \ @@ -323,38 +349,78 @@ static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ SDCARDFS_DENT_FUNC(lower_path) SDCARDFS_DENT_FUNC(orig_path) -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 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) +{ + 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 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 * 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 { - return multiuser_get_uid(info->userid, sb_info->options.gid); - } + else + 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 - * 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 (sb_info->options.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)); @@ -379,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); @@ -388,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); @@ -398,21 +464,31 @@ 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 int check_caller_access_to_name(struct inode *parent_node, const char* name); +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 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; + struct qstr name; + 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 get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name); +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); @@ -422,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; } @@ -447,7 +524,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; @@ -458,7 +535,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: @@ -516,12 +593,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; @@ -530,4 +612,22 @@ 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 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); +} + +#define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) + #endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index 1d6490128c99..a3393e959c63 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); } @@ -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,14 +100,61 @@ 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; } 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) { + pr_err("sdcardfs: remount flags 0x%x unsupported\n", *flags); + err = -EINVAL; + } + 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; + 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 @@ -126,6 +173,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); } @@ -173,8 +221,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); } /* @@ -190,19 +237,25 @@ 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"); - + seq_puts(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); @@ -213,9 +266,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, 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/fs/utimes.c b/fs/utimes.c index f4fb7eca10e8..7216a079d569 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -96,13 +96,13 @@ 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; } } 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/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/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); 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; diff --git a/include/linux/fs.h b/include/linux/fs.h index 7c546b15f6b0..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) @@ -251,6 +248,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 +1333,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 */ @@ -1459,13 +1467,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. @@ -1563,13 +1578,13 @@ 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 { 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); @@ -1585,6 +1600,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); @@ -1624,9 +1640,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 *); @@ -1833,6 +1853,9 @@ 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; struct file_system_type * next; @@ -2021,6 +2044,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, @@ -2232,7 +2257,9 @@ 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); static inline bool execute_ok(struct inode *inode) 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 */ 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/kernel.h b/include/linux/kernel.h index 6802ef7149f3..0228d010f895 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)) @@ -541,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; \ \ @@ -588,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; \ \ @@ -608,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/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 */ 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/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/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 *); 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/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; 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 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 */ 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/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) 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"); diff --git a/kernel/events/core.c b/kernel/events/core.c index 3e6bfeff14d6..7d948d3b0519 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 */ @@ -6377,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); @@ -6835,6 +6841,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 * @@ -7010,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) @@ -7037,14 +7086,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); /* @@ -7086,7 +7152,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); @@ -7117,6 +7183,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); 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/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); - } } } 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/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, "<...>"); diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index a9077c1b4ad3..f423e8d551c0 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -272,7 +272,10 @@ static int t_show(struct seq_file *m, void *v) const char *str = *fmt; int i; - seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); + if (!*fmt) + return 0; + + seq_printf(m, "0x%lx : \"", 0L); /* * Tabs and new lines need to be converted. 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 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; } 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 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); 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? * 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: 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; 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); 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, 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. */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 46cef2b4613c..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); @@ -1181,7 +1187,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; } 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 { 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; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c38b79fe1f90..c0369c362e6d 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; @@ -2479,17 +2468,17 @@ 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; 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 +2516,13 @@ static int netlink_dump(struct sock *sk) if (cb->done) cb->done(cb); - nlk->cb = NULL; - mutex_unlock(nlk->cb_mutex); - module_put(cb->module); - netlink_consume_callback(cb); + nlk->cb_running = false; + module = cb->module; + skb = cb->skb; + mutex_unlock(nlk->cb_mutex); + module_put(module); + consume_skb(skb); return 0; errout_skb: @@ -2549,59 +2540,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 +2594,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 +2820,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); 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, 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; 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; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7a70a5a5671a..91a6a2903e8d 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -390,7 +390,14 @@ 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) return -EINVAL; return 0; 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; 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", }; /* diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3242195bfa95..066baa1926bb 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; } @@ -1240,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) { @@ -1266,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) { 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--; 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: 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); 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. diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c index 79d81def47f2..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)); @@ -685,6 +678,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 +690,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 +703,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 +718,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; } @@ -767,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, @@ -856,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) { @@ -1086,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; @@ -1109,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 = @@ -1193,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; @@ -1233,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) @@ -1307,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; 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; 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-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]; 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/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; } 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: 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); 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); 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; } diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index bc4a0cb86906..11a94e423c4a 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; @@ -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) { 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; } /*