diff options
-rw-r--r-- | recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/defconfig | 2785 | ||||
-rw-r--r-- | recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/kernel_af_bus.patch | 6313 | ||||
-rw-r--r-- | recipes-kernel/linux/linux-omap4_3.4.0.bb | 21 | ||||
-rw-r--r-- | recipes-kernel/linux/linux.inc | 277 |
4 files changed, 9396 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/defconfig b/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/defconfig new file mode 100644 index 0000000..7d9baa0 --- /dev/null +++ b/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/defconfig @@ -0,0 +1,2785 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.11 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_ARM_PATCH_PHYS_VIRT=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_FHANDLE is not set +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_CGROUPS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=0 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_PERF_COUNTERS=y +CONFIG_DEBUG_PERF_USE_VMALLOC=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +CONFIG_GPIO_PCA953X=y +# CONFIG_KEYBOARD_GPIO_POLLED is not set + +# +# TI OMAP Common Features +# +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_OMAP2PLUS=y + +# +# OMAP Feature Selections +# +CONFIG_OMAP_SMARTREFLEX=y +# CONFIG_OMAP_SMARTREFLEX_CLASS3 is not set +CONFIG_OMAP_SMARTREFLEX_CLASS1P5=y +CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY=86400000 +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +CONFIG_OMAP5_SEVM_PALMAS=y +CONFIG_OMAP_MUX_DEBUG=y +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MCBSP=y +CONFIG_OMAP_SCM_DEV=y +CONFIG_OMAP_MBOX_FWK=y +CONFIG_OMAP_MBOX_KFIFO_SIZE=256 +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_PM_NOOP=y +CONFIG_MACH_OMAP_GENERIC=y + +# +# TI OMAP2/3/4 Specific Features +# +CONFIG_ARCH_OMAP2PLUS_TYPICAL=y +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP3 is not set +CONFIG_ARCH_OMAP4=y +CONFIG_ARCH_OMAP5=y +CONFIG_OMAP_PACKAGE_CBL=y +CONFIG_OMAP_PACKAGE_CBS=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP_4430SDP=y +CONFIG_MACH_OMAP4_PANDA=y +CONFIG_MACH_OMAP5_SEVM=y +CONFIG_SECURE_REGS=y +CONFIG_OMAP4_ERRATA_I688=y +CONFIG_OMAP_TPS6236X=y +# CONFIG_OMAP_PM_STANDALONE is not set +# CONFIG_OMAP4_ARM_ERRATA_742230 is not set +# CONFIG_OMAP4_ARM_ERRATA_751472 is not set +# CONFIG_OMAP4_ARM_ERRATA_743622 is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +CONFIG_PL310_ERRATA_588369=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_PL310_ERRATA_727915=y +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +CONFIG_PL310_ERRATA_753970=y +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_761171=y +CONFIG_ARM_ERRATA_4668=y +CONFIG_ARM_GIC=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_ARM_SMP_TWD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=128 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="console=ttyO2,115200n8 root=/dev/mmcblk0p2 rootwait earlyprintk earlycon=ttyO2.115200n8" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_CLK_REG_CPUFREQ_DRIVER is not set + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_HAS_WAKELOCK is not set +# CONFIG_WAKELOCK is not set +# CONFIG_USER_WAKELOCK is not set +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_CAN_PM_TRACE=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_ANDROID_PARANOID_NETWORK is not set +# CONFIG_NET_ACTIVITY_STATS is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +# CONFIG_BT_BNEP_MC_FILTER is not set +# CONFIG_BT_BNEP_PROTO_FILTER is not set +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_WILINK=m +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +CONFIG_LIB80211=m +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_RC_PID is not set +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_MINSTREL_HT=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +# CONFIG_RFKILL_REGULATOR is not set +CONFIG_RFKILL_GPIO=y +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_SYNC is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=16 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_GPIO=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_VIRTIO_BLK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_UID_STAT is not set +CONFIG_DDR=y +CONFIG_EMIF=y +CONFIG_BMP085=m +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +CONFIG_TI_ST=y +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_VERBOSE_ERROR=y +# CONFIG_SATA_PMP is not set + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_SATA_MV is not set + +# +# PATA SFF controllers with BMDMA +# + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_PLATFORM is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_VIRTIO_NET is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC91X is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +# CONFIG_PHYLIB is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +CONFIG_USB_NET_SMSC95XX=m +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +CONFIG_WLAN=y +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_RTL8187 is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_WIFI_CONTROL_FUNC is not set +# CONFIG_ATH_COMMON is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_BCMDHD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTL8192CU is not set +CONFIG_WL_TI=y +# CONFIG_WL1251 is not set +CONFIG_WL12XX=m +CONFIG_WLCORE=m +CONFIG_WLCORE_SDIO=m +CONFIG_WL12XX_PLATFORM_DATA=y +# CONFIG_ZD1211RW is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +CONFIG_KEYBOARD_OMAP4=y +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_SMSC is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TI_TSCADC is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_QUANTUM_OBP=m +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +CONFIG_INPUT_TSL2771=m +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +CONFIG_INPUT_PALMAS_PWRBUTTON=y +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +CONFIG_INPUT_MPU6050=y +CONFIG_INPUT_MPU6050_I2C=y +CONFIG_INPUT_MPU6050_ACCEL=y +CONFIG_INPUT_MPU6050_GYRO=m + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_DW is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_OF_PLATFORM is not set +CONFIG_SERIAL_OMAP=y +CONFIG_SERIAL_OMAP_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X_IRQ is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +CONFIG_GPIO_TWL4030=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_GPIO_PALMAS is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +CONFIG_SENSORS_OMAP_TEMP_SENSOR=y +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +CONFIG_SENSORS_TMP102=y +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +CONFIG_OMAP4460PLUS_SCM=y +CONFIG_OMAP4460PLUS_TEMP_SENSOR=y +CONFIG_TWL4030_CORE=y +# CONFIG_TWL4030_MADC is not set +CONFIG_TWL4030_POWER=y +# CONFIG_MFD_TWL4030_AUDIO is not set +# CONFIG_TWL6030_PWM is not set +CONFIG_TWL6040_CORE=y +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_OMAP_CONTROL is not set +CONFIG_MFD_OMAP_USB_HOST=y +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_MFD_PALMAS=y +CONFIG_MFD_PALMAS_GPADC=y +CONFIG_MFD_PALMAS_RESOURCE=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +CONFIG_REGULATOR_DUMMY=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_PALMAS=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_COMMON=m +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=m + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +CONFIG_MEDIA_ATTACH=y +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEOBUF2_CORE=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_VIVI is not set +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_OMAP2_VOUT=m +CONFIG_SOC_CAMERA=m +# CONFIG_SOC_CAMERA_IMX074 is not set +# CONFIG_SOC_CAMERA_MT9M001 is not set +# CONFIG_SOC_CAMERA_MT9M111 is not set +# CONFIG_SOC_CAMERA_MT9T031 is not set +# CONFIG_SOC_CAMERA_MT9T112 is not set +# CONFIG_SOC_CAMERA_MT9V022 is not set +# CONFIG_SOC_CAMERA_RJ54N1 is not set +# CONFIG_SOC_CAMERA_TW9910 is not set +CONFIG_SOC_CAMERA_PLATFORM=m +# CONFIG_SOC_CAMERA_OV2640 is not set +CONFIG_SOC_CAMERA_OV5642=m +CONFIG_SOC_CAMERA_OV6650=m +# CONFIG_SOC_CAMERA_OV772X is not set +# CONFIG_SOC_CAMERA_OV9640 is not set +# CONFIG_SOC_CAMERA_OV9740 is not set +# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +CONFIG_DRM=y +CONFIG_DRM_KMS_HELPER=y +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_ION is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=16 +CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y +CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS=y +CONFIG_OMAP2_DSS_DPI=y +CONFIG_OMAP2_DSS_RFBI=y +CONFIG_OMAP2_DSS_VENC=y +CONFIG_OMAP4_DSS_HDMI=y +CONFIG_OMAP4_DSS_HDMI_AUDIO=y +CONFIG_OMAP5_DSS_HDMI=y +CONFIG_OMAP5_DSS_HDMI_AUDIO=y +CONFIG_OMAP2_DSS_DSI=y +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 +CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y + +# +# OMAP2/3 Display Device Drivers +# +CONFIG_PANEL_GENERIC_DPI=y +CONFIG_PANEL_TFP410=y +# CONFIG_PANEL_PICODLP is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +CONFIG_SND_DEBUG_VERBOSE=y +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_DMIC=y +CONFIG_SND_OMAP_SOC_MCBSP=y +CONFIG_SND_OMAP_SOC_MCPDM=y +CONFIG_SND_OMAP_SOC_HDMI=y +CONFIG_SND_OMAP_SOC_ABE=y +CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y +CONFIG_SND_OMAP_SOC_SDP4430=y +CONFIG_SND_OMAP_SOC_OMAP_HDMI=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_DMIC=y +CONFIG_SND_SOC_OMAP_HDMI_CODEC=y +CONFIG_SND_SOC_TWL6040=y +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_XHCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_DWC3=m +# CONFIG_USB_DWC3_DEBUG is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=m +# CONFIG_USB_XHCI_HCD_DEBUGGING is not set +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_HCD_OMAP=y +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_MUSB_HDRC=m +# CONFIG_USB_MUSB_TUSB6010 is not set +CONFIG_USB_MUSB_OMAP2PLUS=m +# CONFIG_USB_MUSB_AM35X is not set +CONFIG_USB_INVENTRA_DMA=y +# CONFIG_MUSB_PIO_ONLY is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +# CONFIG_USB_FUSB300 is not set +CONFIG_USB_OMAP=m +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +CONFIG_USB_GADGET_MUSB_HDRC=m +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_GADGET_SUPERSPEED=y +CONFIG_USB_ZERO=m +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +CONFIG_USB_MASS_STORAGE=m +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_TWL4030_USB=y +CONFIG_TWL6030_USB=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_PALMAS_USB is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_OMAP is not set +CONFIG_MMC_OMAP_HS=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGER_TIMER is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_SWITCH is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_TWL4030=y +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +CONFIG_VIRTIO=y +CONFIG_VIRTIO_RING=y + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +CONFIG_VIRTIO_MMIO=y + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_W35UND is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_DRM_OMAP=y +CONFIG_DRM_OMAP_NUM_CRTCS=2 +CONFIG_RPC_OMAP=m + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set +CONFIG_THERMAL_FRAMEWORK=y +CONFIG_OMAP_THERMAL=y +CONFIG_OMAP_DIE_GOVERNOR=y +CONFIG_OMAP_GPU_GOVERNOR=y +CONFIG_DRM_OMAP_DCE=m +# CONFIG_OMAP_RPMSG_RDAEMON is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HWSPINLOCK=y + +# +# Hardware Spinlock drivers +# +CONFIG_HWSPINLOCK_OMAP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_OMAP_IOMMU=y +CONFIG_OMAP_IOVMM=y +# CONFIG_OMAP_IOMMU_DEBUG is not set + +# +# Remoteproc drivers (EXPERIMENTAL) +# +CONFIG_REMOTEPROC=m +CONFIG_OMAP_REMOTEPROC=m +CONFIG_OMAP_REMOTEPROC_IPU=y +CONFIG_OMAP_REMOTEPROC_DSP=y +CONFIG_OMAP_REMOTEPROC_WATCHDOG=y +CONFIG_OMAP4_IPU_CMA_SIZE=0x7000000 +CONFIG_OMAP5_IPU_CMA_SIZE=0xA400000 +CONFIG_OMAP_DSP_CMA_SIZE=0x700000 + +# +# Rpmsg drivers (EXPERIMENTAL) +# +CONFIG_RPMSG=m +CONFIG_RPMSG_RESMGR_FWK=m +CONFIG_RPMSG_RESMGR=m +CONFIG_OMAP_RPMSG_RESMGR=m +CONFIG_RPMSG_OMX=m +CONFIG_VIRT_DRIVERS=y +# CONFIG_PM_DEVFREQ is not set +CONFIG_GATOR=m +CONFIG_STM_FW=y +# CONFIG_STM_OMAP_TI1_0 is not set +CONFIG_STM_ARM=y + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +CONFIG_ROOT_NFS=y +CONFIG_NFS_USE_LEGACY_DNS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_DYNAMIC_FTRACE=y +# CONFIG_FUNCTION_PROFILER is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +CONFIG_OLD_MCOUNT=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_RODATA is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_NONE=y +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +CONFIG_EARLY_PRINTK=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set + +#config required by systemd +CONFIG_CGROUPS=y diff --git a/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/kernel_af_bus.patch b/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/kernel_af_bus.patch new file mode 100644 index 0000000..9ef0452 --- /dev/null +++ b/recipes-kernel/linux/linux-omap4-3.4.0/pandaboard/kernel_af_bus.patch @@ -0,0 +1,6313 @@ +From 8c071e4a4be17b7bb01ab2a911c1697902dc2c35 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas <javier.martinez@collabora.co.uk> +Date: Wed, 20 Jun 2012 12:07:49 +0200 +Subject: [PATCH 1/1] net: bus: add the AF_BUS socket address family + +AF_BUS is a new socket address family that allows both unicast and +multicast I on a local machine with total ordering for messages +(every process on the same bus sees each message in the same order). + +A process can create buses to which other processes can connect and +communicate with each other by sending messages. Processes' addresses are +automatically assigned by the bus on connect and are unique. Messages can +be sent either to process' unique address or to a bus multicast address. + +Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> + +Index: git/Documentation/networking/af_bus.patch +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/Documentation/networking/af_bus.patch 2012-10-05 12:54:51.000000000 +0300 +@@ -0,0 +1,558 @@ ++ The AF_BUS socket address family ++ ================================ ++ ++Introduction ++------------ ++ ++AF_BUS is a message oriented inter process communication system. ++ ++The principle features are: ++ ++ - Reliable datagram based communication (all sockets are of type ++ SOCK_SEQPACKET) ++ ++ - Multicast message delivery (one to many, unicast as a subset) ++ ++ - Strict ordering (messages are delivered to every client in the same order) ++ ++ - Ability to pass file descriptors ++ ++ - Ability to pass credentials ++ ++The basic concept is to provide a virtual bus on which multiple ++processes can communicate and policy is imposed by a "bus master". ++ ++A process can create buses to which other processes can connect and ++communicate with each other by sending messages. Processes' addresses ++are automatically assigned by the bus on connect and are ++unique. Messages can be sent either to a process' unique address or to ++a bus multicast addresses. ++ ++Netfilter rules or Berkeley Packet Filter can be used to restrict the ++messages that each peer is allowed to receive. This is especially ++important when sending to multicast addresses. ++ ++Besides messages, process can send and receive ancillary data (i.e., ++SCM_RIGHTS for passing file descriptors or SCM_CREDENTIALS for passing ++Unix credentials). In the case of a multicast message all recipients ++of a message may obtain a copy a file descriptor or credentials. ++ ++A bus is created by processes connecting on an AF_BUS socket. The ++"bus master" binds itself instead of connecting to the NULL address. ++ ++The socket address is made up of a path component and a numeric ++component. The path component is either a pathname or an abstract ++socket similar to a unix socket. The numeric component is used to ++uniquely identify each connection to the bus. Thus the path identifies ++a specific bus and the numeric component the attachment to that bus. ++ ++The process that calls bind(2) on the socket is the owner of the bus ++and is called the bus master. The master is a special client of the ++bus and has some responsibility for the bus' operation. The master is ++assigned a fixed address with all the bits zero (0x0000000000000000). ++ ++Each process connected to an AF_BUS socket has one or more addresses ++within that bus. These addresses are 64-bit unsigned integers, ++interpreted by splitting the address into two parts: the most ++significant 16 bits are a prefix identifying the type of address, and ++the remaining 48 bits are the actual client address within that ++prefix, as shown in this figure: ++ ++Bit: 0 15 16 63 ++ +----------------+------------------------------------------------+ ++ | Type prefix | Client address | ++ +----------------+------------------------------------------------+ ++ ++The prefix with all bits zero is reserved for use by the kernel, which ++automatically assigns one address from this prefix to each client on ++connection. The address in this prefix with all bits zero is always ++assigned to the bus master. Addresses on the prefix 0x0000 are unique ++and will never repeat for the lifetime of the bus master. ++ ++A client may have multiple addresses. When data is sent to other ++clients, those clients will always see the sender address that is in ++the prefix 0x0000 address space when calling recvmsg(2) or ++recvfrom(2). Similarly, the prefix 0x0000 address is returned by calls ++to getsockname(2) and getpeername(2). ++ ++For each prefix, the address where the least significant 48 bits are ++all 1 (i.e., 0xffffffffffff) is also reserved, and can be used to send ++multicast messages to all the peers on a prefix. ++ ++The non-reserved addresses in each of the remaining prefixes are ++managed by the bus master, which may assign additional addresses to ++any other connected socket. ++ ++Having different name-spaces has two advantages: ++ ++ - Clients can have addresses on different mutually-exclusive ++ scopes. This permits sending multicast packets to only clients ++ that have addresses on a given prefix. ++ ++ - The addressing scheme can be more flexible. The kernel will only ++ assign unique addresses on the all-bits-zero prefix (0x0000) and ++ allows the bus master process to assign additional addresses to ++ clients on other prefixes. By having different prefixes, the ++ kernel and bus master assignments will not collide. ++ ++AF_BUS transport can support two network topologies. When a process ++first connects to the bus master, it can only communicate with the bus ++master. The process can't send and receive packets from other peers on ++the bus. So, from the client process point of view the network ++topology is point-to-point. ++ ++The bus master can allow the connected peer to be part of the bus and ++start to communicate with other peers by setting a socket option with ++the setsockopt(2) system call using the accepted socket descriptor. At ++this point, the topology becomes a bus to the client process. ++ ++Packets whose destination address is not assigned to any client are ++routed by default to the bus master (the client accepted socket ++descriptor). ++ ++ ++Semantics ++--------- ++ ++Bus features: ++ ++ - Unicast and multicast addressing scheme. ++ - Ability to assign addresses from user-space with different prefixes. ++ - Automatic address assignment. ++ - Ordered packets delivery (FIFO, total ordering). ++ - File descriptor and credentials passing. ++ - Support for both point-to-point and bus network topologies. ++ - Bus control access managed from user-space. ++ - Netfilter hooks for packet sending, routing and receiving. ++ ++A process (the "bus master") can create an AF_BUS bus with socket(2) ++and use bind(2) to assign an address to the bus. Then it can listen(2) ++on the created socket to start accepting incoming connections with ++accept(2). ++ ++Processes can connect to the bus by creating a socket with socket(2) ++and using connect(2). The kernel will assign a unique address to each ++connection and messages can be sent and received by using BSD socket ++primitives. ++ ++This uses the connect(2) semantic in a non-traditional way, with ++AF_BUS sockets, it's not possible to connect "my" socket to a specific ++peer socket whereas the traditional BSD sockets API usage, connect(2) ++either connects to stream sockets, or assigns a peer address to a ++datagram socket (so that send(2) can be used instead of sendto()). ++ ++An AF_BUS socket address is represented as a combination of a bus ++address and a bus path name. Address are unique within a path. The ++unique bus address is further subdivided into a prefix and a client ++address. Thus the path identifies a specific bus and the numeric ++component the attachment to that bus. ++ ++#define BUS_PATH_MAX 108 ++ ++/* Bus address */ ++struct bus_addr { ++ uint64_t s_addr; /* 16-bit prefix + 48-bit client address */ ++}; ++ ++/* Structure describing an AF_BUS socket address. */ ++struct sockaddr_bus { ++ sa_family_t sbus_family; /* AF_BUS */ ++ struct bus_addr sbus_addr; /* bus address */ ++ char sbus_path[BUS_PATH_MAX]; /* pathname */ ++}; ++ ++A process becomes a bus master for a given struct sockaddr_bus by ++calling bind(2) on an AF_BUS addresses. The argument must be { AF_BUS, ++0, path }. ++ ++AF_BUS supports both abstract and non-abstract path names. Abstract ++names are distinguished by the fact that sbus_path[0] == '\0' and they ++don't represent file system paths while non-abstract paths are bound ++to a file system path name. (See the unix(7) man page for a discussion ++of abstract socket addresses in the AF_UNIX address family.) ++ ++Then the process calls listen(2) to accept incoming connections. If ++that process calls getsockname(2), the returned address will be { ++AF_BUS, 0, path }. ++ ++The conventional string form of the full address is path + ":" + ++prefix + "/" + client address. Prefix and client address are ++represented in hex. ++ ++For example the address: ++ ++struct sockaddr_bus addr; ++addr.sbus_family = AF_BUS; ++strcpy(addr.sbus_path, "/tmp/test"); ++addr.sbus_addr.s_addr = 0x0002f00ddeadbeef; ++ ++would be represented using the string /tmp/test:0002/f00ddeadbeef. ++ ++If the bus_addr is 0, then both the prefix and client address may be ++omitted from the string form. To connect to a bus as a client it is ++sufficient to specify the path, since the listening address always has ++bus_addr == 0. it is not meanigful to specify 'bus_addr' as other than ++0 on connect() ++ ++The AF_BUS implementation will automatically assign a unique address ++to each client but the bus master can assign additional addresses on a ++different prefix by means of the setsockopt(2) system call. For ++example: ++ ++struct bus_addr addr; ++addr.s_addr = 0x0001deadfee1dead; ++ret = setsockopt(afd, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)); ++ ++where afd is the accepted socket descriptor in the daemon. To show graphically: ++ ++ L The AF_BUS listening socket } ++ / | \ }-- listener process ++ A1 A2 A3 The AF_BUS accepted sockets } ++ | | | ++ C1 C2 C3 The AF_BUS connected sockets }-- client processes ++ ++So if setsockopt(A1, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)) is ++called, C1 will get the new address. ++ ++The inverse operation is BUS_DEL_ADDR, which the bus master can use to ++remove a client socket AF_BUS address: ++ ++ret = setsockopt(afd, SOL_BUS, BUS_DEL_ADDR, &addr, sizeof(addr)); ++ ++Besides assigning additional addresses, the bus master has to allow a ++client process to communicate with other peers on the bus using a ++setsockopt(2): ++ ++ret = setsockopt(afd, SOL_BUS, BUS_JOIN_BUS, NULL, 0); ++ ++Clients are not meant to send messages to each other until the master ++tells them (in a protocol-specific way) that the BUS_JOIN_BUS ++setsockopt(2) call was made. ++ ++If a client sends a message to a destination other than the bus ++master's all-zero address before joining the bus, a EHOSTUNREACH (No ++route to host) error is returned since the only host that exists in ++the point-to-point network before the client joins the bus are the ++client and the bus master. ++ ++A EHOSTUNREACH is returned if a client that joined a bus tries to send ++a packet to a client from another bus. Cross-bus communication is not ++permited. ++ ++When a process wants to send a unicast message to a peer, it fills a ++sockaddr structure and performs a socket operation (i.e., sendto(2)) ++ ++struct sockaddr_bus addr; ++char *msg = "Hello world"; ++ ++addr.sbus_family = AF_BUS; ++strcpy(addr.sbus_path, "/tmp/test"); ++addr.sbus_addr.s_addr = 0x0001f00ddeadbeef; ++ ++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0, ++ (struct sockaddr*)&addr, sizeof(addr)); ++ ++The current implementation requires that the addr.sbus_path component ++match the one used to conenct() to the bus but in future this ++requirement will be removed. ++ ++The kernel will first check that the socket is connected and that the ++bus path of the socket correspond with the destination, then it will ++extract the prefix and client address from the bus address using a ++fixed 16 -bit bitmask. ++ ++prefix = bus address >> 48 & 0xffff ++client address = bus address & 0xffff ++ ++If the client address is not all bits one, then the message is unicast ++and is delivered to the socket with that assigned address ++(0x0001f00ddeadbeef). Otherwise the message is multicast and is ++delivered to all the peers with this address prefix (0x0001 in this ++case). ++ ++So, when a process wants to send a multicast message, it just has to ++fill the address structure with the address prefix + 0xffffffffffff: ++ ++struct sockaddr_bus addr; ++char *msg = "Hello world"; ++ ++addr.bus_family = AF_BUS; ++strcpy(addr.sbus_path, "/tmp/test"); ++addr.bus_addr = 0x0001ffffffffffff; ++ ++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0, ++ (struct sockaddr*)&addr, sizeof(addr)); ++ ++The kernel, will apply the binary and operation, learn that the ++address is 0xffffffffffff and send the message to all the peers on ++this prefix (0x0001). ++ ++Socket transmit queued bytes are limited by a maximum send buffer size ++(sysctl_wmem_max) defined in the kernel and can be modified at runtime ++using the sysctl interface on /proc/sys/net/core/wmem_default. This ++parameter is global for all the sockets families in a Linux system. ++ ++AF_BUS permits the definition of a per-bus maximum send buffer size ++using the BUS_SET_SENDBUF socket option. The bus master can call the ++setsockopt(2) system call using as a parameter the listening socket. ++The command sets a maximum write buffer that will be imposed on each ++new socket that connects to the bus: ++ ++ret = setsockopt(serverfd, SOL_BUS, BUS_SET_SENDBUF, &sndbuf, ++sizeof(int)); ++ ++In the transmission path both Berkeley Packet Filters and Netfilter ++hooks are available, so they can be used to filter sending packets. ++ ++ ++Using this addressing scheme with D-Bus ++--------------------------------------- ++ ++As an example of a use case for AF_BUS, let's analyze how the D-Bus ++IPC system can be implemented on top of it. ++ ++We define a new D-Bus address type "afbus". ++ ++A D-Bus client may connect to an address of the form "afbus:path=X" ++where X is a string. This means that it connect()s to { AF_BUS, 0, X }. ++ ++For example: afbus:path=/tmp/test connects to { AF_BUS, 0, /tmp/test }. ++ ++A D-Bus daemon may listen on the address "afbus:", which means that it ++binds to { AF_BUS, 0, /tmp/test }. It will advertise an address of the ++form "afbus:path=/tmp/test" to clients, for instance via the ++--print-address option, or via dbus-launch setting the ++DBUS_SESSION_BUS_ADDRESS environment variable. For instance, "afbus:" ++is an appropriate default listening address for the session bus, ++resulting in dbus-launch setting the DBUS_SESSION_BUS_ADDRESS ++environment variable to something like ++"afbus:path=/tmp/test,guid=...". ++ ++A D-Bus daemon may listen on the address "afbus:file=/some/file", ++which means that it will do as above, then write its path into the ++given well-known file. For instance, ++"afbus:file=/run/dbus/system_bus.afbus" is an appropriate listening ++address for the system bus. Only processes with suitable privileges to ++write to that file can impersonate the system bus. ++ ++D-Bus clients wishing to connect to the well-known system bus should ++attempt to connect to afbus:file=/run/dbus/system_bus.afbus, falling ++back to unix:path=/var/run/dbus/system_bus_socket if that fails. On ++Linux systems, the well-known system bus daemon should attempt to ++listen on both of those addresses. ++ ++The D-Bus daemon will serve as bus master as well since it will be the ++process that creates and listens on the AF_BUS socket. ++ ++D-Bus clients will use the fixed bus master address (all zero bits) to ++send messages to the D-Bus daemon and the client's unique address to ++send messages to other D-Bus clients using the bus. ++ ++When initially connected, D-Bus clients will only be able to ++communicate with the D-Bus daemon and will send authentication ++information (AUTH message and SCM_CREDENTIALS ancillary ++messages). Since the D-Bus daemon is also the bus master, it can allow ++D-Bus clients to join the bus and be able to send and receive D-Bus ++messages from other peers. ++ ++On connection, the kernel will assign to each client an address in the ++prefix 0x0000. If a client attempts to send messages to clients other ++than the bus master, this is considered to be an error, and is ++prevented by the kernel. ++ ++When the D-Bus daemon has authenticated a client and determined that ++it is authorized to be on this bus, it uses a setsockopt(2) call to ++tell the kernel that this client has permission to send messages. The ++D-Bus daemon then tells the client by sending the Hello() reply that ++it has made the setsockopt(2) call and that now is able to send ++messages to other peers on the bus. ++ ++Well-known names are represented by addresses in the 0x0001, ... prefixes. ++ ++Addresses in prefix 0x0000 must be mapped to D-Bus unique names in a ++way that can't collide with unique names allocated by the dbus-daemon ++for legacy clients. ++ ++In order to be consistent with current D-Bus unique naming, the AF_BUS ++addresses can be mapped directly to D-Bus unique names, for example ++(0000/0000deadbeef to ":0.deadbeef"). Leading zeroes can be suppressed ++since the common case should be relatively small numbers (the kernel ++allocates client addresses sequentially, and machines could be ++rebooted occasionally). ++ ++By having both AF_BUS and legacy D-Bus clients use the same address ++space, the D-Bus daemon can act as a proxy between clients and can be ++sure that D-Bus unique names will be unique for both AF_BUS and legacy ++clients. ++ ++To act as a proxy between AF_BUS and legacy clients, each time the ++D-Bus daemon accepts a legacy connection (i.e., AF_UNIX), it will ++create an AF_BUS socket and establish a connection with itself. It ++will then associate this newly created connection with the legacy one. ++ ++To explain it graphically: ++ ++ L The AF_BUS listening socket } ++ / | \ }-- listener process ++ A1 A2 A3 The AF_BUS accepted sockets } ++ | | | ++ C1 C2 C3 The AF_BUS connected sockets, where: ++ | * C1 belongs to the listener process ++ | * C2 and C3 belongs to the client processes ++ | ++ L2--A4 The AF_UNIX listening and accepted sockets \ ++ | in the listener process ++ C4 The AF_UNIX connected socket in the legacy client process ++ ++ ++where C2 and C3 are normal AF_BUS clients and C4 is a legacy ++client. The D-Bus daemon after accepting the connection using the ++legacy transport (A4), will create an AF_BUS socket pair (C1, A1) ++associated with the legacy client. ++ ++Legacy clients will send messages to the D-Bus daemon using their ++legacy socket and the D-Bus daemon will extract the destination ++address, resolve to the corresponding AF_BUS address and use this to ++send the message to the right peer. ++ ++Conversely, when an AF_BUS client sends a D-Bus message to a legacy ++client, it will use the AF_BUS address of the connection associated ++with that client. The D-Bus daemon will receive the message, modify ++the message's content to set SENDER headers based on the AF_BUS source ++address and use the legacy transport to send the D-Bus message to the ++legacy client. ++ ++As a special case, the bus daemon's all-zeroes address maps to ++"org.freedesktop.DBus" and vice versa. ++ ++When a D-Bus client receives an AF_BUS message from the bus master ++(0/0), it must use the SENDER header field in the D-Bus message, as ++for any other D-Bus transport, to determine whether the message is ++actually from the D-Bus daemon (the SENDER is "org.freedesktop.DBus" ++or missing), or from another client (the SENDER starts with ":"). It ++is valid for messages from another AF_BUS client to be received via ++the D-Bus daemon; if they are, the SENDER header field will always be ++set. ++ ++Besides its unique name, D-Bus services can have well-known names such ++as org.gnome.Keyring or org.freedesktop.Telepathy. These well-known ++names can also be used as a D-Bus message destination ++address. Well-known names are not numeric and AF_BUS is not able to ++parse D-Bus messages. ++ ++To solve this, the D-Bus daemon will assign an additional AF_BUS ++address to each D-Bus client that owns a well-known name. The mapping ++between well-known names and AF_BUS address is maintained by the D-Bus ++daemon on a persistent data structure. ++ ++D-Bus client libraries will maintain a cache of these mappings so they ++can send messages to services with well-known names using their mapped ++AF_BUS address. ++ ++If a client intending to send a D-Bus message to a given well-known ++name does not have that well-known name in its cache, it must send the ++AF_BUS message to the listener (0000/000000000000) instead. ++ ++The listener must forward the D-Bus message to the owner of that ++well-known name, setting the SENDER header field if necessary. It may ++also send this AF_BUS-specific D-Bus signal to the sender, so that the ++sender can update its cache: ++ ++ org.freedesktop.DBus.AF_BUS.Forwarded (STRING well_known_name, ++ UINT64 af_bus_client) ++ ++ Emitted by the D-Bus daemon with sender "org.freedesktop.DBus" ++ and object path "/org/freedesktop/DBus" to indicate that ++ the well-known name well_known_name is represented by the ++ AF_BUS address { AF_BUS, af_bus_client, path } where ++ path is the path name used by this bus. ++ ++ For instance, if the well-known name "org.gnome.Keyring" ++ is represented by AF_BUS address 0001/0000deadbeef, ++ the signal would have arguments ("org.gnome.Keyring", ++ 0x00010000deadbeef), corresponding to the AF_BUS ++ address { AF_BUS, 0x00010000deadbeef, /tmp/test }. ++ ++If the D-Bus service for that well-known name is not active, then the ++D-Bus daemon will first do the service activation, assign an ++additional address to the recently activated service, store the ++well-known service to numeric address mapping on its persistent cache, ++and then send the AF_BUS.Forwarded signal back to the client. ++ ++Once the mapping has been made, the AF_BUS address associated with a ++well-known name cannot be reused for the lifetime of the D-Bus daemon ++(which is the same as the lifetime of the socket). ++ ++Nevertheless the AF_BUS address associated with a well-known name can ++change, for example if a service goes away and a new instance gets ++activated. This new instance can have a different AF_BUS address. The ++D-Bus daemon will maintain a list of the mappings that are currently ++valid so it can send the AF_BUS. ++ ++Forwarded signal with the mapping information to the clients. Client ++libraries will maintain a fixed-size Last Recently Used (LRU) cache ++with previous mappings sent by the D-Bus daemon. ++ ++If the clients overwrite a mapping due to the LRU replace policy and ++later want to send a D-Bus message to the overwritten well-known name, ++they will send the D-Bus message back to the D-Bus daemon and this ++will send the signal with the mapping information. ++ ++If a service goes away or if the service AF_BUS address changed and ++the client still has the old AF_BUS address in its cache, it will send ++the D-Bus message to the old destination. ++ ++Since packets whose destination AF_BUS addresses are not assigned to ++any process are routed by default to the bus master, the D-Bus daemon ++will receive these D-bus messages and send an AF_BUS. ++ ++Forwarded signal back to the client with the new AF_BUS address so it ++can update its cache with the new mapping. ++ ++For well-known names, the D-Bus daemon will use a different address ++prefix (0x0001) so it doesn't conflict with the D-Bus unique names ++address prefix (0x0000). ++ ++Besides D-Bus method call messages which are unicast, D-Bus allows ++clients to send multicast messages (D-Bus signals). Clients can send ++signals messages using the bus unique name prefix multicast address ++(0x0001ffffffffffff). ++ ++A netfilter hook is used to filter these multicast messages and only ++deliver to the correct peers based on match rules. ++ ++ ++D-Bus aware netfilter module ++---------------------------- ++ ++AF_BUS is designed to be a generic bus transport supporting both ++unicast and multicast communications. ++ ++In order for D-Bus to operate efficiently, the transport method has to ++know the D-Bus message wire-protocol and D-Bus message structure. But ++adding this D-Bus specific knowledge to AF_BUS will break one of the ++fundamental design principles of any network protocol stack, namely ++layer-independence: layer n must not make any assumptions about the ++payload in layer n + 1. ++ ++So, in order to have a clean protocol design but be able to allow the ++transport to analyze the D-Bus messages, netfilter hooks are used to ++do the filtering based on match rules. ++ ++The kernel module has to maintain the match rules and the D-Bus daemon ++is responsible for managing this information. Every time an add match ++rule message is processed by the D-Bus daemon, this will update the ++netfilter module match rules set so the netfilter hook function can ++use that information to do the match rules based filtering. ++ ++The D-Bus daemon and the netfilter module will use the generic netlink ++subsystem to do the kernel-to-user-space communication. Netlink is ++already used by most of the networking subsystem in Linux ++(iptables/netfilter, ip/routing, etc). ++ ++We enforce a security scheme so only the bus master's user ID can ++update the netfilter module match rules set. ++ ++The advantage of using the netfilter subsystem is that we decouple the ++mechanism from the policy. AF_BUS will only add a set of hook points ++and external modules will be used to enforce a given policy. +Index: git/drivers/connector/connector.c +=================================================================== +--- git.orig/drivers/connector/connector.c 2012-10-05 12:09:43.000000000 +0300 ++++ git/drivers/connector/connector.c 2012-10-05 12:56:28.000000000 +0300 +@@ -118,6 +118,38 @@ + EXPORT_SYMBOL_GPL(cn_netlink_send); + + /* +++ * Send an unicast reply from a connector callback +++ * +++ */ ++int cn_netlink_reply(struct cn_msg *msg, u32 pid, gfp_t gfp_mask) ++{ ++unsigned int size; ++struct sk_buff *skb; ++struct nlmsghdr *nlh; ++struct cn_msg *data; ++struct cn_dev *dev = &cdev; ++ ++size = NLMSG_SPACE(sizeof(*msg) + msg->len); ++ ++skb = alloc_skb(size, gfp_mask); ++if (!skb) ++return -ENOMEM; ++ ++nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh), 0); ++if (nlh == NULL) { ++kfree_skb(skb); ++return -EMSGSIZE; ++} ++ ++data = nlmsg_data(nlh); ++ ++memcpy(data, msg, sizeof(*data) + msg->len); ++ ++return netlink_unicast(dev->nls, skb, pid, 1); ++} ++EXPORT_SYMBOL_GPL(cn_netlink_reply); ++ ++/* + * Callback helper - queues work and setup destructor for given data. + */ + static int cn_call_callback(struct sk_buff *skb) +Index: git/include/linux/bus.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/include/linux/bus.h 2012-10-05 12:57:46.000000000 +0300 +@@ -0,0 +1,34 @@ ++#ifndef _LINUX_BUS_H ++#define _LINUX_BUS_H ++ ++#include <linux/socket.h> ++ ++/* 'protocol' to use in socket(AF_BUS, SOCK_SEQPACKET, protocol) */ ++#define BUS_PROTO_NONE 0 ++#define BUS_PROTO_DBUS 1 ++#define BUS_PROTO_MAX 1 ++ ++#define BUS_PATH_MAX 108 ++ ++/** ++ * struct bus_addr - af_bus address ++ * @s_addr: an af_bus address (16-bit prefix + 48-bit client address) ++ */ ++struct bus_addr { ++ u64 s_addr; ++}; ++ ++ ++/** ++ * struct sockaddr_bus - af_bus socket address ++ * @sbus_family: the socket address family ++ * @sbus_addr: an af_bus address ++ * @sbus_path: a path name ++ */ ++struct sockaddr_bus { ++ __kernel_sa_family_t sbus_family; ++ struct bus_addr sbus_addr; ++ char sbus_path[BUS_PATH_MAX]; ++}; ++ ++#endif /* _LINUX_BUS_H */ +Index: git/include/linux/connector.h +=================================================================== +--- git.orig/include/linux/connector.h 2012-10-05 12:12:18.000000000 +0300 ++++ git/include/linux/connector.h 2012-10-05 13:01:07.000000000 +0300 +@@ -44,8 +44,10 @@ + #define CN_VAL_DRBD 0x1 + #define CN_KVP_IDX 0x9 /* HyperV KVP */ + #define CN_KVP_VAL 0x1 /* queries from the kernel */ ++#define CN_IDX_NFDBUS 0xA /* netfilter D-Bus */ ++#define CN_VAL_NFDBUS 0x1 + +-#define CN_NETLINK_USERS 10 /* Highest index + 1 */ ++#define CN_NETLINK_USERS 11 /* Highest index + 1 */ + + /* + * Maximum connector's message size. +@@ -125,6 +127,7 @@ + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)); + void cn_del_callback(struct cb_id *); + int cn_netlink_send(struct cn_msg *, u32, gfp_t); ++int cn_netlink_reply(struct cn_msg *, u32, gfp_t); + + int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name, + struct cb_id *id, +Index: git/include/linux/netfilter.h +=================================================================== +--- git.orig/include/linux/netfilter.h 2012-10-05 12:12:19.000000000 +0300 ++++ git/include/linux/netfilter.h 2012-10-05 13:01:54.000000000 +0300 +@@ -67,6 +67,7 @@ + NFPROTO_BRIDGE = 7, + NFPROTO_IPV6 = 10, + NFPROTO_DECNET = 12, ++ NFPROTO_BUS, + NFPROTO_NUMPROTO, + }; + +Index: git/include/linux/security.h +=================================================================== +--- git.orig/include/linux/security.h 2012-10-05 12:12:21.000000000 +0300 ++++ git/include/linux/security.h 2012-10-05 13:07:01.000000000 +0300 +@@ -1578,6 +1578,8 @@ + + #ifdef CONFIG_SECURITY_NETWORK + int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk); ++ int (*bus_connect) (struct sock *sock, struct sock *other, ++ struct sock *newsk); + int (*unix_may_send) (struct socket *sock, struct socket *other); + + int (*socket_create) (int family, int type, int protocol, int kern); +@@ -2517,6 +2519,8 @@ + #ifdef CONFIG_SECURITY_NETWORK + + int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk); ++int security_bus_connect(struct sock *sock, struct sock *other, ++ struct sock *newsk); + int security_unix_may_send(struct socket *sock, struct socket *other); + int security_socket_create(int family, int type, int protocol, int kern); + int security_socket_post_create(struct socket *sock, int family, +@@ -2564,6 +2568,13 @@ + return 0; + } + ++static inline int security_bus_connect(struct socket *sock, ++ struct sock *other, ++ struct sock *newsk) ++{ ++return 0; ++} ++ + static inline int security_unix_may_send(struct socket *sock, + struct socket *other) + { +Index: git/include/linux/socket.h +=================================================================== +--- git.orig/include/linux/socket.h 2012-10-05 12:12:21.000000000 +0300 ++++ git/include/linux/socket.h 2012-10-05 13:11:59.000000000 +0300 +@@ -196,7 +196,8 @@ + #define AF_ALG 38 /* Algorithm sockets */ + #define AF_NFC 39 /* NFC sockets */ + #define AF_RPMSG 40 /* Remote-processor messaging */ +-#define AF_MAX 41 /* For now.. */ ++#define AF_BUS 41/* BUS sockets*/ ++#define AF_MAX 42/* For now.. */ + + /* Protocol families, same as address families. */ + #define PF_UNSPEC AF_UNSPEC +@@ -239,6 +240,7 @@ + #define PF_CAIF AF_CAIF + #define PF_ALG AF_ALG + #define PF_NFC AF_NFC ++#define PF_BUS AF_BUS + #define PF_RPMSG AF_RPMSG + #define PF_MAX AF_MAX + +@@ -315,6 +317,7 @@ + #define SOL_CAIF 278 + #define SOL_ALG 279 + #define SOL_RPMSG 280 ++#define SOL_BUS 281 + + /* IPX options */ + #define IPX_TYPE 1 +Index: git/include/net/af_bus.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/include/net/af_bus.h 2012-10-05 13:18:00.000000000 +0300 +@@ -0,0 +1,273 @@ ++/* ++ * Copyright (c) 2012, GENIVI Alliance ++ * ++ * Authors: Javier Martinez Canillas, <javier.martinez@collabora.co.uk> ++ * Alban Crequy, <alban.crequy@collabora.co.uk> ++ * ++ * 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 the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Based on BSD Unix domain sockets (net/unix). ++ */ ++ ++#ifndef __LINUX_NET_AFBUS_H ++#define __LINUX_NET_AFBUS_H ++ ++#include <linux/socket.h> ++#include <linux/bus.h> ++#include <linux/mutex.h> ++#include <net/sock.h> ++#include <net/tcp_states.h> ++ ++extern void bus_inflight(struct file *fp); ++extern void bus_notinflight(struct file *fp); ++extern void bus_gc(void); ++extern void wait_for_bus_gc(void); ++extern struct sock *bus_get_socket(struct file *filp); ++extern struct sock *bus_peer_get(struct sock *); ++ ++#define BUS_HASH_SIZE 256 ++ ++extern spinlock_t bus_address_lock; ++extern struct hlist_head bus_address_table[BUS_HASH_SIZE]; ++ ++#define BUS_MAX_QLEN 10 ++#define BUS_MASTER_ADDR 0x0 ++#define BUS_PREFIX_BITS 16 ++#define BUS_CLIENT_BITS 48 ++#define BUS_PREFIX_MASK 0xffff000000000000 ++#define BUS_CLIENT_MASK 0x0000ffffffffffff ++ ++/* AF_BUS socket options */ ++#define BUS_ADD_ADDR 1 ++#define BUS_JOIN_BUS 2 ++#define BUS_DEL_ADDR 3 ++#define BUS_SET_EAVESDROP 4 ++#define BUS_UNSET_EAVESDROP 5 ++#define BUS_SET_SENDBUF 6 ++#define BUS_SET_MAXQLEN 7 ++#define BUS_GET_QLENFULL 8 ++ ++/* Connection and socket states */ ++enum { ++ BUS_ESTABLISHED = TCP_ESTABLISHED, ++ BUS_CLOSE = TCP_CLOSE, ++ BUS_LISTEN = TCP_LISTEN, ++ BUS_MAX_STATES ++}; ++ ++#define NF_BUS_SENDING 1 ++ ++extern unsigned int bus_tot_inflight; ++extern spinlock_t bus_table_lock; ++extern struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1]; ++ ++/** ++ * struct bus_address - an af_bus address associated with an af_bus sock ++ * @refcnt: address reference counter ++ * @len: address length ++ * @hash: address hash value ++ * @addr_node: member of struct bus_sock.addr_list ++ * @table_node: member of struct hlist_head bus_address_table[hash] ++ * @sock: the af_bus sock that owns this address ++ * @name: the socket address for this address ++ */ ++struct bus_address { ++ atomic_t refcnt; ++ int len; ++ unsigned hash; ++ struct hlist_node addr_node; ++ struct hlist_node table_node; ++ struct sock *sock; ++ struct sockaddr_bus name[0]; ++}; ++ ++/** ++ * struct bus_send_context - sending context for an socket buffer ++ * @sender_socket: the sender socket associated with this sk_buff ++ * @siocb: used to send ancillary data ++ * @timeo: sending timeout ++ * @max_level: file descriptor passing maximum recursion level ++ * @namelen: length of socket address name ++ * @hash: socket name hash value ++ * @other: destination sock ++ * @sender: sender socket address name ++ * @recipient: recipient socket address name ++ * @authenticated: flag whether the sock already joined the bus ++ * @bus_master_side: flag whether the sock is an accepted socket ++ * @to_master: flag whether the destination is the bus master ++ * @multicast: flag whether the destination is a multicast address ++ * @deliver: flag whether the skb has to be delivered ++ * @eavesdropper: flag whether the sock is allowed to eavesdrop ++ * @main_recipient: flag whether the sock is the main recipient ++ */ ++struct bus_send_context { ++ struct socket *sender_socket; ++ struct sock_iocb *siocb; ++ long timeo; ++ int max_level; ++ int namelen; ++ unsigned hash; ++ struct sock *other; ++ struct sockaddr_bus *sender; ++ struct sockaddr_bus *recipient; ++ unsigned int authenticated:1; ++ unsigned int bus_master_side:1; ++ unsigned int to_master:1; ++ unsigned int multicast:1; ++ unsigned int deliver:1; ++ unsigned int eavesdropper:1; ++ unsigned int main_recipient:1; ++}; ++ ++/** ++ * struct bus_skb_parms - socket buffer parameters ++ * @pid: process id ++ * @cred: skb credentials ++ * @fp: passed file descriptors ++ * @secid: security id ++ * @sendctx: skb sending context ++ */ ++struct bus_skb_parms { ++ struct pid *pid; ++ const struct cred *cred; ++ struct scm_fp_list *fp; ++#ifdef CONFIG_SECURITY_NETWORK ++ u32 secid; ++#endif ++ struct bus_send_context *sendctx; ++}; ++ ++#define BUSCB(skb) (*(struct bus_skb_parms *)&((skb)->cb)) ++#define BUSSID(skb) (&BUSCB((skb)).secid) ++ ++#define bus_state_lock(s) spin_lock(&bus_sk(s)->lock) ++#define bus_state_unlock(s) spin_unlock(&bus_sk(s)->lock) ++#define bus_state_lock_nested(s) \ ++ spin_lock_nested(&bus_sk(s)->lock, \ ++ SINGLE_DEPTH_NESTING) ++ ++/** ++ * struct bus - a communication bus ++ * @master: the bus master sock ++ * @peers: list of struct bus_sock.bus_node allowed to join the bus ++ * @lock: protect peers concurrent access ++ * @send_lock: enforce atomic multicast delivery ++ * @kref: bus reference counter ++ * @addr_cnt: address number counter to assign prefix 0x0000 addresses ++ * @eavesdropper_cnt: eavesdroppers counter ++ */ ++struct bus { ++ struct sock *master; ++ struct hlist_head peers; ++ spinlock_t lock; ++ spinlock_t send_lock; ++ struct kref kref; ++ atomic64_t addr_cnt; ++ atomic64_t eavesdropper_cnt; ++}; ++ ++/** ++ * struct bus_sock - an af_bus socket ++ * @sk: associated sock ++ * @addr: sock principal address ++ * @addr_list: list of struct bus_address.addr_node ++ * @path: sock path name ++ * @readlock: protect from concurrent reading ++ * @peer: peer sock ++ * @other: the listening sock ++ * @link: list of candidates for garbage collection ++ * @inflight: number of times the file descriptor is in flight ++ * @lock: protect the sock from concurrent access ++ * @gc_candidate: flag whether the is a candidate for gc ++ * @gc_maybe_cycle: flag whether could be a cyclic reference ++ * @recursion_level: file passing current recursion level ++ * @peer_wq: peer sock wait queue ++ * @bus: bus that this sock belongs to ++ * @bus_master: flag whether the sock is the bus master ++ * @bus_master_side: flag whether is an accepted socket ++ * @authenticated: flag whether the sock joined the bus ++ * @eavesdropper: flag whether the sock is allowed to eavesdrop ++ * @bus_node: member of struct bus.peers list of joined socks ++ */ ++struct bus_sock { ++ /* WARNING: sk has to be the first member */ ++ struct sock sk; ++ struct bus_address *addr; ++ struct hlist_head addr_list; ++ struct path path; ++ struct mutex readlock; ++ struct sock *peer; ++ struct sock *other; ++ struct list_head link; ++ atomic_long_t inflight; ++ spinlock_t lock; ++ unsigned int gc_candidate:1; ++ unsigned int gc_maybe_cycle:1; ++ unsigned char recursion_level; ++ struct socket_wq peer_wq; ++ struct bus *bus; ++ bool bus_master; ++ bool bus_master_side; ++ bool authenticated; ++ bool eavesdropper; ++ struct hlist_node bus_node; ++}; ++#define bus_sk(__sk) ((struct bus_sock *)__sk) ++ ++#define peer_wait peer_wq.wait ++ ++/** ++ * bus_same_bus - Test if two socket address belongs to the same bus ++ * @sbusaddr1: socket address name ++ * @sbusaddr2: socket address name ++ */ ++static inline bool bus_same_bus(struct sockaddr_bus *sbusaddr1, ++ struct sockaddr_bus *sbusaddr2) ++{ ++ int offset; ++ ++ if (sbusaddr1->sbus_path[0] != sbusaddr2->sbus_path[0]) ++ return false; ++ ++ /* ++ * abstract path names start with a null byte character, ++ * so they have to be compared starting at the second char. ++ */ ++ offset = (sbusaddr1->sbus_path[0] == '\0'); ++ ++ return !strncmp(sbusaddr1->sbus_path + offset, ++ sbusaddr2->sbus_path + offset, ++ BUS_PATH_MAX); ++} ++ ++static inline unsigned int bus_hash_fold(__wsum n) ++{ ++ unsigned int hash = (__force unsigned int)n; ++ hash ^= hash>>16; ++ hash ^= hash>>8; ++ return hash&(BUS_HASH_SIZE-1); ++} ++ ++static inline unsigned int bus_compute_hash(struct bus_addr addr) ++{ ++ return bus_hash_fold(csum_partial((void *)&addr, sizeof(addr), 0)); ++} ++ ++long bus_inq_len(struct sock *sk); ++long bus_outq_len(struct sock *sk); ++ ++#ifdef CONFIG_SYSCTL ++extern int bus_sysctl_register(struct net *net); ++extern void bus_sysctl_unregister(struct net *net); ++#else ++static inline int bus_sysctl_register(struct net *net) { return 0; } ++static inline void bus_sysctl_unregister(struct net *net) {} ++#endif ++ ++bool bus_can_write(struct net *net, struct sockaddr_bus *addr, int len, ++ int protocol); ++ ++#endif /* __LINUX_NET_AFBUS_H */ +Index: git/net/Kconfig +=================================================================== +--- git.orig/net/Kconfig 2012-10-05 12:12:33.000000000 +0300 ++++ git/net/Kconfig 2012-10-05 13:18:58.000000000 +0300 +@@ -47,6 +47,7 @@ + + source "net/packet/Kconfig" + source "net/unix/Kconfig" ++source "net/bus/Kconfig" + source "net/xfrm/Kconfig" + source "net/iucv/Kconfig" + +Index: git/net/Makefile +=================================================================== +--- git.orig/net/Makefile 2012-10-05 12:12:33.000000000 +0300 ++++ git/net/Makefile 2012-10-05 13:19:47.000000000 +0300 +@@ -19,6 +19,7 @@ + obj-$(CONFIG_INET) += ipv4/ + obj-$(CONFIG_XFRM) += xfrm/ + obj-$(CONFIG_UNIX) += unix/ ++obj-$(CONFIG_AF_BUS) += bus/ + obj-$(CONFIG_NET) += ipv6/ + obj-$(CONFIG_PACKET) += packet/ + obj-$(CONFIG_NET_KEY) += key/ +Index: git/net/bus/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/bus/Kconfig 2012-10-05 13:22:11.000000000 +0300 +@@ -0,0 +1,15 @@ ++# ++# Bus Domain Sockets ++# ++ ++config AF_BUS ++ tristate "Bus domain sockets (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ ---help--- ++ If you say Y here, you will include support for Bus domain sockets. ++ These sockets are used to create communication buses for IPC. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called bus. ++ ++ Say N unless you know what you are doing. +Index: git/net/bus/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/bus/Makefile 2012-10-05 13:22:50.000000000 +0300 +@@ -0,0 +1,7 @@ ++# ++# Makefile for the Linux bus domain socket layer. ++# ++ ++obj-$(CONFIG_AF_BUS) += af-bus.o ++ ++af-bus-y := af_bus.o garbage.o +Index: git/net/bus/af_bus.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/bus/af_bus.c 2012-10-05 13:35:20.000000000 +0300 +@@ -0,0 +1,2688 @@ ++/* ++ * Implementation of Bus domain sockets. ++ * ++ * Copyright (c) 2012, GENIVI Alliance ++ * ++ * Authors: Javier Martinez Canillas <javier.martinez@collabora.co.uk> ++ * Alban Crequy <alban.crequy@collabora.co.uk> ++ * ++ * 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 the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Based on BSD Unix domain sockets (net/unix). ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/stat.h> ++#include <linux/dcache.h> ++#include <linux/namei.h> ++#include <linux/socket.h> ++#include <linux/bus.h> ++#include <linux/fcntl.h> ++#include <linux/termios.h> ++#include <linux/sockios.h> ++#include <linux/net.h> ++#include <linux/in.h> ++#include <linux/fs.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include <net/net_namespace.h> ++#include <net/sock.h> ++#include <net/af_bus.h> ++#include <linux/proc_fs.h> ++#include <linux/seq_file.h> ++#include <net/scm.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/rtnetlink.h> ++#include <linux/mount.h> ++#include <net/checksum.h> ++#include <linux/security.h> ++ ++struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1]; ++EXPORT_SYMBOL_GPL(bus_socket_table); ++struct hlist_head bus_address_table[BUS_HASH_SIZE]; ++EXPORT_SYMBOL_GPL(bus_address_table); ++DEFINE_SPINLOCK(bus_table_lock); ++DEFINE_SPINLOCK(bus_address_lock); ++EXPORT_SYMBOL_GPL(bus_address_lock); ++static atomic_long_t bus_nr_socks; ++ ++#define bus_sockets_unbound (&bus_socket_table[BUS_HASH_SIZE]) ++ ++#define BUS_ABSTRACT(sk) (bus_sk(sk)->addr->hash != BUS_HASH_SIZE) ++ ++#ifdef CONFIG_SECURITY_NETWORK ++static void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ memcpy(BUSSID(skb), &scm->secid, sizeof(u32)); ++} ++ ++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ scm->secid = *BUSSID(skb); ++} ++#else ++static inline void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) ++{ } ++ ++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) ++{ } ++#endif /* CONFIG_SECURITY_NETWORK */ ++ ++/* ++ * SMP locking strategy: ++ * bus_socket_table hash table is protected with spinlock bus_table_lock ++ * bus_address_table hash table is protected with spinlock bus_address_lock ++ * each bus is protected by a separate spin lock. ++ * multicast atomic sending is protected by a separate spin lock. ++ * each socket state is protected by a separate spin lock. ++ * each socket address is protected by a separate spin lock. ++ * ++ * When holding more than one lock, use the following hierarchy: ++ * - bus_table_lock. ++ * - bus_address_lock. ++ * - socket lock. ++ * - bus lock. ++ * - bus send_lock. ++ * - sock address lock. ++ */ ++ ++#define bus_peer(sk) (bus_sk(sk)->peer) ++ ++static inline int bus_our_peer(struct sock *sk, struct sock *osk) ++{ ++ return bus_peer(osk) == sk; ++} ++ ++static inline int bus_recvq_full(struct sock const *sk) ++{ ++ return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; ++} ++ ++static inline u16 bus_addr_prefix(struct sockaddr_bus *busaddr) ++{ ++ return (busaddr->sbus_addr.s_addr & BUS_PREFIX_MASK) >> BUS_CLIENT_BITS; ++} ++ ++static inline u64 bus_addr_client(struct sockaddr_bus *sbusaddr) ++{ ++ return sbusaddr->sbus_addr.s_addr & BUS_CLIENT_MASK; ++} ++ ++static inline bool bus_mc_addr(struct sockaddr_bus *sbusaddr) ++{ ++ return bus_addr_client(sbusaddr) == BUS_CLIENT_MASK; ++} ++ ++struct sock *bus_peer_get(struct sock *s) ++{ ++ struct sock *peer; ++ ++ bus_state_lock(s); ++ peer = bus_peer(s); ++ if (peer) ++ sock_hold(peer); ++ bus_state_unlock(s); ++ return peer; ++} ++EXPORT_SYMBOL_GPL(bus_peer_get); ++ ++static inline void bus_release_addr(struct bus_address *addr) ++{ ++ if (atomic_dec_and_test(&addr->refcnt)) ++ kfree(addr); ++} ++ ++/* ++ * Check bus socket name: ++ * - should be not zero length. ++ * - if started by not zero, should be NULL terminated (FS object) ++ * - if started by zero, it is abstract name. ++ */ ++ ++static int bus_mkname(struct sockaddr_bus *sbusaddr, int len, ++ unsigned int *hashp) ++{ ++ int offset = (sbusaddr->sbus_path[0] == '\0'); ++ ++ if (len <= sizeof(short) || len > sizeof(*sbusaddr)) ++ return -EINVAL; ++ if (!sbusaddr || sbusaddr->sbus_family != AF_BUS) ++ return -EINVAL; ++ ++ len = strnlen(sbusaddr->sbus_path + offset, BUS_PATH_MAX) + 1 + ++ sizeof(__kernel_sa_family_t) + ++ sizeof(struct bus_addr); ++ ++ *hashp = bus_compute_hash(sbusaddr->sbus_addr); ++ return len; ++} ++ ++static void __bus_remove_address(struct bus_address *addr) ++{ ++ hlist_del(&addr->table_node); ++} ++ ++static void __bus_insert_address(struct hlist_head *list, ++ struct bus_address *addr) ++{ ++ hlist_add_head(&addr->table_node, list); ++} ++ ++static inline void bus_remove_address(struct bus_address *addr) ++{ ++ spin_lock(&bus_address_lock); ++ __bus_remove_address(addr); ++ spin_unlock(&bus_address_lock); ++} ++ ++static inline void bus_insert_address(struct hlist_head *list, ++ struct bus_address *addr) ++{ ++ spin_lock(&bus_address_lock); ++ __bus_insert_address(list, addr); ++ spin_unlock(&bus_address_lock); ++} ++ ++static void __bus_remove_socket(struct sock *sk) ++{ ++ sk_del_node_init(sk); ++} ++ ++static void __bus_insert_socket(struct hlist_head *list, struct sock *sk) ++{ ++ WARN_ON(!sk_unhashed(sk)); ++ sk_add_node(sk, list); ++} ++ ++static inline void bus_remove_socket(struct sock *sk) ++{ ++ spin_lock(&bus_table_lock); ++ __bus_remove_socket(sk); ++ spin_unlock(&bus_table_lock); ++} ++ ++static inline void bus_insert_socket(struct hlist_head *list, struct sock *sk) ++{ ++ spin_lock(&bus_table_lock); ++ __bus_insert_socket(list, sk); ++ spin_unlock(&bus_table_lock); ++} ++ ++static inline bool __bus_has_prefix(struct sock *sk, u16 prefix) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ struct bus_address *addr; ++ struct hlist_node *node; ++ bool ret = false; ++ ++ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) { ++ if (bus_addr_prefix(addr->name) == prefix) ++ ret = true; ++ } ++ ++ return ret; ++} ++ ++static inline bool bus_has_prefix(struct sock *sk, u16 prefix) ++{ ++ bool ret; ++ ++ bus_state_lock(sk); ++ ret = __bus_has_prefix(sk, prefix); ++ bus_state_unlock(sk); ++ ++ return ret; ++} ++ ++static inline bool __bus_eavesdropper(struct sock *sk, u16 condition) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ ++ return u->eavesdropper; ++} ++ ++static inline bool bus_eavesdropper(struct sock *sk, u16 condition) ++{ ++ bool ret; ++ ++ bus_state_lock(sk); ++ ret = __bus_eavesdropper(sk, condition); ++ bus_state_unlock(sk); ++ ++ return ret; ++} ++ ++static inline bool bus_has_prefix_eavesdropper(struct sock *sk, u16 prefix) ++{ ++ bool ret; ++ ++ bus_state_lock(sk); ++ ret = __bus_has_prefix(sk, prefix) || __bus_eavesdropper(sk, 0); ++ bus_state_unlock(sk); ++ ++ return ret; ++} ++ ++static inline struct bus_address *__bus_get_address(struct sock *sk, ++ struct bus_addr *sbus_addr) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ struct bus_address *addr = NULL; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) { ++ if (addr->name->sbus_addr.s_addr == sbus_addr->s_addr) ++ return addr; ++ } ++ ++ return NULL; ++} ++ ++static inline struct bus_address *bus_get_address(struct sock *sk, ++ struct bus_addr *sbus_addr) ++{ ++ struct bus_address *addr; ++ ++ bus_state_lock(sk); ++ addr = __bus_get_address(sk, sbus_addr); ++ bus_state_unlock(sk); ++ ++ return addr; ++} ++ ++static struct sock *__bus_find_socket_byname(struct net *net, ++ struct sockaddr_bus *sbusname, ++ int len, unsigned int hash) ++{ ++ struct sock *s; ++ struct hlist_node *node; ++ ++ sk_for_each(s, node, &bus_socket_table[hash]) { ++ struct bus_sock *u = bus_sk(s); ++ ++ if (!net_eq(sock_net(s), net)) ++ continue; ++ ++ if (u->addr->len == len && ++ !memcmp(u->addr->name, sbusname, len)) ++ return s; ++ } ++ ++ return NULL; ++} ++ ++static inline struct sock *bus_find_socket_byname(struct net *net, ++ struct sockaddr_bus *sbusname, ++ int len, unsigned int hash) ++{ ++ struct sock *s; ++ ++ spin_lock(&bus_table_lock); ++ s = __bus_find_socket_byname(net, sbusname, len, hash); ++ if (s) ++ sock_hold(s); ++ spin_unlock(&bus_table_lock); ++ return s; ++} ++ ++static struct sock *__bus_find_socket_byaddress(struct net *net, ++ struct sockaddr_bus *sbusname, ++ int len, int protocol, ++ unsigned int hash) ++{ ++ struct sock *s; ++ struct bus_address *addr; ++ struct hlist_node *node; ++ struct bus_sock *u; ++ int offset = (sbusname->sbus_path[0] == '\0'); ++ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX); ++ ++ len = path_len + 1 + sizeof(__kernel_sa_family_t) + ++ sizeof(struct bus_addr); ++ ++ hlist_for_each_entry(addr, node, &bus_address_table[hash], ++ table_node) { ++ s = addr->sock; ++ u = bus_sk(s); ++ ++ if (s->sk_protocol != protocol) ++ continue; ++ ++ if (!net_eq(sock_net(s), net)) ++ continue; ++ ++ if (addr->len == len && ++ addr->name->sbus_family == sbusname->sbus_family && ++ addr->name->sbus_addr.s_addr == sbusname->sbus_addr.s_addr ++ && bus_same_bus(addr->name, sbusname)) ++ goto found; ++ } ++ s = NULL; ++found: ++ return s; ++} ++ ++static inline struct sock *bus_find_socket_byaddress(struct net *net, ++ struct sockaddr_bus *name, ++ int len, int protocol, ++ unsigned int hash) ++{ ++ struct sock *s; ++ ++ spin_lock(&bus_address_lock); ++ s = __bus_find_socket_byaddress(net, name, len, protocol, hash); ++ if (s) ++ sock_hold(s); ++ spin_unlock(&bus_address_lock); ++ return s; ++} ++ ++static inline int bus_writable(struct sock *sk) ++{ ++ return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; ++} ++ ++static void bus_write_space(struct sock *sk) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ struct bus_sock *p; ++ struct hlist_node *node; ++ struct socket_wq *wq; ++ ++ if (bus_writable(sk)) { ++ rcu_read_lock(); ++ wq = rcu_dereference(sk->sk_wq); ++ if (wq_has_sleeper(wq)) ++ wake_up_interruptible_sync_poll(&wq->wait, ++ POLLOUT | POLLWRNORM | POLLWRBAND); ++ sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); ++ rcu_read_unlock(); ++ ++ if (u && u->bus) { ++ spin_lock(&u->bus->lock); ++ hlist_for_each_entry(p, node, &u->bus->peers, ++ bus_node) { ++ wake_up_interruptible_sync_poll(sk_sleep(&p->sk), ++ POLLOUT | ++ POLLWRNORM | ++ POLLWRBAND); ++ sk_wake_async(&p->sk, SOCK_WAKE_SPACE, ++ POLL_OUT); ++ } ++ spin_unlock(&u->bus->lock); ++ } ++ } ++} ++ ++static void bus_bus_release(struct kref *kref) ++{ ++ struct bus *bus; ++ ++ bus = container_of(kref, struct bus, kref); ++ ++ kfree(bus); ++} ++ ++static void bus_sock_destructor(struct sock *sk) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ ++ skb_queue_purge(&sk->sk_receive_queue); ++ ++ WARN_ON(atomic_read(&sk->sk_wmem_alloc)); ++ WARN_ON(!sk_unhashed(sk)); ++ WARN_ON(sk->sk_socket); ++ if (!sock_flag(sk, SOCK_DEAD)) { ++ pr_info("Attempt to release alive bus socket: %p\n", sk); ++ return; ++ } ++ ++ if (u->bus) { ++ kref_put(&u->bus->kref, bus_bus_release); ++ u->bus = NULL; ++ } ++ ++ atomic_long_dec(&bus_nr_socks); ++ local_bh_disable(); ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); ++ local_bh_enable(); ++#ifdef BUS_REFCNT_DEBUG ++ pr_debug("BUS %p is destroyed, %ld are still alive.\n", sk, ++ atomic_long_read(&bus_nr_socks)); ++#endif ++} ++ ++static int bus_release_sock(struct sock *sk, int embrion) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ struct path path; ++ struct sock *skpair; ++ struct sk_buff *skb; ++ int state; ++ struct bus_address *addr; ++ struct hlist_node *node, *tmp; ++ ++ bus_remove_socket(sk); ++ ++ if (u->bus && u->authenticated && ++ !u->bus_master && !u->bus_master_side) { ++ spin_lock(&u->bus->lock); ++ hlist_del(&u->bus_node); ++ if (u->eavesdropper) ++ atomic64_dec(&u->bus->eavesdropper_cnt); ++ spin_unlock(&u->bus->lock); ++ } ++ ++ /* Clear state */ ++ bus_state_lock(sk); ++ sock_orphan(sk); ++ sk->sk_shutdown = SHUTDOWN_MASK; ++ path = u->path; ++ u->path.dentry = NULL; ++ u->path.mnt = NULL; ++ state = sk->sk_state; ++ sk->sk_state = BUS_CLOSE; ++ ++ if (u->bus_master) ++ u->bus->master = NULL; ++ ++ if (u->bus_master_side) { ++ bus_release_addr(u->addr); ++ u->addr = NULL; ++ } else { ++ u->addr = NULL; ++ ++ spin_lock(&bus_address_lock); ++ hlist_for_each_entry_safe(addr, node, tmp, &u->addr_list, ++ addr_node) { ++ hlist_del(&addr->addr_node); ++ __bus_remove_address(addr); ++ bus_release_addr(addr); ++ } ++ spin_unlock(&bus_address_lock); ++ } ++ ++ bus_state_unlock(sk); ++ ++ wake_up_interruptible_all(&u->peer_wait); ++ ++ skpair = bus_peer(sk); ++ ++ if (skpair != NULL) { ++ bus_state_lock(skpair); ++ /* No more writes */ ++ skpair->sk_shutdown = SHUTDOWN_MASK; ++ if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) ++ skpair->sk_err = ECONNRESET; ++ bus_state_unlock(skpair); ++ skpair->sk_state_change(skpair); ++ sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); ++ sock_put(skpair); /* It may now die */ ++ bus_peer(sk) = NULL; ++ } ++ ++ /* Try to flush out this socket. Throw out buffers at least */ ++ ++ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { ++ if (state == BUS_LISTEN) ++ bus_release_sock(skb->sk, 1); ++ /* passed fds are erased in the kfree_skb hook */ ++ kfree_skb(skb); ++ } ++ ++ if (path.dentry) ++ path_put(&path); ++ ++ sock_put(sk); ++ ++ /* ---- Socket is dead now and most probably destroyed ---- */ ++ ++ if (bus_tot_inflight) ++ bus_gc(); /* Garbage collect fds */ ++ ++ return 0; ++} ++ ++static void init_peercred(struct sock *sk) ++{ ++ put_pid(sk->sk_peer_pid); ++ if (sk->sk_peer_cred) ++ put_cred(sk->sk_peer_cred); ++ sk->sk_peer_pid = get_pid(task_tgid(current)); ++ sk->sk_peer_cred = get_current_cred(); ++} ++ ++static void copy_peercred(struct sock *sk, struct sock *peersk) ++{ ++ put_pid(sk->sk_peer_pid); ++ if (sk->sk_peer_cred) ++ put_cred(sk->sk_peer_cred); ++ sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); ++ sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); ++} ++ ++static int bus_listen(struct socket *sock, int backlog) ++{ ++ int err; ++ struct sock *sk = sock->sk; ++ struct bus_sock *u = bus_sk(sk); ++ struct pid *old_pid = NULL; ++ const struct cred *old_cred = NULL; ++ ++ err = -EINVAL; ++ if (!u->addr || !u->bus_master) ++ goto out; /* Only listens on an bound an master socket */ ++ bus_state_lock(sk); ++ if (sk->sk_state != BUS_CLOSE && sk->sk_state != BUS_LISTEN) ++ goto out_unlock; ++ if (backlog > sk->sk_max_ack_backlog) ++ wake_up_interruptible_all(&u->peer_wait); ++ sk->sk_max_ack_backlog = backlog; ++ sk->sk_state = BUS_LISTEN; ++ /* set credentials so connect can copy them */ ++ init_peercred(sk); ++ err = 0; ++ ++out_unlock: ++ bus_state_unlock(sk); ++ put_pid(old_pid); ++ if (old_cred) ++ put_cred(old_cred); ++out: ++ return err; ++} ++ ++static int bus_release(struct socket *); ++static int bus_bind(struct socket *, struct sockaddr *, int); ++static int bus_connect(struct socket *, struct sockaddr *, ++ int addr_len, int flags); ++static int bus_accept(struct socket *, struct socket *, int); ++static int bus_getname(struct socket *, struct sockaddr *, int *, int); ++static unsigned int bus_poll(struct file *, struct socket *, ++ poll_table *); ++static int bus_ioctl(struct socket *, unsigned int, unsigned long); ++static int bus_shutdown(struct socket *, int); ++static int bus_setsockopt(struct socket *, int, int, char __user *, ++ unsigned int); ++static int bus_sendmsg(struct kiocb *, struct socket *, ++ struct msghdr *, size_t); ++static int bus_recvmsg(struct kiocb *, struct socket *, ++ struct msghdr *, size_t, int); ++ ++static void bus_set_peek_off(struct sock *sk, int val) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ ++ mutex_lock(&u->readlock); ++ sk->sk_peek_off = val; ++ mutex_unlock(&u->readlock); ++} ++ ++static const struct proto_ops bus_seqpacket_ops = { ++ .family = PF_BUS, ++ .owner = THIS_MODULE, ++ .release = bus_release, ++ .bind = bus_bind, ++ .connect = bus_connect, ++ .socketpair = sock_no_socketpair, ++ .accept = bus_accept, ++ .getname = bus_getname, ++ .poll = bus_poll, ++ .ioctl = bus_ioctl, ++ .listen = bus_listen, ++ .shutdown = bus_shutdown, ++ .setsockopt = bus_setsockopt, ++ .getsockopt = sock_no_getsockopt, ++ .sendmsg = bus_sendmsg, ++ .recvmsg = bus_recvmsg, ++ .mmap = sock_no_mmap, ++ .sendpage = sock_no_sendpage, ++ .set_peek_off = bus_set_peek_off, ++}; ++ ++static struct proto bus_proto = { ++ .name = "BUS", ++ .owner = THIS_MODULE, ++ .obj_size = sizeof(struct bus_sock), ++}; ++ ++/* ++ * AF_BUS sockets do not interact with hardware, hence they ++ * dont trigger interrupts - so it's safe for them to have ++ * bh-unsafe locking for their sk_receive_queue.lock. Split off ++ * this special lock-class by reinitializing the spinlock key: ++ */ ++static struct lock_class_key af_bus_sk_receive_queue_lock_key; ++ ++static struct sock *bus_create1(struct net *net, struct socket *sock) ++{ ++ struct sock *sk = NULL; ++ struct bus_sock *u; ++ ++ atomic_long_inc(&bus_nr_socks); ++ if (atomic_long_read(&bus_nr_socks) > 2 * get_max_files()) ++ goto out; ++ ++ sk = sk_alloc(net, PF_BUS, GFP_KERNEL, &bus_proto); ++ if (!sk) ++ goto out; ++ ++ sock_init_data(sock, sk); ++ lockdep_set_class(&sk->sk_receive_queue.lock, ++ &af_bus_sk_receive_queue_lock_key); ++ ++ sk->sk_write_space = bus_write_space; ++ sk->sk_max_ack_backlog = BUS_MAX_QLEN; ++ sk->sk_destruct = bus_sock_destructor; ++ u = bus_sk(sk); ++ u->path.dentry = NULL; ++ u->path.mnt = NULL; ++ u->bus = NULL; ++ u->bus_master = false; ++ u->authenticated = false; ++ u->eavesdropper = false; ++ spin_lock_init(&u->lock); ++ atomic_long_set(&u->inflight, 0); ++ INIT_LIST_HEAD(&u->link); ++ INIT_HLIST_HEAD(&u->addr_list); ++ INIT_HLIST_NODE(&u->bus_node); ++ mutex_init(&u->readlock); /* single task reading lock */ ++ init_waitqueue_head(&u->peer_wait); ++ bus_insert_socket(bus_sockets_unbound, sk); ++out: ++ if (sk == NULL) ++ atomic_long_dec(&bus_nr_socks); ++ else { ++ local_bh_disable(); ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); ++ local_bh_enable(); ++ } ++ return sk; ++} ++ ++static int bus_create(struct net *net, struct socket *sock, int protocol, ++ int kern) ++{ ++ struct sock *sk; ++ ++ if (protocol < BUS_PROTO_NONE || protocol > BUS_PROTO_DBUS) ++ return -EPROTONOSUPPORT; ++ ++ if (protocol != BUS_PROTO_NONE) ++ request_module("net-pf-%d-proto-%d", PF_BUS, protocol); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type == SOCK_SEQPACKET) ++ sock->ops = &bus_seqpacket_ops; ++ else ++ return -ESOCKTNOSUPPORT; ++ ++ sk = bus_create1(net, sock); ++ if (!sk) ++ return -ENOMEM; ++ ++ sk->sk_protocol = protocol; ++ ++ return 0; ++} ++ ++static int bus_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ if (!sk) ++ return 0; ++ ++ sock->sk = NULL; ++ ++ return bus_release_sock(sk, 0); ++} ++ ++static struct sock *bus_find_other(struct net *net, ++ struct sockaddr_bus *sbusname, int len, ++ int protocol, unsigned int hash, int *error) ++{ ++ struct sock *u; ++ struct path path; ++ int err = 0; ++ ++ if (sbusname->sbus_path[0]) { ++ struct inode *inode; ++ err = kern_path(sbusname->sbus_path, LOOKUP_FOLLOW, &path); ++ if (err) ++ goto fail; ++ inode = path.dentry->d_inode; ++ err = inode_permission(inode, MAY_WRITE); ++ if (err) ++ goto put_fail; ++ ++ err = -ECONNREFUSED; ++ if (!S_ISSOCK(inode->i_mode)) ++ goto put_fail; ++ u = bus_find_socket_byaddress(net, sbusname, len, protocol, ++ hash); ++ if (!u) ++ goto put_fail; ++ ++ touch_atime(&path); ++ path_put(&path); ++ ++ } else { ++ err = -ECONNREFUSED; ++ u = bus_find_socket_byaddress(net, sbusname, len, protocol, hash); ++ if (u) { ++ struct dentry *dentry; ++ dentry = bus_sk(u)->path.dentry; ++ if (dentry) ++ touch_atime(&bus_sk(u)->path); ++ } else ++ goto fail; ++ } ++ ++ return u; ++ ++put_fail: ++ path_put(&path); ++fail: ++ *error = err; ++ return NULL; ++} ++ ++ ++static int bus_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ++{ ++ struct sock *sk = sock->sk; ++ struct net *net = sock_net(sk); ++ struct bus_sock *u = bus_sk(sk); ++ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr; ++ char *sbus_path = sbusaddr->sbus_path; ++ struct dentry *dentry = NULL; ++ struct path path; ++ int err; ++ unsigned int hash; ++ struct bus_address *addr; ++ struct hlist_head *list; ++ struct bus *bus; ++ ++ err = -EINVAL; ++ if (sbusaddr->sbus_family != AF_BUS) ++ goto out; ++ ++ /* If the address is available, the socket is the bus master */ ++ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR; ++ ++ err = bus_mkname(sbusaddr, addr_len, &hash); ++ if (err < 0) ++ goto out; ++ addr_len = err; ++ ++ mutex_lock(&u->readlock); ++ ++ err = -EINVAL; ++ if (u->addr) ++ goto out_up; ++ ++ err = -ENOMEM; ++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); ++ if (!addr) ++ goto out_up; ++ ++ memcpy(addr->name, sbusaddr, sizeof(struct sockaddr_bus)); ++ addr->len = addr_len; ++ addr->hash = hash; ++ atomic_set(&addr->refcnt, 1); ++ addr->sock = sk; ++ INIT_HLIST_NODE(&addr->addr_node); ++ INIT_HLIST_NODE(&addr->table_node); ++ ++ if (sbus_path[0]) { ++ umode_t mode; ++ err = 0; ++ /* ++ * Get the parent directory, calculate the hash for last ++ * component. ++ */ ++ dentry = kern_path_create(AT_FDCWD, sbus_path, &path, 0); ++ err = PTR_ERR(dentry); ++ if (IS_ERR(dentry)) ++ goto out_mknod_parent; ++ ++ /* ++ * All right, let's create it. ++ */ ++ mode = S_IFSOCK | ++ (SOCK_INODE(sock)->i_mode & ~current_umask()); ++ err = mnt_want_write(path.mnt); ++ if (err) ++ goto out_mknod_dput; ++ err = security_path_mknod(&path, dentry, mode, 0); ++ if (err) ++ goto out_mknod_drop_write; ++ err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); ++out_mknod_drop_write: ++ mnt_drop_write(path.mnt); ++ if (err) ++ goto out_mknod_dput; ++ mutex_unlock(&path.dentry->d_inode->i_mutex); ++ dput(path.dentry); ++ path.dentry = dentry; ++ } ++ ++ err = -ENOMEM; ++ bus = kzalloc(sizeof(*bus), GFP_KERNEL); ++ if (!bus) ++ goto out_unlock; ++ ++ spin_lock(&bus_table_lock); ++ ++ if (!sbus_path[0]) { ++ err = -EADDRINUSE; ++ if (__bus_find_socket_byname(net, sbusaddr, addr_len, hash)) { ++ bus_release_addr(addr); ++ kfree(bus); ++ goto out_unlock; ++ } ++ ++ list = &bus_socket_table[addr->hash]; ++ } else { ++ list = &bus_socket_table[dentry->d_inode->i_ino & ++ (BUS_HASH_SIZE-1)]; ++ u->path = path; ++ } ++ ++ kref_init(&bus->kref); ++ bus->master = sk; ++ INIT_HLIST_HEAD(&bus->peers); ++ spin_lock_init(&bus->lock); ++ spin_lock_init(&bus->send_lock); ++ atomic64_set(&bus->addr_cnt, 0); ++ atomic64_set(&bus->eavesdropper_cnt, 0); ++ ++ hlist_add_head(&addr->addr_node, &u->addr_list); ++ ++ err = 0; ++ __bus_remove_socket(sk); ++ u->addr = addr; ++ u->bus_master = true; ++ u->bus = bus; ++ __bus_insert_socket(list, sk); ++ bus_insert_address(&bus_address_table[addr->hash], addr); ++ ++out_unlock: ++ spin_unlock(&bus_table_lock); ++out_up: ++ mutex_unlock(&u->readlock); ++out: ++ return err; ++ ++out_mknod_dput: ++ dput(dentry); ++ mutex_unlock(&path.dentry->d_inode->i_mutex); ++ path_put(&path); ++out_mknod_parent: ++ if (err == -EEXIST) ++ err = -EADDRINUSE; ++ bus_release_addr(addr); ++ goto out_up; ++} ++ ++static long bus_wait_for_peer(struct sock *other, long timeo) ++{ ++ struct bus_sock *u = bus_sk(other); ++ int sched; ++ DEFINE_WAIT(wait); ++ ++ prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); ++ ++ sched = !sock_flag(other, SOCK_DEAD) && ++ !(other->sk_shutdown & RCV_SHUTDOWN) && ++ bus_recvq_full(other); ++ ++ bus_state_unlock(other); ++ ++ if (sched) ++ timeo = schedule_timeout(timeo); ++ ++ finish_wait(&u->peer_wait, &wait); ++ return timeo; ++} ++ ++static int bus_connect(struct socket *sock, struct sockaddr *uaddr, ++ int addr_len, int flags) ++{ ++ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr; ++ struct sock *sk = sock->sk; ++ struct net *net = sock_net(sk); ++ struct bus_sock *u = bus_sk(sk), *newu, *otheru; ++ struct sock *newsk = NULL; ++ struct sock *other = NULL; ++ struct sk_buff *skb = NULL; ++ struct bus_address *addr = NULL; ++ unsigned int hash; ++ int st; ++ int err; ++ long timeo; ++ ++ /* Only connections to the bus master is allowed */ ++ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR; ++ ++ err = bus_mkname(sbusaddr, addr_len, &hash); ++ if (err < 0) ++ goto out; ++ addr_len = err; ++ ++ err = -ENOMEM; ++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); ++ if (!addr) ++ goto out; ++ ++ atomic_set(&addr->refcnt, 1); ++ INIT_HLIST_NODE(&addr->addr_node); ++ INIT_HLIST_NODE(&addr->table_node); ++ ++ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); ++ ++ /* First of all allocate resources. ++ If we will make it after state is locked, ++ we will have to recheck all again in any case. ++ */ ++ ++ err = -ENOMEM; ++ ++ /* create new sock for complete connection */ ++ newsk = bus_create1(sock_net(sk), NULL); ++ if (newsk == NULL) ++ goto out; ++ ++ /* Allocate skb for sending to listening sock */ ++ skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); ++ if (skb == NULL) ++ goto out; ++ ++restart: ++ /* Find listening sock. */ ++ other = bus_find_other(net, sbusaddr, addr_len, sk->sk_protocol, hash, ++ &err); ++ if (!other) ++ goto out; ++ ++ /* Latch state of peer */ ++ bus_state_lock(other); ++ ++ /* Apparently VFS overslept socket death. Retry. */ ++ if (sock_flag(other, SOCK_DEAD)) { ++ bus_state_unlock(other); ++ sock_put(other); ++ goto restart; ++ } ++ ++ err = -ECONNREFUSED; ++ if (other->sk_state != BUS_LISTEN) ++ goto out_unlock; ++ if (other->sk_shutdown & RCV_SHUTDOWN) ++ goto out_unlock; ++ ++ if (bus_recvq_full(other)) { ++ err = -EAGAIN; ++ if (!timeo) ++ goto out_unlock; ++ ++ timeo = bus_wait_for_peer(other, timeo); ++ ++ err = sock_intr_errno(timeo); ++ if (signal_pending(current)) ++ goto out; ++ sock_put(other); ++ goto restart; ++ } ++ ++ /* Latch our state. ++ ++ It is tricky place. We need to grab our state lock and cannot ++ drop lock on peer. It is dangerous because deadlock is ++ possible. Connect to self case and simultaneous ++ attempt to connect are eliminated by checking socket ++ state. other is BUS_LISTEN, if sk is BUS_LISTEN we ++ check this before attempt to grab lock. ++ ++ Well, and we have to recheck the state after socket locked. ++ */ ++ st = sk->sk_state; ++ ++ switch (st) { ++ case BUS_CLOSE: ++ /* This is ok... continue with connect */ ++ break; ++ case BUS_ESTABLISHED: ++ /* Socket is already connected */ ++ err = -EISCONN; ++ goto out_unlock; ++ default: ++ err = -EINVAL; ++ goto out_unlock; ++ } ++ ++ bus_state_lock_nested(sk); ++ ++ if (sk->sk_state != st) { ++ bus_state_unlock(sk); ++ bus_state_unlock(other); ++ sock_put(other); ++ goto restart; ++ } ++ ++ err = security_bus_connect(sk, other, newsk); ++ if (err) { ++ bus_state_unlock(sk); ++ goto out_unlock; ++ } ++ ++ /* The way is open! Fastly set all the necessary fields... */ ++ ++ sock_hold(sk); ++ bus_peer(newsk) = sk; ++ newsk->sk_state = BUS_ESTABLISHED; ++ newsk->sk_type = sk->sk_type; ++ newsk->sk_protocol = sk->sk_protocol; ++ init_peercred(newsk); ++ newu = bus_sk(newsk); ++ RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); ++ otheru = bus_sk(other); ++ ++ /* copy address information from listening to new sock*/ ++ if (otheru->addr && otheru->bus_master) { ++ atomic_inc(&otheru->addr->refcnt); ++ newu->addr = otheru->addr; ++ memcpy(addr->name, otheru->addr->name, ++ sizeof(struct sockaddr_bus)); ++ addr->len = otheru->addr->len; ++ addr->name->sbus_addr.s_addr = ++ (atomic64_inc_return(&otheru->bus->addr_cnt) & ++ BUS_CLIENT_MASK); ++ addr->hash = bus_compute_hash(addr->name->sbus_addr); ++ addr->sock = sk; ++ u->addr = addr; ++ kref_get(&otheru->bus->kref); ++ u->bus = otheru->bus; ++ u->bus_master_side = false; ++ kref_get(&otheru->bus->kref); ++ newu->bus = otheru->bus; ++ newu->bus_master_side = true; ++ hlist_add_head(&addr->addr_node, &u->addr_list); ++ ++ bus_insert_address(&bus_address_table[addr->hash], addr); ++ } ++ if (otheru->path.dentry) { ++ path_get(&otheru->path); ++ newu->path = otheru->path; ++ } ++ ++ /* Set credentials */ ++ copy_peercred(sk, other); ++ sk->sk_sndbuf = other->sk_sndbuf; ++ sk->sk_max_ack_backlog = other->sk_max_ack_backlog; ++ newsk->sk_sndbuf = other->sk_sndbuf; ++ ++ sock->state = SS_CONNECTED; ++ sk->sk_state = BUS_ESTABLISHED; ++ sock_hold(newsk); ++ ++ smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */ ++ bus_peer(sk) = newsk; ++ ++ bus_state_unlock(sk); ++ ++ /* take ten and and send info to listening sock */ ++ spin_lock(&other->sk_receive_queue.lock); ++ __skb_queue_tail(&other->sk_receive_queue, skb); ++ spin_unlock(&other->sk_receive_queue.lock); ++ bus_state_unlock(other); ++ other->sk_data_ready(other, 0); ++ sock_put(other); ++ return 0; ++ ++out_unlock: ++ if (other) ++ bus_state_unlock(other); ++ ++out: ++ kfree_skb(skb); ++ if (addr) ++ bus_release_addr(addr); ++ if (newsk) ++ bus_release_sock(newsk, 0); ++ if (other) ++ sock_put(other); ++ return err; ++} ++ ++static int bus_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ struct sock *sk = sock->sk; ++ struct sock *tsk; ++ struct sk_buff *skb; ++ int err; ++ ++ err = -EINVAL; ++ if (sk->sk_state != BUS_LISTEN) ++ goto out; ++ ++ /* If socket state is BUS_LISTEN it cannot change (for now...), ++ * so that no locks are necessary. ++ */ ++ ++ skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); ++ if (!skb) { ++ /* This means receive shutdown. */ ++ if (err == 0) ++ err = -EINVAL; ++ goto out; ++ } ++ ++ tsk = skb->sk; ++ skb_free_datagram(sk, skb); ++ wake_up_interruptible(&bus_sk(sk)->peer_wait); ++ ++ /* attach accepted sock to socket */ ++ bus_state_lock(tsk); ++ newsock->state = SS_CONNECTED; ++ sock_graft(tsk, newsock); ++ bus_state_unlock(tsk); ++ return 0; ++ ++out: ++ return err; ++} ++ ++ ++static int bus_getname(struct socket *sock, struct sockaddr *uaddr, ++ int *uaddr_len, int peer) ++{ ++ struct sock *sk = sock->sk; ++ struct bus_sock *u; ++ DECLARE_SOCKADDR(struct sockaddr_bus *, sbusaddr, uaddr); ++ int err = 0; ++ ++ if (peer) { ++ sk = bus_peer_get(sk); ++ ++ err = -ENOTCONN; ++ if (!sk) ++ goto out; ++ err = 0; ++ } else { ++ sock_hold(sk); ++ } ++ ++ u = bus_sk(sk); ++ ++ bus_state_lock(sk); ++ if (!u->addr) { ++ sbusaddr->sbus_family = AF_BUS; ++ sbusaddr->sbus_path[0] = 0; ++ *uaddr_len = sizeof(short); ++ } else { ++ struct bus_address *addr = u->addr; ++ ++ *uaddr_len = sizeof(struct sockaddr_bus); ++ memcpy(sbusaddr, addr->name, *uaddr_len); ++ } ++ bus_state_unlock(sk); ++ sock_put(sk); ++out: ++ return err; ++} ++ ++static void bus_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ int i; ++ ++ scm->fp = BUSCB(skb).fp; ++ BUSCB(skb).fp = NULL; ++ ++ for (i = scm->fp->count-1; i >= 0; i--) ++ bus_notinflight(scm->fp->fp[i]); ++} ++ ++static void bus_destruct_scm(struct sk_buff *skb) ++{ ++ struct scm_cookie scm; ++ memset(&scm, 0, sizeof(scm)); ++ scm.pid = BUSCB(skb).pid; ++ scm.cred = BUSCB(skb).cred; ++ if (BUSCB(skb).fp) ++ bus_detach_fds(&scm, skb); ++ ++ scm_destroy(&scm); ++ if (skb->sk) ++ sock_wfree(skb); ++} ++ ++#define MAX_RECURSION_LEVEL 4 ++ ++static int bus_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) ++{ ++ int i; ++ unsigned char max_level = 0; ++ int bus_sock_count = 0; ++ ++ for (i = scm->fp->count - 1; i >= 0; i--) { ++ struct sock *sk = bus_get_socket(scm->fp->fp[i]); ++ ++ if (sk) { ++ bus_sock_count++; ++ max_level = max(max_level, ++ bus_sk(sk)->recursion_level); ++ } ++ } ++ if (unlikely(max_level > MAX_RECURSION_LEVEL)) ++ return -ETOOMANYREFS; ++ ++ /* ++ * Need to duplicate file references for the sake of garbage ++ * collection. Otherwise a socket in the fps might become a ++ * candidate for GC while the skb is not yet queued. ++ */ ++ BUSCB(skb).fp = scm_fp_dup(scm->fp); ++ if (!BUSCB(skb).fp) ++ return -ENOMEM; ++ ++ if (bus_sock_count) { ++ for (i = scm->fp->count - 1; i >= 0; i--) ++ bus_inflight(scm->fp->fp[i]); ++ } ++ return max_level; ++} ++ ++static int bus_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, ++ bool send_fds) ++{ ++ int err = 0; ++ ++ BUSCB(skb).pid = get_pid(scm->pid); ++ if (scm->cred) ++ BUSCB(skb).cred = get_cred(scm->cred); ++ BUSCB(skb).fp = NULL; ++ if (scm->fp && send_fds) ++ err = bus_attach_fds(scm, skb); ++ ++ skb->destructor = bus_destruct_scm; ++ return err; ++} ++ ++/* ++ * Some apps rely on write() giving SCM_CREDENTIALS ++ * We include credentials if source or destination socket ++ * asserted SOCK_PASSCRED. ++ */ ++static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, ++ const struct sock *other) ++{ ++ if (BUSCB(skb).cred) ++ return; ++ if (test_bit(SOCK_PASSCRED, &sock->flags) || ++ !other->sk_socket || ++ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) { ++ BUSCB(skb).pid = get_pid(task_tgid(current)); ++ BUSCB(skb).cred = get_current_cred(); ++ } ++} ++ ++/* ++ * Send AF_BUS data. ++ */ ++ ++static void bus_deliver_skb(struct sk_buff *skb) ++{ ++ struct bus_send_context *sendctx = BUSCB(skb).sendctx; ++ struct socket *sock = sendctx->sender_socket; ++ ++ if (sock_flag(sendctx->other, SOCK_RCVTSTAMP)) ++ __net_timestamp(skb); ++ maybe_add_creds(skb, sock, sendctx->other); ++ skb_queue_tail(&sendctx->other->sk_receive_queue, skb); ++ if (sendctx->max_level > bus_sk(sendctx->other)->recursion_level) ++ bus_sk(sendctx->other)->recursion_level = sendctx->max_level; ++} ++ ++/** ++ * bus_sendmsg_finish - delivery an skb to a destination ++ * @skb: sk_buff to deliver ++ * ++ * Delivers a packet to a destination. The skb control buffer has ++ * all the information about the destination contained on sending ++ * context. If the sending is unicast, then the skb is delivered ++ * and the receiver notified but if the sending is multicast, the ++ * skb is just marked as delivered and the actual delivery is made ++ * outside the function with the bus->send_lock held to ensure that ++ * the multicast sending is atomic. ++ */ ++static int bus_sendmsg_finish(struct sk_buff *skb) ++{ ++ int err; ++ struct bus_send_context *sendctx; ++ struct socket *sock; ++ struct sock *sk; ++ struct net *net; ++ size_t len = skb->len; ++ ++ sendctx = BUSCB(skb).sendctx; ++ sock = sendctx->sender_socket; ++ sk = sock->sk; ++ net = sock_net(sk); ++ ++restart: ++ if (!sendctx->other) { ++ err = -ECONNRESET; ++ if (sendctx->recipient == NULL) ++ goto out_free; ++ ++ sendctx->other = bus_find_other(net, sendctx->recipient, ++ sendctx->namelen, ++ sk->sk_protocol, ++ sendctx->hash, &err); ++ ++ if (sendctx->other == NULL || ++ !bus_sk(sendctx->other)->authenticated) { ++ ++ if (sendctx->other) ++ sock_put(sendctx->other); ++ ++ if (!bus_sk(sk)->bus_master_side) { ++ err = -ENOTCONN; ++ sendctx->other = bus_peer_get(sk); ++ if (!sendctx->other) ++ goto out_free; ++ } else { ++ sendctx->other = sk; ++ sock_hold(sendctx->other); ++ } ++ } ++ } ++ ++ if (sk_filter(sendctx->other, skb) < 0) { ++ /* Toss the packet but do not return any error to the sender */ ++ err = len; ++ goto out_free; ++ } ++ ++ bus_state_lock(sendctx->other); ++ ++ if (sock_flag(sendctx->other, SOCK_DEAD)) { ++ /* ++ * Check with 1003.1g - what should ++ * datagram error ++ */ ++ bus_state_unlock(sendctx->other); ++ sock_put(sendctx->other); ++ ++ err = 0; ++ bus_state_lock(sk); ++ if (bus_peer(sk) == sendctx->other) { ++ bus_peer(sk) = NULL; ++ bus_state_unlock(sk); ++ sock_put(sendctx->other); ++ err = -ECONNREFUSED; ++ } else { ++ bus_state_unlock(sk); ++ } ++ ++ sendctx->other = NULL; ++ if (err) ++ goto out_free; ++ goto restart; ++ } ++ ++ err = -EPIPE; ++ if (sendctx->other->sk_shutdown & RCV_SHUTDOWN) ++ goto out_unlock; ++ ++ if (bus_recvq_full(sendctx->other)) { ++ if (!sendctx->timeo) { ++ err = -EAGAIN; ++ goto out_unlock; ++ } ++ ++ sendctx->timeo = bus_wait_for_peer(sendctx->other, ++ sendctx->timeo); ++ ++ err = sock_intr_errno(sendctx->timeo); ++ if (signal_pending(current)) ++ goto out_free; ++ ++ goto restart; ++ } ++ ++ if (!sendctx->multicast && !sendctx->eavesdropper) { ++ bus_deliver_skb(skb); ++ bus_state_unlock(sendctx->other); ++ sendctx->other->sk_data_ready(sendctx->other, 0); ++ sock_put(sendctx->other); ++ } else { ++ sendctx->deliver = 1; ++ bus_state_unlock(sendctx->other); ++ } ++ ++ return len; ++ ++out_unlock: ++ bus_state_unlock(sendctx->other); ++out_free: ++ kfree_skb(skb); ++ if (sendctx->other) ++ sock_put(sendctx->other); ++ ++ return err; ++} ++ ++/** ++ * bus_sendmsg_mcast - do a multicast sending ++ * @skb: sk_buff to deliver ++ * ++ * Send a packet to a multicast destination. ++ * The function is also called for unicast sending when eavesdropping ++ * is enabled. Since the unicast destination and the eavesdroppers ++ * have to receive the packet atomically. ++ */ ++static int bus_sendmsg_mcast(struct sk_buff *skb) ++{ ++ struct bus_send_context *sendctx; ++ struct bus_send_context *tmpctx; ++ struct socket *sock; ++ struct sock *sk; ++ struct net *net; ++ struct bus_sock *u, *s; ++ struct hlist_node *node; ++ u16 prefix = 0; ++ struct sk_buff **skb_set = NULL; ++ struct bus_send_context **sendctx_set = NULL; ++ int rcp_cnt, send_cnt; ++ int i; ++ int err; ++ int len = skb->len; ++ bool (*is_receiver) (struct sock *, u16); ++ bool main_rcp_found = false; ++ ++ sendctx = BUSCB(skb).sendctx; ++ sendctx->deliver = 0; ++ sock = sendctx->sender_socket; ++ sk = sock->sk; ++ u = bus_sk(sk); ++ net = sock_net(sk); ++ ++ if (sendctx->multicast) { ++ prefix = bus_addr_prefix(sendctx->recipient); ++ if (sendctx->eavesdropper) ++ is_receiver = &bus_has_prefix_eavesdropper; ++ else ++ is_receiver = &bus_has_prefix; ++ } else { ++ is_receiver = &bus_eavesdropper; ++ ++ /* ++ * If the destination is not the peer accepted socket ++ * we have to get the correct destination. ++ */ ++ if (!sendctx->to_master && sendctx->recipient) { ++ sendctx->other = bus_find_other(net, sendctx->recipient, ++ sendctx->namelen, ++ sk->sk_protocol, ++ sendctx->hash, &err); ++ ++ ++ if (sendctx->other == NULL || ++ !bus_sk(sendctx->other)->authenticated) { ++ ++ if (sendctx->other) ++ sock_put(sendctx->other); ++ ++ if (sendctx->other == NULL) { ++ if (!bus_sk(sk)->bus_master_side) { ++ err = -ENOTCONN; ++ sendctx->other = bus_peer_get(sk); ++ if (!sendctx->other) ++ goto out; ++ } else { ++ sendctx->other = sk; ++ sock_hold(sendctx->other); ++ } ++ } ++ sendctx->to_master = 1; ++ } ++ } ++ } ++ ++ ++try_again: ++ rcp_cnt = 0; ++ main_rcp_found = false; ++ ++ spin_lock(&u->bus->lock); ++ ++ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) { ++ ++ if (!net_eq(sock_net(&s->sk), net)) ++ continue; ++ ++ if (is_receiver(&s->sk, prefix) || ++ (!sendctx->multicast && ++ !sendctx->to_master && ++ &s->sk == sendctx->other)) ++ rcp_cnt++; ++ } ++ ++ spin_unlock(&u->bus->lock); ++ ++ /* ++ * Memory can't be allocated while holding a spinlock so ++ * we have to release the lock, do the allocation for the ++ * array to store each destination peer sk_buff and grab ++ * the bus peer lock again. Peers could have joined the ++ * bus while we relesed the lock so we allocate 5 more ++ * recipients hoping that this will be enough to not having ++ * to try again in case only a few peers joined the bus. ++ */ ++ rcp_cnt += 5; ++ skb_set = kzalloc(sizeof(struct sk_buff *) * rcp_cnt, GFP_KERNEL); ++ ++ if (!skb_set) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ sendctx_set = kzalloc(sizeof(struct bus_send_context *) * rcp_cnt, ++ GFP_KERNEL); ++ if (!sendctx_set) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ for (i = 0; i < rcp_cnt; i++) { ++ skb_set[i] = skb_clone(skb, GFP_KERNEL); ++ if (!skb_set[i]) { ++ err = -ENOMEM; ++ goto out_free; ++ } ++ sendctx_set[i] = BUSCB(skb_set[i]).sendctx ++ = kmalloc(sizeof(*sendctx) * rcp_cnt, GFP_KERNEL); ++ if (!sendctx_set[i]) { ++ err = -ENOMEM; ++ goto out_free; ++ } ++ memcpy(sendctx_set[i], sendctx, sizeof(*sendctx)); ++ err = bus_scm_to_skb(sendctx_set[i]->siocb->scm, ++ skb_set[i], true); ++ if (err < 0) ++ goto out_free; ++ bus_get_secdata(sendctx_set[i]->siocb->scm, ++ skb_set[i]); ++ ++ sendctx_set[i]->other = NULL; ++ } ++ ++ send_cnt = 0; ++ ++ spin_lock(&u->bus->lock); ++ ++ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) { ++ ++ if (!net_eq(sock_net(&s->sk), net)) ++ continue; ++ ++ if (send_cnt >= rcp_cnt) { ++ spin_unlock(&u->bus->lock); ++ ++ for (i = 0; i < rcp_cnt; i++) { ++ sock_put(sendctx_set[i]->other); ++ kfree_skb(skb_set[i]); ++ kfree(sendctx_set[i]); ++ } ++ kfree(skb_set); ++ kfree(sendctx_set); ++ sendctx_set = NULL; ++ skb_set = NULL; ++ goto try_again; ++ } ++ ++ if (is_receiver(&s->sk, prefix) || ++ (!sendctx->multicast && ++ !sendctx->to_master && ++ &s->sk == sendctx->other)) { ++ skb_set_owner_w(skb_set[send_cnt], &s->sk); ++ tmpctx = BUSCB(skb_set[send_cnt]).sendctx; ++ sock_hold(&s->sk); ++ if (&s->sk == sendctx->other) { ++ tmpctx->main_recipient = 1; ++ main_rcp_found = true; ++ } ++ tmpctx->other = &s->sk; ++ tmpctx->recipient = s->addr->name; ++ tmpctx->eavesdropper = bus_eavesdropper(&s->sk, 0); ++ ++ send_cnt++; ++ } ++ } ++ ++ spin_unlock(&u->bus->lock); ++ ++ /* ++ * Peers have left the bus so we have to free ++ * their pre-allocated bus_send_context and ++ * socket buffers. ++ */ ++ if (send_cnt < rcp_cnt) { ++ for (i = send_cnt; i < rcp_cnt; i++) { ++ kfree_skb(skb_set[i]); ++ kfree(sendctx_set[i]); ++ } ++ rcp_cnt = send_cnt; ++ } ++ ++ for (i = 0; i < send_cnt; i++) { ++ tmpctx = BUSCB(skb_set[i]).sendctx; ++ tmpctx->deliver = 0; ++ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb_set[i], ++ NULL, NULL, bus_sendmsg_finish); ++ if (err == -EPERM) ++ sock_put(tmpctx->other); ++ } ++ ++ /* ++ * If the send context is not multicast, the destination ++ * coud be either the peer accepted socket descriptor or ++ * a peer that is not an eavesdropper. If the peer is not ++ * the accepted socket descriptor and has been authenticated, ++ * it is a member of the bus peer list so it has already been ++ * marked for delivery. ++ * But if the destination is the accepted socket descriptor ++ * or is a non-authenticated peer it is not a member of the ++ * bus peer list so the packet has to be explicitly deliver ++ * to it. ++ */ ++ ++ if (!sendctx->multicast && ++ (sendctx->to_master || ++ (sendctx->bus_master_side && !main_rcp_found))) { ++ sendctx->main_recipient = 1; ++ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL, ++ bus_sendmsg_finish); ++ if (err == -EPERM) ++ sock_put(sendctx->other); ++ } ++ ++ spin_lock(&u->bus->send_lock); ++ ++ for (i = 0; i < send_cnt; i++) { ++ tmpctx = sendctx_set[i]; ++ if (tmpctx->deliver != 1) ++ continue; ++ ++ bus_state_lock(tmpctx->other); ++ bus_deliver_skb(skb_set[i]); ++ bus_state_unlock(tmpctx->other); ++ } ++ ++ if (!sendctx->multicast && ++ sendctx->deliver == 1 && ++ !bus_sk(sendctx->other)->eavesdropper) { ++ bus_state_lock(sendctx->other); ++ bus_deliver_skb(skb); ++ bus_state_unlock(sendctx->other); ++ } ++ ++ spin_unlock(&u->bus->send_lock); ++ ++ for (i = 0; i < send_cnt; i++) { ++ tmpctx = sendctx_set[i]; ++ if (tmpctx->deliver != 1) ++ continue; ++ ++ tmpctx->other->sk_data_ready(tmpctx->other, 0); ++ sock_put(tmpctx->other); ++ } ++ ++ if (!sendctx->multicast && ++ sendctx->deliver == 1 && ++ !bus_sk(sendctx->other)->eavesdropper) { ++ sendctx->other->sk_data_ready(sendctx->other, 0); ++ sock_put(sendctx->other); ++ } ++ ++ err = len; ++ goto out; ++ ++out_free: ++ for (i = 0; i < rcp_cnt; i++) { ++ if (skb_set[i]) ++ kfree_skb(skb_set[i]); ++ } ++ ++out: ++ kfree(skb_set); ++ if (sendctx_set) { ++ for (i = 0; i < rcp_cnt; i++) ++ kfree(sendctx_set[i]); ++ kfree(sendctx_set); ++ } ++ ++ if (sendctx->deliver == 0) { ++ if (!sendctx->to_master && ++ !(sendctx->bus_master_side && !main_rcp_found)) ++ kfree_skb(skb); ++ if (!sendctx->to_master && ++ !(sendctx->bus_master_side && !main_rcp_found)) ++ if (sendctx->other) ++ sock_put(sendctx->other); ++ } ++ scm_destroy(sendctx->siocb->scm); ++ ++ return err; ++} ++ ++static inline void bus_copy_path(struct sockaddr_bus *dest, ++ struct sockaddr_bus *src) ++{ ++ int offset; ++ ++ /* ++ * abstract path names start with a null byte character, ++ * so they have to be compared starting at the second char. ++ */ ++ offset = (src->sbus_path[0] == '\0'); ++ ++ strncpy(dest->sbus_path + offset, ++ src->sbus_path + offset, ++ BUS_PATH_MAX); ++} ++ ++/** ++ * bus_sendmsg - send an skb to a destination ++ * @kiocb: I/O control block info ++ * @sock: sender socket ++ * @msg: message header ++ * @len: message length ++ * ++ * Send an socket buffer to a destination. The destination could be ++ * either an unicast or a multicast address. In any case, a copy of ++ * the packet has to be send to all the sockets that are allowed to ++ * eavesdrop the communication bus. ++ * ++ * If the destination address is not associated with any socket, the ++ * packet is default routed to the bus master (the sender accepted ++ * socket). ++ * ++ * The af_bus sending path is hooked to the netfilter subsystem so ++ * netfilter hooks can filter or modify the packet before delivery. ++ */ ++static int bus_sendmsg(struct kiocb *kiocb, struct socket *sock, ++ struct msghdr *msg, size_t len) ++{ ++ struct sock *sk = sock->sk; ++ struct bus_sock *u = bus_sk(sk); ++ struct sockaddr_bus *sbusaddr = msg->msg_name; ++ int err; ++ struct sk_buff *skb; ++ struct scm_cookie tmp_scm; ++ bool to_master = false; ++ bool multicast = false; ++ struct bus_send_context sendctx; ++ ++ err = sock_error(sk); ++ if (err) ++ return err; ++ ++ if (sk->sk_state != BUS_ESTABLISHED) ++ return -ENOTCONN; ++ ++ if (!msg->msg_namelen) ++ sbusaddr = NULL; ++ ++ if (sbusaddr) ++ bus_copy_path(sbusaddr, u->addr->name); ++ ++ if ((!sbusaddr && !u->bus_master_side) || ++ (sbusaddr && sbusaddr->sbus_addr.s_addr == BUS_MASTER_ADDR)) ++ to_master = true; ++ else if (sbusaddr && !u->bus_master_side && !u->authenticated) ++ return -EHOSTUNREACH; ++ ++ sendctx.namelen = 0; /* fake GCC */ ++ sendctx.siocb = kiocb_to_siocb(kiocb); ++ sendctx.other = NULL; ++ ++ if (NULL == sendctx.siocb->scm) ++ sendctx.siocb->scm = &tmp_scm; ++ wait_for_bus_gc(); ++ err = scm_send(sock, msg, sendctx.siocb->scm); ++ if (err < 0) ++ return err; ++ ++ err = -EOPNOTSUPP; ++ if (msg->msg_flags&MSG_OOB) ++ goto out; ++ ++ if (sbusaddr && !to_master) { ++ err = bus_mkname(sbusaddr, msg->msg_namelen, &sendctx.hash); ++ if (err < 0) ++ goto out; ++ sendctx.namelen = err; ++ multicast = bus_mc_addr(sbusaddr); ++ } else { ++ err = -ENOTCONN; ++ sendctx.other = bus_peer_get(sk); ++ if (!sendctx.other) ++ goto out; ++ } ++ ++ err = -EMSGSIZE; ++ if (len > sk->sk_sndbuf - 32) ++ goto out; ++ ++ sendctx.timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); ++ ++restart: ++ bus_state_lock(sk); ++ if (bus_recvq_full(sk)) { ++ err = -EAGAIN; ++ if (!sendctx.timeo) { ++ bus_state_unlock(sk); ++ goto out; ++ } ++ ++ sendctx.timeo = bus_wait_for_peer(sk, sendctx.timeo); ++ ++ err = sock_intr_errno(sendctx.timeo); ++ if (signal_pending(current)) ++ goto out; ++ ++ goto restart; ++ } else { ++ bus_state_unlock(sk); ++ } ++ ++ skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); ++ if (skb == NULL) ++ goto out; ++ ++ err = bus_scm_to_skb(sendctx.siocb->scm, skb, true); ++ if (err < 0) ++ goto out_free; ++ sendctx.max_level = err + 1; ++ bus_get_secdata(sendctx.siocb->scm, skb); ++ ++ skb_reset_transport_header(skb); ++ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); ++ if (err) ++ goto out_free; ++ ++ sendctx.sender_socket = sock; ++ if (u->bus_master_side && sendctx.other) { ++ /* if the bus master sent an unicast message to a peer, we ++ * need the address of that peer ++ */ ++ sendctx.sender = bus_sk(sendctx.other)->addr->name; ++ } else { ++ sendctx.sender = u->addr->name; ++ } ++ sendctx.recipient = sbusaddr; ++ sendctx.authenticated = u->authenticated; ++ sendctx.bus_master_side = u->bus_master_side; ++ sendctx.to_master = to_master; ++ sendctx.multicast = multicast; ++ sendctx.eavesdropper = atomic64_read(&u->bus->eavesdropper_cnt) ? 1 : 0; ++ BUSCB(skb).sendctx = &sendctx; ++ ++ if (sendctx.multicast || sendctx.eavesdropper) { ++ sendctx.main_recipient = 0; ++ err = bus_sendmsg_mcast(skb); ++ return sendctx.multicast ? len : err; ++ } else { ++ sendctx.main_recipient = 1; ++ len = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL, ++ bus_sendmsg_finish); ++ ++ if (len == -EPERM) { ++ err = len; ++ goto out; ++ } else { ++ scm_destroy(sendctx.siocb->scm); ++ return len; ++ } ++ } ++ ++out_free: ++ kfree_skb(skb); ++out: ++ if (sendctx.other) ++ sock_put(sendctx.other); ++ scm_destroy(sendctx.siocb->scm); ++ return err; ++} ++ ++static void bus_copy_addr(struct msghdr *msg, struct sock *sk) ++{ ++ struct bus_sock *u = bus_sk(sk); ++ ++ msg->msg_namelen = 0; ++ if (u->addr) { ++ msg->msg_namelen = u->addr->len; ++ memcpy(msg->msg_name, u->addr->name, ++ sizeof(struct sockaddr_bus)); ++ } ++} ++ ++static int bus_recvmsg(struct kiocb *iocb, struct socket *sock, ++ struct msghdr *msg, size_t size, int flags) ++{ ++ struct sock_iocb *siocb = kiocb_to_siocb(iocb); ++ struct scm_cookie tmp_scm; ++ struct sock *sk = sock->sk; ++ struct bus_sock *u = bus_sk(sk); ++ int noblock = flags & MSG_DONTWAIT; ++ struct sk_buff *skb; ++ int err; ++ int peeked, skip; ++ ++ if (sk->sk_state != BUS_ESTABLISHED) ++ return -ENOTCONN; ++ ++ err = -EOPNOTSUPP; ++ if (flags&MSG_OOB) ++ goto out; ++ ++ msg->msg_namelen = 0; ++ ++ err = mutex_lock_interruptible(&u->readlock); ++ if (err) { ++ err = sock_intr_errno(sock_rcvtimeo(sk, noblock)); ++ goto out; ++ } ++ ++ skip = sk_peek_offset(sk, flags); ++ ++ skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err); ++ if (!skb) { ++ bus_state_lock(sk); ++ /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ ++ if (err == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN)) ++ err = 0; ++ bus_state_unlock(sk); ++ goto out_unlock; ++ } ++ ++ wake_up_interruptible_sync_poll(&u->peer_wait, ++ POLLOUT | POLLWRNORM | POLLWRBAND); ++ ++ if (msg->msg_name) ++ bus_copy_addr(msg, skb->sk); ++ ++ if (size > skb->len - skip) ++ size = skb->len - skip; ++ else if (size < skb->len - skip) ++ msg->msg_flags |= MSG_TRUNC; ++ ++ err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size); ++ if (err) ++ goto out_free; ++ ++ if (sock_flag(sk, SOCK_RCVTSTAMP)) ++ __sock_recv_timestamp(msg, sk, skb); ++ ++ if (!siocb->scm) { ++ siocb->scm = &tmp_scm; ++ memset(&tmp_scm, 0, sizeof(tmp_scm)); ++ } ++ scm_set_cred(siocb->scm, BUSCB(skb).pid, BUSCB(skb).cred); ++ bus_set_secdata(siocb->scm, skb); ++ ++ if (!(flags & MSG_PEEK)) { ++ if (BUSCB(skb).fp) ++ bus_detach_fds(siocb->scm, skb); ++ ++ sk_peek_offset_bwd(sk, skb->len); ++ } else { ++ /* It is questionable: on PEEK we could: ++ - do not return fds - good, but too simple 8) ++ - return fds, and do not return them on read (old strategy, ++ apparently wrong) ++ - clone fds (I chose it for now, it is the most universal ++ solution) ++ ++ POSIX 1003.1g does not actually define this clearly ++ at all. POSIX 1003.1g doesn't define a lot of things ++ clearly however! ++ ++ */ ++ ++ sk_peek_offset_fwd(sk, size); ++ ++ if (BUSCB(skb).fp) ++ siocb->scm->fp = scm_fp_dup(BUSCB(skb).fp); ++ } ++ err = (flags & MSG_TRUNC) ? skb->len - skip : size; ++ ++ scm_recv(sock, msg, siocb->scm, flags); ++ ++out_free: ++ skb_free_datagram(sk, skb); ++out_unlock: ++ mutex_unlock(&u->readlock); ++out: ++ return err; ++} ++ ++static int bus_shutdown(struct socket *sock, int mode) ++{ ++ struct sock *sk = sock->sk; ++ struct sock *other; ++ ++ mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN); ++ ++ if (!mode) ++ return 0; ++ ++ bus_state_lock(sk); ++ sk->sk_shutdown |= mode; ++ other = bus_peer(sk); ++ if (other) ++ sock_hold(other); ++ bus_state_unlock(sk); ++ sk->sk_state_change(sk); ++ ++ if (other) { ++ ++ int peer_mode = 0; ++ ++ if (mode&RCV_SHUTDOWN) ++ peer_mode |= SEND_SHUTDOWN; ++ if (mode&SEND_SHUTDOWN) ++ peer_mode |= RCV_SHUTDOWN; ++ bus_state_lock(other); ++ other->sk_shutdown |= peer_mode; ++ bus_state_unlock(other); ++ other->sk_state_change(other); ++ if (peer_mode == SHUTDOWN_MASK) ++ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); ++ else if (peer_mode & RCV_SHUTDOWN) ++ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); ++ sock_put(other); ++ } ++ ++ return 0; ++} ++ ++static int bus_add_addr(struct sock *sk, struct bus_addr *sbus_addr) ++{ ++ struct bus_address *addr; ++ struct sock *other; ++ struct bus_sock *u = bus_sk(sk); ++ struct net *net = sock_net(sk); ++ int ret = 0; ++ ++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); ++ if (!addr) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memcpy(addr->name, u->addr->name, sizeof(struct sockaddr_bus)); ++ addr->len = u->addr->len; ++ ++ addr->name->sbus_addr.s_addr = sbus_addr->s_addr; ++ addr->hash = bus_compute_hash(addr->name->sbus_addr); ++ other = bus_find_socket_byaddress(net, addr->name, addr->len, ++ sk->sk_protocol, addr->hash); ++ ++ if (other) { ++ sock_put(other); ++ kfree(addr); ++ ret = -EADDRINUSE; ++ goto out; ++ } ++ ++ atomic_set(&addr->refcnt, 1); ++ INIT_HLIST_NODE(&addr->addr_node); ++ INIT_HLIST_NODE(&addr->table_node); ++ ++ addr->sock = sk; ++ ++ hlist_add_head(&addr->addr_node, &u->addr_list); ++ bus_insert_address(&bus_address_table[addr->hash], addr); ++ ++out: ++ sock_put(sk); ++ ++ return ret; ++} ++ ++static int bus_del_addr(struct sock *sk, struct bus_addr *sbus_addr) ++{ ++ struct bus_address *addr; ++ int ret = 0; ++ ++ bus_state_lock(sk); ++ addr = __bus_get_address(sk, sbus_addr); ++ if (!addr) { ++ ret = -EINVAL; ++ bus_state_unlock(sk); ++ goto out; ++ } ++ hlist_del(&addr->addr_node); ++ bus_state_unlock(sk); ++ ++ bus_remove_address(addr); ++ bus_release_addr(addr); ++out: ++ sock_put(sk); ++ ++ return ret; ++} ++ ++static int bus_join_bus(struct sock *sk) ++{ ++ struct sock *peer; ++ struct bus_sock *u = bus_sk(sk), *peeru; ++ int err = 0; ++ ++ peer = bus_peer_get(sk); ++ if (!peer) ++ return -ENOTCONN; ++ peeru = bus_sk(peer); ++ ++ if (!u->bus_master_side || peeru->authenticated) { ++ err = -EINVAL; ++ goto sock_put_out; ++ } ++ ++ if (sk->sk_state != BUS_ESTABLISHED) { ++ err = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ if (peer->sk_shutdown != 0) { ++ err = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ bus_state_lock(peer); ++ peeru->authenticated = true; ++ bus_state_unlock(peer); ++ ++ spin_lock(&u->bus->lock); ++ hlist_add_head(&peeru->bus_node, &u->bus->peers); ++ spin_unlock(&u->bus->lock); ++ ++sock_put_out: ++ sock_put(peer); ++ return err; ++} ++ ++static int __bus_set_eavesdrop(struct sock *sk, bool eavesdrop) ++{ ++ struct sock *peer = bus_peer_get(sk); ++ struct bus_sock *u = bus_sk(sk), *peeru; ++ int err = 0; ++ ++ if (!peer) ++ return -ENOTCONN; ++ ++ if (sk->sk_state != BUS_ESTABLISHED) { ++ err = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ peeru = bus_sk(peer); ++ ++ if (!u->bus_master_side || !peeru->authenticated) { ++ err = -EINVAL; ++ goto sock_put_out; ++ } ++ ++ if (peer->sk_shutdown != 0) { ++ err = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ bus_state_lock(peeru); ++ if (peeru->eavesdropper != eavesdrop) { ++ peeru->eavesdropper = eavesdrop; ++ if (eavesdrop) ++ atomic64_inc(&u->bus->eavesdropper_cnt); ++ else ++ atomic64_dec(&u->bus->eavesdropper_cnt); ++ } ++ bus_state_unlock(peeru); ++ ++sock_put_out: ++ sock_put(peer); ++ return err; ++} ++ ++static int bus_set_eavesdrop(struct sock *sk) ++{ ++ return __bus_set_eavesdrop(sk, true); ++} ++ ++static int bus_unset_eavesdrop(struct sock *sk) ++{ ++ return __bus_set_eavesdrop(sk, false); ++} ++ ++static inline void sk_sendbuf_set(struct sock *sk, int sndbuf) ++{ ++ bus_state_lock(sk); ++ sk->sk_sndbuf = sndbuf; ++ bus_state_unlock(sk); ++} ++ ++static inline void sk_maxqlen_set(struct sock *sk, int qlen) ++{ ++ bus_state_lock(sk); ++ sk->sk_max_ack_backlog = qlen; ++ bus_state_unlock(sk); ++} ++ ++static int bus_get_qlenfull(struct sock *sk) ++{ ++ struct sock *peer; ++ struct bus_sock *u = bus_sk(sk), *peeru; ++ int ret = 0; ++ ++ peer = bus_peer_get(sk); ++ if (!peer) ++ return -ENOTCONN; ++ ++ peeru = bus_sk(peer); ++ ++ if (!u->bus_master_side || peeru->authenticated) { ++ ret = -EINVAL; ++ goto sock_put_out; ++ } ++ ++ if (sk->sk_state != BUS_ESTABLISHED) { ++ ret = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ if (peer->sk_shutdown != 0) { ++ ret = -ENOTCONN; ++ goto sock_put_out; ++ } ++ ++ ret = bus_recvq_full(peer); ++ ++sock_put_out: ++ sock_put(peer); ++ return ret; ++} ++ ++static int bus_setsockopt(struct socket *sock, int level, int optname, ++ char __user *optval, unsigned int optlen) ++{ ++ struct bus_addr addr; ++ int res; ++ int val; ++ ++ if (level != SOL_BUS) ++ return -ENOPROTOOPT; ++ ++ switch (optname) { ++ case BUS_ADD_ADDR: ++ case BUS_DEL_ADDR: ++ if (optlen < sizeof(struct bus_addr)) ++ return -EINVAL; ++ ++ if (!bus_sk(sock->sk)->bus_master_side) ++ return -EINVAL; ++ ++ if (copy_from_user(&addr, optval, sizeof(struct bus_addr))) ++ return -EFAULT; ++ ++ if (optname == BUS_ADD_ADDR) ++ res = bus_add_addr(bus_peer_get(sock->sk), &addr); ++ else ++ res = bus_del_addr(bus_peer_get(sock->sk), &addr); ++ break; ++ case BUS_JOIN_BUS: ++ res = bus_join_bus(sock->sk); ++ break; ++ case BUS_SET_EAVESDROP: ++ res = bus_set_eavesdrop(sock->sk); ++ break; ++ case BUS_UNSET_EAVESDROP: ++ res = bus_unset_eavesdrop(sock->sk); ++ break; ++ case BUS_SET_SENDBUF: ++ case BUS_SET_MAXQLEN: ++ if (sock->sk->sk_state != BUS_LISTEN) { ++ res = -EINVAL; ++ } else { ++ res = -EFAULT; ++ ++ if (copy_from_user(&val, optval, optlen)) ++ break; ++ ++ res = 0; ++ ++ if (optname == BUS_SET_SENDBUF) ++ sk_sendbuf_set(sock->sk, val); ++ else ++ sk_maxqlen_set(sock->sk, val); ++ } ++ break; ++ case BUS_GET_QLENFULL: ++ res = bus_get_qlenfull(sock->sk); ++ ++ if (copy_to_user(&res, optval, optlen)) { ++ res = -EFAULT; ++ break; ++ } ++ res = 0; ++ break; ++ default: ++ res = -EINVAL; ++ break; ++ } ++ ++ return res; ++} ++ ++long bus_inq_len(struct sock *sk) ++{ ++ struct sk_buff *skb; ++ long amount = 0; ++ ++ if (sk->sk_state == BUS_LISTEN) ++ return -EINVAL; ++ ++ spin_lock(&sk->sk_receive_queue.lock); ++ skb_queue_walk(&sk->sk_receive_queue, skb) ++ amount += skb->len; ++ spin_unlock(&sk->sk_receive_queue.lock); ++ ++ return amount; ++} ++EXPORT_SYMBOL_GPL(bus_inq_len); ++ ++long bus_outq_len(struct sock *sk) ++{ ++ return sk_wmem_alloc_get(sk); ++} ++EXPORT_SYMBOL_GPL(bus_outq_len); ++ ++static int bus_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct sock *sk = sock->sk; ++ long amount = 0; ++ int err; ++ ++ switch (cmd) { ++ case SIOCOUTQ: ++ amount = bus_outq_len(sk); ++ err = put_user(amount, (int __user *)arg); ++ break; ++ case SIOCINQ: ++ amount = bus_inq_len(sk); ++ if (amount < 0) ++ err = amount; ++ else ++ err = put_user(amount, (int __user *)arg); ++ break; ++ default: ++ err = -ENOIOCTLCMD; ++ break; ++ } ++ return err; ++} ++ ++static unsigned int bus_poll(struct file *file, struct socket *sock, ++ poll_table *wait) ++{ ++ struct sock *sk = sock->sk, *other; ++ unsigned int mask, writable; ++ struct bus_sock *u = bus_sk(sk), *p; ++ struct hlist_node *node; ++ ++ sock_poll_wait(file, sk_sleep(sk), wait); ++ mask = 0; ++ ++ /* exceptional events? */ ++ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) ++ mask |= POLLERR; ++ if (sk->sk_shutdown & RCV_SHUTDOWN) ++ mask |= POLLRDHUP | POLLIN | POLLRDNORM; ++ if (sk->sk_shutdown == SHUTDOWN_MASK) ++ mask |= POLLHUP; ++ ++ /* readable? */ ++ if (!skb_queue_empty(&sk->sk_receive_queue)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ /* Connection-based need to check for termination and startup */ ++ if (sk->sk_state == BUS_CLOSE) ++ mask |= POLLHUP; ++ ++ /* No write status requested, avoid expensive OUT tests. */ ++ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) ++ return mask; ++ ++ writable = bus_writable(sk); ++ other = bus_peer_get(sk); ++ if (other) { ++ if (bus_recvq_full(other)) ++ writable = 0; ++ sock_put(other); ++ } ++ ++ /* ++ * If the socket has already joined the bus we have to check ++ * that each peer receiver queue on the bus is not full. ++ */ ++ if (!u->bus_master_side && u->authenticated) { ++ spin_lock(&u->bus->lock); ++ hlist_for_each_entry(p, node, &u->bus->peers, bus_node) { ++ if (bus_recvq_full(&p->sk)) { ++ writable = 0; ++ break; ++ } ++ } ++ spin_unlock(&u->bus->lock); ++ } ++ ++ if (writable) ++ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; ++ else ++ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); ++ ++ return mask; ++} ++ ++#ifdef CONFIG_PROC_FS ++static struct sock *first_bus_socket(int *i) ++{ ++ for (*i = 0; *i <= BUS_HASH_SIZE; (*i)++) { ++ if (!hlist_empty(&bus_socket_table[*i])) ++ return __sk_head(&bus_socket_table[*i]); ++ } ++ return NULL; ++} ++ ++static struct sock *next_bus_socket(int *i, struct sock *s) ++{ ++ struct sock *next = sk_next(s); ++ /* More in this chain? */ ++ if (next) ++ return next; ++ /* Look for next non-empty chain. */ ++ for ((*i)++; *i <= BUS_HASH_SIZE; (*i)++) { ++ if (!hlist_empty(&bus_socket_table[*i])) ++ return __sk_head(&bus_socket_table[*i]); ++ } ++ return NULL; ++} ++ ++struct bus_iter_state { ++ struct seq_net_private p; ++ int i; ++}; ++ ++static struct sock *bus_seq_idx(struct seq_file *seq, loff_t pos) ++{ ++ struct bus_iter_state *iter = seq->private; ++ loff_t off = 0; ++ struct sock *s; ++ ++ for (s = first_bus_socket(&iter->i); s; ++ s = next_bus_socket(&iter->i, s)) { ++ if (sock_net(s) != seq_file_net(seq)) ++ continue; ++ if (off == pos) ++ return s; ++ ++off; ++ } ++ return NULL; ++} ++ ++static void *bus_seq_start(struct seq_file *seq, loff_t *pos) ++ __acquires(bus_table_lock) ++{ ++ spin_lock(&bus_table_lock); ++ return *pos ? bus_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN; ++} ++ ++static void *bus_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++{ ++ struct bus_iter_state *iter = seq->private; ++ struct sock *sk = v; ++ ++*pos; ++ ++ if (v == SEQ_START_TOKEN) ++ sk = first_bus_socket(&iter->i); ++ else ++ sk = next_bus_socket(&iter->i, sk); ++ while (sk && (sock_net(sk) != seq_file_net(seq))) ++ sk = next_bus_socket(&iter->i, sk); ++ return sk; ++} ++ ++static void bus_seq_stop(struct seq_file *seq, void *v) ++ __releases(bus_table_lock) ++{ ++ spin_unlock(&bus_table_lock); ++} ++ ++static int bus_seq_show(struct seq_file *seq, void *v) ++{ ++ ++ if (v == SEQ_START_TOKEN) ++ seq_puts(seq, "Num RefCount Protocol Flags Type St " \ ++ "Inode Path\n"); ++ else { ++ struct sock *s = v; ++ struct bus_sock *u = bus_sk(s); ++ bus_state_lock(s); ++ ++ seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", ++ s, ++ atomic_read(&s->sk_refcnt), ++ 0, ++ s->sk_state == BUS_LISTEN ? __SO_ACCEPTCON : 0, ++ s->sk_type, ++ s->sk_socket ? ++ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : ++ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), ++ sock_i_ino(s)); ++ ++ if (u->addr) { ++ int i, len; ++ seq_putc(seq, ' '); ++ ++ i = 0; ++ len = u->addr->len - sizeof(short); ++ if (!BUS_ABSTRACT(s)) ++ len--; ++ else { ++ seq_putc(seq, '@'); ++ i++; ++ } ++ for ( ; i < len; i++) ++ seq_putc(seq, u->addr->name->sbus_path[i]); ++ } ++ bus_state_unlock(s); ++ seq_putc(seq, '\n'); ++ } ++ ++ return 0; ++} ++ ++static const struct seq_operations bus_seq_ops = { ++ .start = bus_seq_start, ++ .next = bus_seq_next, ++ .stop = bus_seq_stop, ++ .show = bus_seq_show, ++}; ++ ++static int bus_seq_open(struct inode *inode, struct file *file) ++{ ++ return seq_open_net(inode, file, &bus_seq_ops, ++ sizeof(struct bus_iter_state)); ++} ++ ++static const struct file_operations bus_seq_fops = { ++ .owner = THIS_MODULE, ++ .open = bus_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release_net, ++}; ++ ++#endif ++ ++static const struct net_proto_family bus_family_ops = { ++ .family = PF_BUS, ++ .create = bus_create, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init af_bus_init(void) ++{ ++ int rc = -1; ++ struct sk_buff *dummy_skb; ++ ++ BUILD_BUG_ON(sizeof(struct bus_skb_parms) > sizeof(dummy_skb->cb)); ++ ++ rc = proto_register(&bus_proto, 1); ++ if (rc != 0) { ++ pr_crit("%s: Cannot create bus_sock SLAB cache!\n", __func__); ++ return rc; ++ } ++ ++ sock_register(&bus_family_ops); ++ return rc; ++} ++ ++static void __exit af_bus_exit(void) ++{ ++ sock_unregister(PF_BUS); ++ proto_unregister(&bus_proto); ++} ++ ++module_init(af_bus_init); ++module_exit(af_bus_exit); ++ ++MODULE_AUTHOR("Alban Crequy, Javier Martinez Canillas"); ++MODULE_DESCRIPTION("Linux Bus domain sockets"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_NETPROTO(PF_BUS); +Index: git/net/bus/garbage.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/bus/garbage.c 2012-10-05 13:37:11.000000000 +0300 +@@ -0,0 +1,322 @@ ++/* ++ * Garbage Collector For AF_BUS sockets ++ * ++ * Based on Garbage Collector For AF_UNIX sockets (net/unix/garbage.c). ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/socket.h> ++#include <linux/un.h> ++#include <linux/net.h> ++#include <linux/fs.h> ++#include <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include <linux/file.h> ++#include <linux/proc_fs.h> ++#include <linux/mutex.h> ++#include <linux/wait.h> ++ ++#include <net/sock.h> ++#include <net/af_bus.h> ++#include <net/scm.h> ++#include <net/tcp_states.h> ++ ++/* Internal data structures and random procedures: */ ++ ++static LIST_HEAD(gc_inflight_list); ++static LIST_HEAD(gc_candidates); ++static DEFINE_SPINLOCK(bus_gc_lock); ++static DECLARE_WAIT_QUEUE_HEAD(bus_gc_wait); ++ ++unsigned int bus_tot_inflight; ++ ++ ++struct sock *bus_get_socket(struct file *filp) ++{ ++ struct sock *u_sock = NULL; ++ struct inode *inode = filp->f_path.dentry->d_inode; ++ ++ /* ++ * Socket ? ++ */ ++ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { ++ struct socket *sock = SOCKET_I(inode); ++ struct sock *s = sock->sk; ++ ++ /* ++ * PF_BUS ? ++ */ ++ if (s && sock->ops && sock->ops->family == PF_BUS) ++ u_sock = s; ++ } ++ return u_sock; ++} ++ ++/* ++ * Keep the number of times in flight count for the file ++ * descriptor if it is for an AF_BUS socket. ++ */ ++ ++void bus_inflight(struct file *fp) ++{ ++ struct sock *s = bus_get_socket(fp); ++ if (s) { ++ struct bus_sock *u = bus_sk(s); ++ spin_lock(&bus_gc_lock); ++ if (atomic_long_inc_return(&u->inflight) == 1) { ++ BUG_ON(!list_empty(&u->link)); ++ list_add_tail(&u->link, &gc_inflight_list); ++ } else { ++ BUG_ON(list_empty(&u->link)); ++ } ++ bus_tot_inflight++; ++ spin_unlock(&bus_gc_lock); ++ } ++} ++ ++void bus_notinflight(struct file *fp) ++{ ++ struct sock *s = bus_get_socket(fp); ++ if (s) { ++ struct bus_sock *u = bus_sk(s); ++ spin_lock(&bus_gc_lock); ++ BUG_ON(list_empty(&u->link)); ++ if (atomic_long_dec_and_test(&u->inflight)) ++ list_del_init(&u->link); ++ bus_tot_inflight--; ++ spin_unlock(&bus_gc_lock); ++ } ++} ++ ++static void scan_inflight(struct sock *x, void (*func)(struct bus_sock *), ++ struct sk_buff_head *hitlist) ++{ ++ struct sk_buff *skb; ++ struct sk_buff *next; ++ ++ spin_lock(&x->sk_receive_queue.lock); ++ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { ++ /* ++ * Do we have file descriptors ? ++ */ ++ if (BUSCB(skb).fp) { ++ bool hit = false; ++ /* ++ * Process the descriptors of this socket ++ */ ++ int nfd = BUSCB(skb).fp->count; ++ struct file **fp = BUSCB(skb).fp->fp; ++ while (nfd--) { ++ /* ++ * Get the socket the fd matches ++ * if it indeed does so ++ */ ++ struct sock *sk = bus_get_socket(*fp++); ++ if (sk) { ++ struct bus_sock *u = bus_sk(sk); ++ ++ /* ++ * Ignore non-candidates, they could ++ * have been added to the queues after ++ * starting the garbage collection ++ */ ++ if (u->gc_candidate) { ++ hit = true; ++ func(u); ++ } ++ } ++ } ++ if (hit && hitlist != NULL) { ++ __skb_unlink(skb, &x->sk_receive_queue); ++ __skb_queue_tail(hitlist, skb); ++ } ++ } ++ } ++ spin_unlock(&x->sk_receive_queue.lock); ++} ++ ++static void scan_children(struct sock *x, void (*func)(struct bus_sock *), ++ struct sk_buff_head *hitlist) ++{ ++ if (x->sk_state != TCP_LISTEN) ++ scan_inflight(x, func, hitlist); ++ else { ++ struct sk_buff *skb; ++ struct sk_buff *next; ++ struct bus_sock *u; ++ LIST_HEAD(embryos); ++ ++ /* ++ * For a listening socket collect the queued embryos ++ * and perform a scan on them as well. ++ */ ++ spin_lock(&x->sk_receive_queue.lock); ++ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { ++ u = bus_sk(skb->sk); ++ ++ /* ++ * An embryo cannot be in-flight, so it's safe ++ * to use the list link. ++ */ ++ BUG_ON(!list_empty(&u->link)); ++ list_add_tail(&u->link, &embryos); ++ } ++ spin_unlock(&x->sk_receive_queue.lock); ++ ++ while (!list_empty(&embryos)) { ++ u = list_entry(embryos.next, struct bus_sock, link); ++ scan_inflight(&u->sk, func, hitlist); ++ list_del_init(&u->link); ++ } ++ } ++} ++ ++static void dec_inflight(struct bus_sock *usk) ++{ ++ atomic_long_dec(&usk->inflight); ++} ++ ++static void inc_inflight(struct bus_sock *usk) ++{ ++ atomic_long_inc(&usk->inflight); ++} ++ ++static void inc_inflight_move_tail(struct bus_sock *u) ++{ ++ atomic_long_inc(&u->inflight); ++ /* ++ * If this still might be part of a cycle, move it to the end ++ * of the list, so that it's checked even if it was already ++ * passed over ++ */ ++ if (u->gc_maybe_cycle) ++ list_move_tail(&u->link, &gc_candidates); ++} ++ ++static bool gc_in_progress = false; ++#define BUS_INFLIGHT_TRIGGER_GC 16000 ++ ++void wait_for_bus_gc(void) ++{ ++ /* ++ * If number of inflight sockets is insane, ++ * force a garbage collect right now. ++ */ ++ if (bus_tot_inflight > BUS_INFLIGHT_TRIGGER_GC && !gc_in_progress) ++ bus_gc(); ++ wait_event(bus_gc_wait, gc_in_progress == false); ++} ++ ++/* The external entry point: bus_gc() */ ++void bus_gc(void) ++{ ++ struct bus_sock *u; ++ struct bus_sock *next; ++ struct sk_buff_head hitlist; ++ struct list_head cursor; ++ LIST_HEAD(not_cycle_list); ++ ++ spin_lock(&bus_gc_lock); ++ ++ /* Avoid a recursive GC. */ ++ if (gc_in_progress) ++ goto out; ++ ++ gc_in_progress = true; ++ /* ++ * First, select candidates for garbage collection. Only ++ * in-flight sockets are considered, and from those only ones ++ * which don't have any external reference. ++ * ++ * Holding bus_gc_lock will protect these candidates from ++ * being detached, and hence from gaining an external ++ * reference. Since there are no possible receivers, all ++ * buffers currently on the candidates' queues stay there ++ * during the garbage collection. ++ * ++ * We also know that no new candidate can be added onto the ++ * receive queues. Other, non candidate sockets _can_ be ++ * added to queue, so we must make sure only to touch ++ * candidates. ++ */ ++ list_for_each_entry_safe(u, next, &gc_inflight_list, link) { ++ long total_refs; ++ long inflight_refs; ++ ++ total_refs = file_count(u->sk.sk_socket->file); ++ inflight_refs = atomic_long_read(&u->inflight); ++ ++ BUG_ON(inflight_refs < 1); ++ BUG_ON(total_refs < inflight_refs); ++ if (total_refs == inflight_refs) { ++ list_move_tail(&u->link, &gc_candidates); ++ u->gc_candidate = 1; ++ u->gc_maybe_cycle = 1; ++ } ++ } ++ ++ /* ++ * Now remove all internal in-flight reference to children of ++ * the candidates. ++ */ ++ list_for_each_entry(u, &gc_candidates, link) ++ scan_children(&u->sk, dec_inflight, NULL); ++ ++ /* ++ * Restore the references for children of all candidates, ++ * which have remaining references. Do this recursively, so ++ * only those remain, which form cyclic references. ++ * ++ * Use a "cursor" link, to make the list traversal safe, even ++ * though elements might be moved about. ++ */ ++ list_add(&cursor, &gc_candidates); ++ while (cursor.next != &gc_candidates) { ++ u = list_entry(cursor.next, struct bus_sock, link); ++ ++ /* Move cursor to after the current position. */ ++ list_move(&cursor, &u->link); ++ ++ if (atomic_long_read(&u->inflight) > 0) { ++ list_move_tail(&u->link, ¬_cycle_list); ++ u->gc_maybe_cycle = 0; ++ scan_children(&u->sk, inc_inflight_move_tail, NULL); ++ } ++ } ++ list_del(&cursor); ++ ++ /* ++ * not_cycle_list contains those sockets which do not make up a ++ * cycle. Restore these to the inflight list. ++ */ ++ while (!list_empty(¬_cycle_list)) { ++ u = list_entry(not_cycle_list.next, struct bus_sock, link); ++ u->gc_candidate = 0; ++ list_move_tail(&u->link, &gc_inflight_list); ++ } ++ ++ /* ++ * Now gc_candidates contains only garbage. Restore original ++ * inflight counters for these as well, and remove the skbuffs ++ * which are creating the cycle(s). ++ */ ++ skb_queue_head_init(&hitlist); ++ list_for_each_entry(u, &gc_candidates, link) ++ scan_children(&u->sk, inc_inflight, &hitlist); ++ ++ spin_unlock(&bus_gc_lock); ++ ++ /* Here we are. Hitlist is filled. Die. */ ++ __skb_queue_purge(&hitlist); ++ ++ spin_lock(&bus_gc_lock); ++ ++ /* All candidates should have been detached by now. */ ++ BUG_ON(!list_empty(&gc_candidates)); ++ gc_in_progress = false; ++ wake_up(&bus_gc_wait); ++ ++ out: ++ spin_unlock(&bus_gc_lock); ++} +Index: git/net/core/scm.c +=================================================================== +--- git.orig/net/core/scm.c 2012-10-05 12:12:51.000000000 +0300 ++++ git/net/core/scm.c 2012-10-05 13:38:54.000000000 +0300 +@@ -158,7 +158,8 @@ + switch (cmsg->cmsg_type) + { + case SCM_RIGHTS: +- if (!sock->ops || sock->ops->family != PF_UNIX) ++ if (!sock->ops || (sock->ops->family != PF_UNIX && ++ sock->ops->family != PF_BUS)) + goto error; + err=scm_fp_copy(cmsg, &p->fp); + if (err<0) +Index: git/net/core/sock.c +=================================================================== +--- git.orig/net/core/sock.c 2012-10-05 12:12:51.000000000 +0300 ++++ git/net/core/sock.c 2012-10-05 13:42:37.000000000 +0300 +@@ -205,7 +205,7 @@ + "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , + "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , + "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" , +- "sk_lock-AF_NFC" , "sk_lock-AF_MAX" ++ "sk_lock-AF_NFC" , "sk_lock-AF_BUS" , "sk_lock-AF_MAX" + }; + static const char *const af_family_slock_key_strings[AF_MAX+1] = { + "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , +@@ -221,7 +221,7 @@ + "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , + "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , + "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" , +- "slock-AF_NFC" , "slock-AF_MAX" ++ "slock-AF_NFC" , "slock-AF_BUS" , "slock-AF_MAX" + }; + static const char *const af_family_clock_key_strings[AF_MAX+1] = { + "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , +@@ -237,7 +237,7 @@ + "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , + "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , + "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" , +- "clock-AF_NFC" , "clock-AF_MAX" ++ "clock-AF_NFC" , "clock-AF_BUS" , "clock-AF_MAX" + }; + + /* +Index: git/net/netfilter/Kconfig +=================================================================== +--- git.orig/net/netfilter/Kconfig 2012-10-05 12:13:57.000000000 +0300 ++++ git/net/netfilter/Kconfig 2012-10-05 13:43:47.000000000 +0300 +@@ -1193,3 +1193,5 @@ + source "net/netfilter/ipset/Kconfig" + + source "net/netfilter/ipvs/Kconfig" ++ ++source "net/netfilter/nfdbus/Kconfig" +Index: git/net/netfilter/Makefile +=================================================================== +--- git.orig/net/netfilter/Makefile 2012-10-05 12:13:57.000000000 +0300 ++++ git/net/netfilter/Makefile 2012-10-05 13:44:39.000000000 +0300 +@@ -121,3 +121,6 @@ + + # IPVS + obj-$(CONFIG_IP_VS) += ipvs/ ++ ++# Dbus ++obj-$(CONFIG_NETFILTER_DBUS) += nfdbus/ +Index: git/net/netfilter/nfdbus/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/Kconfig 2012-10-05 13:47:00.000000000 +0300 +@@ -0,0 +1,12 @@ ++# ++# Netfilter D-Bus module configuration ++# ++config NETFILTER_DBUS ++ tristate "Netfilter D-bus (EXPERIMENTAL)" ++ depends on AF_BUS && CONNECTOR && EXPERIMENTAL ++ ---help--- ++ If you say Y here, you will include support for a netfilter hook to ++ parse D-Bus messages sent using the AF_BUS socket address family. ++ ++ To compile this as a module, choose M here: the module will be ++ called netfilter_dbus. +Index: git/net/netfilter/nfdbus/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/Makefile 2012-10-05 13:47:47.000000000 +0300 +@@ -0,0 +1,6 @@ ++# ++# Makefile for the netfilter D-Bus module ++# ++obj-$(CONFIG_NETFILTER_DBUS) += netfilter_dbus.o ++ ++netfilter_dbus-y := nfdbus.o message.o matchrule.o +Index: git/net/netfilter/nfdbus/matchrule.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/matchrule.c 2012-10-05 13:50:04.000000000 +0300 +@@ -0,0 +1,1132 @@ ++/* ++ * matchrule.c D-Bus match rule implementation ++ * ++ * Based on signals.c from dbus ++ * ++ * Copyright (C) 2010 Collabora, Ltd. ++ * Copyright (C) 2003, 2005 Red Hat, Inc. ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#include "matchrule.h" ++ ++#include <linux/rbtree.h> ++#include <linux/list.h> ++#include <linux/slab.h> ++ ++#include "message.h" ++ ++enum bus_match_flags { ++ BUS_MATCH_MESSAGE_TYPE = 1 << 0, ++ BUS_MATCH_INTERFACE = 1 << 1, ++ BUS_MATCH_MEMBER = 1 << 2, ++ BUS_MATCH_SENDER = 1 << 3, ++ BUS_MATCH_DESTINATION = 1 << 4, ++ BUS_MATCH_PATH = 1 << 5, ++ BUS_MATCH_ARGS = 1 << 6, ++ BUS_MATCH_PATH_NAMESPACE = 1 << 7, ++ BUS_MATCH_CLIENT_IS_EAVESDROPPING = 1 << 8 ++}; ++ ++struct bus_match_rule { ++ /* For debugging only*/ ++ char *rule_text; ++ ++ unsigned int flags; /**< BusMatchFlags */ ++ ++ int message_type; ++ char *interface; ++ char *member; ++ char *sender; ++ char *destination; ++ char *path; ++ ++ unsigned int *arg_lens; ++ char **args; ++ int args_len; ++ ++ /* bus_match_rule is attached to rule_pool, either in a simple ++ * double-linked list if the rule does not have any interface, or in a ++ * red-black tree sorted by interface. If several rules can have the ++ * same interface, the first one is attached with struct rb_node and the ++ * next ones are in the list ++ */ ++ ++ struct rb_node node; ++ /* Doubly-linked non-circular list. If the rule has an interface, it is ++ * in the rb tree and the single head is right here. Otherwise, the ++ * single head is in rule_pool->rules_without_iface. With this data ++ * structure, we don't need any allocation to insert or remove the rule. ++ */ ++ struct hlist_head first; ++ struct hlist_node list; ++ ++ /* used to delete all names from the tree */ ++ struct list_head del_list; ++}; ++ ++struct dbus_name { ++ struct rb_node node; ++ char *name; ++ ++ /* used to delete all names from the tree */ ++ struct list_head del_list; ++}; ++ ++#define BUS_MATCH_ARG_IS_PATH 0x8000000u ++ ++#define DBUS_STRING_MAX_LENGTH 1024 ++ ++/** Max length of a match rule string; to keep people from hosing the ++ * daemon with some huge rule ++ */ ++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 ++ ++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags) ++{ ++ struct bus_match_rule *rule; ++ ++ rule = kzalloc(sizeof(struct bus_match_rule), gfp_flags); ++ if (rule == NULL) ++ return NULL; ++ ++ return rule; ++} ++ ++void bus_match_rule_free(struct bus_match_rule *rule) ++{ ++ kfree(rule->rule_text); ++ kfree(rule->interface); ++ kfree(rule->member); ++ kfree(rule->sender); ++ kfree(rule->destination); ++ kfree(rule->path); ++ kfree(rule->arg_lens); ++ ++ /* can't use dbus_free_string_array() since there ++ * are embedded NULL ++ */ ++ if (rule->args) { ++ int i; ++ ++ i = 0; ++ while (i < rule->args_len) { ++ kfree(rule->args[i]); ++ ++i; ++ } ++ ++ kfree(rule->args); ++ } ++ ++ kfree(rule); ++} ++ ++static int ++bus_match_rule_set_message_type(struct bus_match_rule *rule, ++ int type, ++ gfp_t gfp_flags) ++{ ++ rule->flags |= BUS_MATCH_MESSAGE_TYPE; ++ ++ rule->message_type = type; ++ ++ return 1; ++} ++ ++static int ++bus_match_rule_set_interface(struct bus_match_rule *rule, ++ const char *interface, ++ gfp_t gfp_flags) ++{ ++ char *new; ++ ++ WARN_ON(!interface); ++ ++ new = kstrdup(interface, gfp_flags); ++ if (new == NULL) ++ return 0; ++ ++ rule->flags |= BUS_MATCH_INTERFACE; ++ kfree(rule->interface); ++ rule->interface = new; ++ ++ return 1; ++} ++ ++static int ++bus_match_rule_set_member(struct bus_match_rule *rule, ++ const char *member, ++ gfp_t gfp_flags) ++{ ++ char *new; ++ ++ WARN_ON(!member); ++ ++ new = kstrdup(member, gfp_flags); ++ if (new == NULL) ++ return 0; ++ ++ rule->flags |= BUS_MATCH_MEMBER; ++ kfree(rule->member); ++ rule->member = new; ++ ++ return 1; ++} ++ ++static int ++bus_match_rule_set_sender(struct bus_match_rule *rule, ++ const char *sender, ++ gfp_t gfp_flags) ++{ ++ char *new; ++ ++ WARN_ON(!sender); ++ ++ new = kstrdup(sender, gfp_flags); ++ if (new == NULL) ++ return 0; ++ ++ rule->flags |= BUS_MATCH_SENDER; ++ kfree(rule->sender); ++ rule->sender = new; ++ ++ return 1; ++} ++ ++static int ++bus_match_rule_set_destination(struct bus_match_rule *rule, ++ const char *destination, ++ gfp_t gfp_flags) ++{ ++ char *new; ++ ++ WARN_ON(!destination); ++ ++ new = kstrdup(destination, gfp_flags); ++ if (new == NULL) ++ return 0; ++ ++ rule->flags |= BUS_MATCH_DESTINATION; ++ kfree(rule->destination); ++ rule->destination = new; ++ ++ return 1; ++} ++ ++#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || \ ++ ((c) == '\r')) ++ ++static int find_key(const char *str, int start, char *key, int *value_pos) ++{ ++ const char *p; ++ const char *s; ++ const char *key_start; ++ const char *key_end; ++ ++ s = str; ++ ++ p = s + start; ++ ++ while (*p && ISWHITE(*p)) ++ ++p; ++ ++ key_start = p; ++ ++ while (*p && *p != '=' && !ISWHITE(*p)) ++ ++p; ++ ++ key_end = p; ++ ++ while (*p && ISWHITE(*p)) ++ ++p; ++ ++ if (key_start == key_end) { ++ /* Empty match rules or trailing whitespace are OK */ ++ *value_pos = p - s; ++ return 1; ++ } ++ ++ if (*p != '=') { ++ pr_warn("Match rule has a key with no subsequent '=' character"); ++ return 0; ++ } ++ ++p; ++ ++ strncat(key, key_start, key_end - key_start); ++ ++ *value_pos = p - s; ++ ++ return 1; ++} ++ ++static int find_value(const char *str, int start, const char *key, char *value, ++ int *value_end) ++{ ++ const char *p; ++ const char *s; ++ char quote_char; ++ int orig_len; ++ ++ orig_len = strlen(value); ++ ++ s = str; ++ ++ p = s + start; ++ ++ quote_char = '\0'; ++ ++ while (*p) { ++ if (quote_char == '\0') { ++ switch (*p) { ++ case '\0': ++ goto done; ++ ++ case '\'': ++ quote_char = '\''; ++ goto next; ++ ++ case ',': ++ ++p; ++ goto done; ++ ++ case '\\': ++ quote_char = '\\'; ++ goto next; ++ ++ default: ++ strncat(value, p, 1); ++ } ++ } else if (quote_char == '\\') { ++ /*\ only counts as an escape if escaping a quote mark */ ++ if (*p != '\'') ++ strncat(value, "\\", 1); ++ ++ strncat(value, p, 1); ++ ++ quote_char = '\0'; ++ } else { ++ if (*p == '\'') ++ quote_char = '\0'; ++ else ++ strncat(value, p, 1); ++ } ++ ++next: ++ ++p; ++ } ++ ++done: ++ ++ if (quote_char == '\\') ++ strncat(value, "\\", 1); ++ else if (quote_char == '\'') { ++ pr_warn("Unbalanced quotation marks in match rule"); ++ return 0; ++ } ++ ++ /* Zero-length values are allowed */ ++ ++ *value_end = p - s; ++ ++ return 1; ++} ++ ++/* duplicates aren't allowed so the real legitimate max is only 6 or ++ * so. Leaving extra so we don't have to bother to update it. ++ * FIXME this is sort of busted now with arg matching, but we let ++ * you match on up to 10 args for now ++ */ ++#define MAX_RULE_TOKENS 16 ++ ++/* this is slightly too high level to be termed a "token" ++ * but let's not be pedantic. ++ */ ++struct rule_token { ++ char *key; ++ char *value; ++}; ++ ++static int tokenize_rule(const char *rule_text, ++ struct rule_token tokens[MAX_RULE_TOKENS], ++ gfp_t gfp_flags) ++{ ++ int i; ++ int pos; ++ int retval; ++ ++ retval = 0; ++ ++ i = 0; ++ pos = 0; ++ while (i < MAX_RULE_TOKENS && ++ pos < strlen(rule_text)) { ++ char *key; ++ char *value; ++ ++ key = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags); ++ if (!key) { ++ pr_err("Out of memory"); ++ return 0; ++ } ++ ++ value = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags); ++ if (!value) { ++ kfree(key); ++ pr_err("Out of memory"); ++ return 0; ++ } ++ ++ if (!find_key(rule_text, pos, key, &pos)) ++ goto out; ++ ++ if (strlen(key) == 0) ++ goto next; ++ ++ tokens[i].key = key; ++ ++ if (!find_value(rule_text, pos, tokens[i].key, value, &pos)) ++ goto out; ++ ++ tokens[i].value = value; ++ ++next: ++ ++i; ++ } ++ ++ retval = 1; ++ ++out: ++ if (!retval) { ++ i = 0; ++ while (tokens[i].key || tokens[i].value) { ++ kfree(tokens[i].key); ++ kfree(tokens[i].value); ++ tokens[i].key = NULL; ++ tokens[i].value = NULL; ++ ++i; ++ } ++ } ++ ++ return retval; ++} ++ ++/* ++ * The format is comma-separated with strings quoted with single quotes ++ * as for the shell (to escape a literal single quote, use '\''). ++ * ++ * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus', ++ * member='Foo', path='/bar/foo',destination=':452345.34' ++ * ++ */ ++struct bus_match_rule *bus_match_rule_parse(const char *rule_text, ++ gfp_t gfp_flags) ++{ ++ struct bus_match_rule *rule; ++ struct rule_token tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ ++ int i; ++ ++ if (strlen(rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) { ++ pr_warn("Match rule text is %ld bytes, maximum is %d", ++ strlen(rule_text), ++ DBUS_MAXIMUM_MATCH_RULE_LENGTH); ++ return NULL; ++ } ++ ++ memset(tokens, '\0', sizeof(tokens)); ++ ++ rule = bus_match_rule_new(gfp_flags); ++ if (rule == NULL) { ++ pr_err("Out of memory"); ++ goto failed; ++ } ++ ++ rule->rule_text = kstrdup(rule_text, gfp_flags); ++ if (rule->rule_text == NULL) { ++ pr_err("Out of memory"); ++ goto failed; ++ } ++ ++ if (!tokenize_rule(rule_text, tokens, gfp_flags)) ++ goto failed; ++ ++ i = 0; ++ while (tokens[i].key != NULL) { ++ const char *key = tokens[i].key; ++ const char *value = tokens[i].value; ++ ++ if (strcmp(key, "type") == 0) { ++ int t; ++ ++ if (rule->flags & BUS_MATCH_MESSAGE_TYPE) { ++ pr_warn("Key %s specified twice in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ t = dbus_message_type_from_string(value); ++ ++ if (t == DBUS_MESSAGE_TYPE_INVALID) { ++ pr_warn("Invalid message type (%s) in match rule\n", ++ value); ++ goto failed; ++ } ++ ++ if (!bus_match_rule_set_message_type(rule, t, ++ gfp_flags)) { ++ pr_err("Out of memeory"); ++ goto failed; ++ } ++ } else if (strcmp(key, "sender") == 0) { ++ if (rule->flags & BUS_MATCH_SENDER) { ++ pr_warn("Key %s specified twice in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ if (!bus_match_rule_set_sender(rule, value, ++ gfp_flags)) { ++ pr_err("Out of memeory"); ++ goto failed; ++ } ++ } else if (strcmp(key, "interface") == 0) { ++ if (rule->flags & BUS_MATCH_INTERFACE) { ++ pr_warn("Key %s specified twice in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ if (!bus_match_rule_set_interface(rule, value, ++ gfp_flags)) { ++ pr_err("Out of memeory"); ++ goto failed; ++ } ++ } else if (strcmp(key, "member") == 0) { ++ if (rule->flags & BUS_MATCH_MEMBER) { ++ pr_warn("Key %s specified twice in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ if (!bus_match_rule_set_member(rule, value, ++ gfp_flags)) { ++ pr_err("Out of memeory"); ++ goto failed; ++ } ++ } else if (strcmp(key, "destination") == 0) { ++ if (rule->flags & BUS_MATCH_DESTINATION) { ++ pr_warn("Key %s specified twice in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ if (!bus_match_rule_set_destination(rule, value, ++ gfp_flags)) { ++ pr_err("Out of memeory"); ++ goto failed; ++ } ++ } else if (strcmp(key, "eavesdrop") == 0) { ++ if (strcmp(value, "true") == 0) { ++ rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING; ++ } else if (strcmp(value, "false") == 0) { ++ rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING); ++ } else { ++ pr_warn("eavesdrop='%s' is invalid, " \ ++ "it should be 'true' or 'false'\n", ++ value); ++ goto failed; ++ } ++ } else if (strncmp(key, "arg", 3) != 0) { ++ pr_warn("Unknown key \"%s\" in match rule\n", ++ key); ++ goto failed; ++ } ++ ++ ++i; ++ } ++ ++ goto out; ++ ++failed: ++ if (rule) { ++ bus_match_rule_free(rule); ++ rule = NULL; ++ } ++ ++out: ++ ++ i = 0; ++ while (tokens[i].key || tokens[i].value) { ++ WARN_ON(i >= MAX_RULE_TOKENS); ++ kfree(tokens[i].key); ++ kfree(tokens[i].value); ++ ++i; ++ } ++ ++ return rule; ++} ++ ++/* return the match rule containing the hlist_head. It may not be the first ++ * match rule in the list. */ ++struct bus_match_rule *match_rule_search(struct rb_root *root, ++ const char *interface) ++{ ++ struct rb_node *node = root->rb_node; ++ ++ while (node) { ++ struct bus_match_rule *data = ++ container_of(node, struct bus_match_rule, node); ++ int result; ++ ++ result = strcmp(interface, data->interface); ++ ++ if (result < 0) ++ node = node->rb_left; ++ else if (result > 0) ++ node = node->rb_right; ++ else ++ return data; ++ } ++ return NULL; ++} ++ ++void match_rule_insert(struct rb_root *root, struct bus_match_rule *data) ++{ ++ struct rb_node **new = &(root->rb_node), *parent = NULL; ++ ++ /* Figure out where to put new node */ ++ while (*new) { ++ struct bus_match_rule *this = ++ container_of(*new, struct bus_match_rule, node); ++ int result = strcmp(data->interface, this->interface); ++ ++ parent = *new; ++ if (result < 0) ++ new = &((*new)->rb_left); ++ else if (result > 0) ++ new = &((*new)->rb_right); ++ else { ++ /* the head is not used */ ++ INIT_HLIST_HEAD(&data->first); ++ /* Add it at the beginning of the list */ ++ hlist_add_head(&data->list, &this->first); ++ return; ++ } ++ } ++ ++ /* this rule is single in its list */ ++ INIT_HLIST_HEAD(&data->first); ++ hlist_add_head(&data->list, &data->first); ++ ++ /* Add new node and rebalance tree. */ ++ rb_link_node(&data->node, parent, new); ++ rb_insert_color(&data->node, root); ++} ++ ++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags) ++{ ++ struct bus_match_maker *matchmaker; ++ int i; ++ ++ matchmaker = kzalloc(sizeof(struct bus_match_maker), gfp_flags); ++ if (matchmaker == NULL) ++ return NULL; ++ ++ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) { ++ struct rule_pool *p = matchmaker->rules_by_type + i; ++ ++ p->rules_by_iface = RB_ROOT; ++ } ++ ++ kref_init(&matchmaker->kref); ++ ++ return matchmaker; ++} ++ ++void bus_matchmaker_free(struct kref *kref) ++{ ++ struct bus_match_maker *matchmaker; ++ struct list_head del_list; ++ struct rb_node *n; ++ int i; ++ ++ matchmaker = container_of(kref, struct bus_match_maker, kref); ++ ++ /* free names */ ++ INIT_LIST_HEAD(&del_list); ++ n = matchmaker->names.rb_node; ++ if (n) { ++ struct dbus_name *dbus_name, *cur, *tmp; ++ ++ dbus_name = rb_entry(n, struct dbus_name, node); ++ list_add_tail(&dbus_name->del_list, &del_list); ++ ++ list_for_each_entry(cur, &del_list, del_list) { ++ struct dbus_name *right, *left; ++ if (cur->node.rb_right) { ++ right = rb_entry(cur->node.rb_right, ++ struct dbus_name, node); ++ list_add_tail(&right->del_list, &del_list); ++ } ++ if (cur->node.rb_left) { ++ left = rb_entry(cur->node.rb_left, ++ struct dbus_name, node); ++ list_add_tail(&left->del_list, &del_list); ++ } ++ } ++ list_for_each_entry_safe(dbus_name, tmp, &del_list, del_list) { ++ kfree(dbus_name->name); ++ list_del(&dbus_name->del_list); ++ kfree(dbus_name); ++ } ++ } ++ WARN_ON(!list_empty_careful(&del_list)); ++ ++ /* free match rules */ ++ for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++) { ++ struct rule_pool *pool = matchmaker->rules_by_type + i; ++ struct bus_match_rule *match_rule, *cur, *tmp; ++ struct hlist_node *list_tmp, *list_tmp2; ++ ++ /* free match rules from the list */ ++ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2, ++ &pool->rules_without_iface, list) { ++ bus_match_rule_free(cur); ++ } ++ ++ /* free match rules from the tree */ ++ if (!pool->rules_by_iface.rb_node) ++ continue; ++ match_rule = rb_entry(pool->rules_by_iface.rb_node, ++ struct bus_match_rule, node); ++ list_add_tail(&match_rule->del_list, &del_list); ++ ++ list_for_each_entry(cur, &del_list, del_list) { ++ struct bus_match_rule *right, *left; ++ if (cur->node.rb_right) { ++ right = rb_entry(cur->node.rb_right, ++ struct bus_match_rule, node); ++ list_add_tail(&right->del_list, &del_list); ++ } ++ if (cur->node.rb_left) { ++ left = rb_entry(cur->node.rb_left, ++ struct bus_match_rule, node); ++ list_add_tail(&left->del_list, &del_list); ++ } ++ } ++ list_for_each_entry_safe(match_rule, tmp, &del_list, del_list) { ++ /* keep a ref during the loop to ensure the first ++ * iteration of the loop does not delete it */ ++ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2, ++ &match_rule->first, list) { ++ if (cur != match_rule) ++ bus_match_rule_free(cur); ++ } ++ list_del(&match_rule->del_list); ++ bus_match_rule_free(match_rule); ++ } ++ WARN_ON(!list_empty_careful(&del_list)); ++ } ++ ++ kfree(matchmaker); ++} ++ ++/* The rule can't be modified after it's added. */ ++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker, ++ struct bus_match_rule *rule) ++{ ++ struct rule_pool *pool; ++ ++ WARN_ON(rule->message_type < 0); ++ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES); ++ ++ pool = matchmaker->rules_by_type + rule->message_type; ++ ++ if (rule->interface) ++ match_rule_insert(&pool->rules_by_iface, rule); ++ else ++ hlist_add_head(&rule->list, &pool->rules_without_iface); ++ ++ return 1; ++} ++ ++static int match_rule_equal(struct bus_match_rule *a, ++ struct bus_match_rule *b) ++{ ++ if (a->flags != b->flags) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && ++ a->message_type != b->message_type) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_MEMBER) && ++ strcmp(a->member, b->member) != 0) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_PATH) && ++ strcmp(a->path, b->path) != 0) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_INTERFACE) && ++ strcmp(a->interface, b->interface) != 0) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_SENDER) && ++ strcmp(a->sender, b->sender) != 0) ++ return 0; ++ ++ if ((a->flags & BUS_MATCH_DESTINATION) && ++ strcmp(a->destination, b->destination) != 0) ++ return 0; ++ ++ if (a->flags & BUS_MATCH_ARGS) { ++ int i; ++ ++ if (a->args_len != b->args_len) ++ return 0; ++ ++ i = 0; ++ while (i < a->args_len) { ++ int length; ++ ++ if ((a->args[i] != NULL) != (b->args[i] != NULL)) ++ return 0; ++ ++ if (a->arg_lens[i] != b->arg_lens[i]) ++ return 0; ++ ++ length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; ++ ++ if (a->args[i] != NULL) { ++ WARN_ON(!b->args[i]); ++ if (memcmp(a->args[i], b->args[i], length) != 0) ++ return 0; ++ } ++ ++ ++i; ++ } ++ } ++ ++ return 1; ++} ++ ++/* Remove a single rule which is equal to the given rule by value */ ++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker, ++ struct bus_match_rule *rule) ++{ ++ struct rule_pool *pool; ++ ++ WARN_ON(rule->message_type < 0); ++ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES); ++ ++ pool = matchmaker->rules_by_type + rule->message_type; ++ ++ if (rule->interface) { ++ struct bus_match_rule *head = ++ match_rule_search(&pool->rules_by_iface, ++ rule->interface); ++ ++ struct hlist_node *cur; ++ struct bus_match_rule *cur_rule; ++ hlist_for_each_entry(cur_rule, cur, &head->first, list) { ++ if (match_rule_equal(cur_rule, rule)) { ++ hlist_del(cur); ++ if (hlist_empty(&head->first)) ++ rb_erase(&head->node, ++ &pool->rules_by_iface); ++ bus_match_rule_free(cur_rule); ++ break; ++ } ++ } ++ } else { ++ struct hlist_head *head = &pool->rules_without_iface; ++ ++ struct hlist_node *cur; ++ struct bus_match_rule *cur_rule; ++ hlist_for_each_entry(cur_rule, cur, head, list) { ++ if (match_rule_equal(cur_rule, rule)) { ++ hlist_del(cur); ++ bus_match_rule_free(cur_rule); ++ break; ++ } ++ } ++ } ++ ++} ++ ++static int connection_is_primary_owner(struct bus_match_maker *connection, ++ const char *service_name) ++{ ++ struct rb_node *node = connection->names.rb_node; ++ ++ if (!service_name) ++ return 0; ++ ++ while (node) { ++ struct dbus_name *data = container_of(node, struct dbus_name, ++ node); ++ int result; ++ ++ result = strcmp(service_name, data->name); ++ ++ if (result < 0) ++ node = node->rb_left; ++ else if (result > 0) ++ node = node->rb_right; ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++static int match_rule_matches(struct bus_match_maker *matchmaker, ++ struct bus_match_maker *sender, ++ int eavesdrop, ++ struct bus_match_rule *rule, ++ const struct dbus_message *message) ++{ ++ /* Don't consider the rule if this is a eavesdropping match rule ++ * and eavesdropping is not allowed on that peer */ ++ if ((rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) && !eavesdrop) ++ return 0; ++ ++ /* Since D-Bus 1.5.6, match rules do not match messages which have a ++ * DESTINATION field unless the match rule specifically requests this ++ * by specifying eavesdrop='true' in the match rule. */ ++ if (message->destination && ++ !(rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)) ++ return 0; ++ ++ if (rule->flags & BUS_MATCH_MEMBER) { ++ const char *member; ++ ++ WARN_ON(!rule->member); ++ ++ member = message->member; ++ if (member == NULL) ++ return 0; ++ ++ if (strcmp(member, rule->member) != 0) ++ return 0; ++ } ++ ++ if (rule->flags & BUS_MATCH_SENDER) { ++ WARN_ON(!rule->sender); ++ ++ if (sender == NULL) { ++ if (strcmp(rule->sender, ++ "org.freedesktop.DBus") != 0) ++ return 0; ++ } else ++ if (!connection_is_primary_owner(sender, rule->sender)) ++ return 0; ++ } ++ ++ if (rule->flags & BUS_MATCH_DESTINATION) { ++ const char *destination; ++ ++ WARN_ON(!rule->destination); ++ ++ destination = message->destination; ++ if (destination == NULL) ++ return 0; ++ ++ /* This will not just work out of the box because it this is ++ * an eavesdropping match rule. */ ++ if (matchmaker == NULL) { ++ if (strcmp(rule->destination, ++ "org.freedesktop.DBus") != 0) ++ return 0; ++ } else ++ if (!connection_is_primary_owner(matchmaker, ++ rule->destination)) ++ return 0; ++ } ++ ++ if (rule->flags & BUS_MATCH_PATH) { ++ const char *path; ++ ++ WARN_ON(!rule->path); ++ ++ path = message->path; ++ if (path == NULL) ++ return 0; ++ ++ if (strcmp(path, rule->path) != 0) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static bool get_recipients_from_list(struct bus_match_maker *matchmaker, ++ struct bus_match_maker *sender, ++ int eavesdrop, ++ struct hlist_head *rules, ++ const struct dbus_message *message) ++{ ++ struct hlist_node *cur; ++ struct bus_match_rule *rule; ++ ++ if (rules == NULL) { ++ pr_debug("no rules of this type\n"); ++ return 0; ++ } ++ ++ hlist_for_each_entry(rule, cur, rules, list) { ++ if (match_rule_matches(matchmaker, sender, eavesdrop, rule, ++ message)) { ++ pr_debug("[YES] deliver with match rule \"%s\"\n", ++ rule->rule_text); ++ return 1; ++ } else { ++ pr_debug("[NO] deliver with match rule \"%s\"\n", ++ rule->rule_text); ++ } ++ } ++ pr_debug("[NO] no match rules\n"); ++ return 0; ++} ++ ++static struct hlist_head ++*bus_matchmaker_get_rules(struct bus_match_maker *matchmaker, ++ int message_type, const char *interface) ++{ ++ static struct hlist_head empty = {0,}; ++ struct rule_pool *p; ++ ++ WARN_ON(message_type < 0); ++ WARN_ON(message_type >= DBUS_NUM_MESSAGE_TYPES); ++ ++ p = matchmaker->rules_by_type + message_type; ++ ++ if (interface == NULL) ++ return &p->rules_without_iface; ++ else { ++ struct bus_match_rule *rule = ++ match_rule_search(&p->rules_by_iface, interface); ++ if (rule) ++ return &rule->first; ++ else ++ return ∅ ++ } ++} ++ ++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker, ++ struct bus_match_maker *sender, ++ int eavesdrop, ++ const struct dbus_message *message) ++{ ++ int type; ++ const char *interface; ++ struct hlist_head *neither, *just_type, *just_iface, *both; ++ ++ type = message->type; ++ interface = message->interface; ++ ++ neither = bus_matchmaker_get_rules(matchmaker, ++ DBUS_MESSAGE_TYPE_INVALID, NULL); ++ just_type = just_iface = both = NULL; ++ ++ if (interface != NULL) ++ just_iface = bus_matchmaker_get_rules(matchmaker, ++ DBUS_MESSAGE_TYPE_INVALID, ++ interface); ++ ++ if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) { ++ just_type = bus_matchmaker_get_rules(matchmaker, type, NULL); ++ ++ if (interface != NULL) ++ both = bus_matchmaker_get_rules(matchmaker, type, ++ interface); ++ } ++ ++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, neither, ++ message)) ++ return 1; ++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_iface, ++ message)) ++ return 1; ++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_type, ++ message)) ++ return 1; ++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, both, ++ message)) ++ return 1; ++ ++ return connection_is_primary_owner(matchmaker, message->destination); ++} ++ ++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker, ++ const char *name, ++ gfp_t gfp_flags) ++{ ++ struct dbus_name *dbus_name; ++ struct rb_node **new = &(matchmaker->names.rb_node), *parent = NULL; ++ ++ dbus_name = kmalloc(sizeof(struct dbus_name), gfp_flags); ++ if (!dbus_name) ++ return; ++ dbus_name->name = kstrdup(name, gfp_flags); ++ if (!dbus_name->name) ++ return; ++ ++ /* Figure out where to put new node */ ++ while (*new) { ++ struct dbus_name *this = container_of(*new, struct dbus_name, ++ node); ++ int result = strcmp(dbus_name->name, this->name); ++ ++ parent = *new; ++ if (result < 0) ++ new = &((*new)->rb_left); ++ else if (result > 0) ++ new = &((*new)->rb_right); ++ else ++ return; ++ } ++ ++ /* Add new node and rebalance tree. */ ++ rb_link_node(&dbus_name->node, parent, new); ++ rb_insert_color(&dbus_name->node, &matchmaker->names); ++} ++ ++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker, ++ const char *name) ++{ ++ struct rb_node *node = matchmaker->names.rb_node; ++ ++ while (node) { ++ struct dbus_name *data = container_of(node, struct dbus_name, ++ node); ++ int result; ++ ++ result = strcmp(name, data->name); ++ ++ if (result < 0) ++ node = node->rb_left; ++ else if (result > 0) ++ node = node->rb_right; ++ else { ++ rb_erase(&data->node, &matchmaker->names); ++ kfree(data->name); ++ kfree(data); ++ } ++ } ++ ++} ++ +Index: git/net/netfilter/nfdbus/matchrule.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/matchrule.h 2012-10-05 13:51:44.000000000 +0300 +@@ -0,0 +1,82 @@ ++/* ++ * signals.h Bus signal connection implementation ++ * ++ * Copyright (C) 2003 Red Hat, Inc. ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef BUS_SIGNALS_H ++#define BUS_SIGNALS_H ++ ++#include <linux/gfp.h> ++#include <linux/list.h> ++#include <linux/rbtree.h> ++#include <linux/slab.h> ++#include <net/af_bus.h> ++ ++#include "message.h" ++ ++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags); ++void bus_match_rule_free(struct bus_match_rule *rule); ++ ++struct bus_match_rule *bus_match_rule_parse(const char *rule_text, ++ gfp_t gfp_flags); ++ ++struct rule_pool { ++ /* Maps non-NULL interface names to a list of bus_match_rule */ ++ struct rb_root rules_by_iface; ++ ++ /* List of bus_match_rule which don't specify an interface */ ++ struct hlist_head rules_without_iface; ++}; ++ ++struct bus_match_maker { ++ struct sockaddr_bus addr; ++ ++ struct hlist_node table_node; ++ ++ /* Pools of rules, grouped by the type of message they match. 0 ++ * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a ++ * message type. ++ */ ++ struct rule_pool rules_by_type[DBUS_NUM_MESSAGE_TYPES]; ++ ++ struct rb_root names; ++ ++ struct kref kref; ++}; ++ ++ ++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags); ++void bus_matchmaker_free(struct kref *kref); ++ ++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker, ++ struct bus_match_rule *rule); ++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker, ++ struct bus_match_rule *value); ++ ++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker, ++ struct bus_match_maker *sender, ++ int eavesdrop, ++ const struct dbus_message *message); ++ ++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker, ++ const char *name, gfp_t gfp_flags); ++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker, ++ const char *name); ++ ++#endif /* BUS_SIGNALS_H */ +Index: git/net/netfilter/nfdbus/message.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/message.c 2012-10-05 13:52:50.000000000 +0300 +@@ -0,0 +1,194 @@ ++/* ++ * message.c Basic D-Bus message parsing ++ * ++ * Copyright (C) 2010-2012 Collabora Ltd ++ * Authors: Alban Crequy <alban.crequy@collabora.co.uk> ++ * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. ++ * Copyright (C) 2002, 2003 CodeFactory AB ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#include <linux/slab.h> ++ ++#include "message.h" ++ ++int dbus_message_type_from_string(const char *type_str) ++{ ++ if (strcmp(type_str, "method_call") == 0) ++ return DBUS_MESSAGE_TYPE_METHOD_CALL; ++ if (strcmp(type_str, "method_return") == 0) ++ return DBUS_MESSAGE_TYPE_METHOD_RETURN; ++ else if (strcmp(type_str, "signal") == 0) ++ return DBUS_MESSAGE_TYPE_SIGNAL; ++ else if (strcmp(type_str, "error") == 0) ++ return DBUS_MESSAGE_TYPE_ERROR; ++ else ++ return DBUS_MESSAGE_TYPE_INVALID; ++} ++ ++int dbus_message_parse(unsigned char *message, size_t len, ++ struct dbus_message *dbus_message) ++{ ++ unsigned char *cur; ++ int array_header_len; ++ ++ dbus_message->message = message; ++ ++ if (len < 4 + 4 + 4 + 4 || message[1] == 0 || message[1] > 4) ++ return -EINVAL; ++ ++ dbus_message->type = message[1]; ++ dbus_message->body_length = *((u32 *)(message + 4)); ++ cur = message + 12; ++ array_header_len = *(u32 *)cur; ++ dbus_message->len_offset = 12; ++ cur += 4; ++ while (cur < message + len ++ && cur < message + 12 + 4 + array_header_len) { ++ int header_code; ++ int signature_len; ++ unsigned char *signature; ++ int str_len; ++ unsigned char *str; ++ ++ /* D-Bus alignment craziness */ ++ if ((cur - message) % 8 != 0) ++ cur += 8 - (cur - message) % 8; ++ ++ header_code = *(char *)cur; ++ cur++; ++ signature_len = *(char *)cur; ++ /* All header fields of the current D-Bus spec have a simple ++ * type, either o, s, g, or u */ ++ if (signature_len != 1) ++ return -EINVAL; ++ cur++; ++ signature = cur; ++ cur += signature_len + 1; ++ if (signature[0] != 'o' && ++ signature[0] != 's' && ++ signature[0] != 'g' && ++ signature[0] != 'u') ++ return -EINVAL; ++ ++ if (signature[0] == 'u') { ++ cur += 4; ++ continue; ++ } ++ ++ if (signature[0] != 'g') { ++ str_len = *(u32 *)cur; ++ cur += 4; ++ } else { ++ str_len = *(char *)cur; ++ cur += 1; ++ } ++ ++ str = cur; ++ switch (header_code) { ++ case 1: ++ dbus_message->path = str; ++ break; ++ case 2: ++ dbus_message->interface = str; ++ break; ++ case 3: ++ dbus_message->member = str; ++ break; ++ case 6: ++ dbus_message->destination = str; ++ break; ++ case 7: ++ dbus_message->sender = str; ++ break; ++ case 8: ++ dbus_message->body_signature = str; ++ break; ++ } ++ cur += str_len + 1; ++ } ++ ++ dbus_message->padding_end = (8 - (cur - message) % 8) % 8; ++ ++ /* Jump to body D-Bus alignment craziness */ ++ if ((cur - message) % 8 != 0) ++ cur += 8 - (cur - message) % 8; ++ dbus_message->new_header_offset = cur - message; ++ ++ if (dbus_message->new_header_offset ++ + dbus_message->body_length != len) { ++ pr_warn("Message truncated? " \ ++ "Header %d + Body %d != Length %zd\n", ++ dbus_message->new_header_offset, ++ dbus_message->body_length, len); ++ return -EINVAL; ++ } ++ ++ if (dbus_message->body_signature && ++ dbus_message->body_signature[0] == 's') { ++ int str_len; ++ str_len = *(u32 *)cur; ++ cur += 4; ++ dbus_message->arg0 = cur; ++ cur += str_len + 1; ++ } ++ ++ if ((cur - message) % 4 != 0) ++ cur += 4 - (cur - message) % 4; ++ ++ if (dbus_message->body_signature && ++ dbus_message->body_signature[0] == 's' && ++ dbus_message->body_signature[1] == 's') { ++ int str_len; ++ str_len = *(u32 *)cur; ++ cur += 4; ++ dbus_message->arg1 = cur; ++ cur += str_len + 1; ++ } ++ ++ if ((cur - message) % 4 != 0) ++ cur += 4 - (cur - message) % 4; ++ ++ if (dbus_message->body_signature && ++ dbus_message->body_signature[0] == 's' && ++ dbus_message->body_signature[1] == 's' && ++ dbus_message->body_signature[2] == 's') { ++ int str_len; ++ str_len = *(u32 *)cur; ++ cur += 4; ++ dbus_message->arg2 = cur; ++ cur += str_len + 1; ++ } ++ ++ if ((cur - message) % 4 != 0) ++ cur += 4 - (cur - message) % 4; ++ ++ if (dbus_message->type == DBUS_MESSAGE_TYPE_SIGNAL && ++ dbus_message->sender && dbus_message->path && ++ dbus_message->interface && dbus_message->member && ++ dbus_message->arg0 && ++ strcmp(dbus_message->sender, "org.freedesktop.DBus") == 0 && ++ strcmp(dbus_message->interface, "org.freedesktop.DBus") == 0 && ++ strcmp(dbus_message->path, "/org/freedesktop/DBus") == 0) { ++ if (strcmp(dbus_message->member, "NameAcquired") == 0) ++ dbus_message->name_acquired = dbus_message->arg0; ++ else if (strcmp(dbus_message->member, "NameLost") == 0) ++ dbus_message->name_lost = dbus_message->arg0; ++ } ++ ++ return 0; ++} +Index: git/net/netfilter/nfdbus/message.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/message.h 2012-10-05 13:53:47.000000000 +0300 +@@ -0,0 +1,71 @@ ++/* ++ * message.h Basic D-Bus message parsing ++ * ++ * Copyright (C) 2010 Collabora Ltd ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef DBUS_MESSAGE_H ++#define DBUS_MESSAGE_H ++ ++#include <linux/list.h> ++ ++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 ++ ++/* Types of message */ ++ ++#define DBUS_MESSAGE_TYPE_INVALID 0 ++#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 ++#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 ++#define DBUS_MESSAGE_TYPE_ERROR 3 ++#define DBUS_MESSAGE_TYPE_SIGNAL 4 ++#define DBUS_NUM_MESSAGE_TYPES 5 ++ ++/* No need to implement a feature-complete parser. It only implement what is ++ * needed by the bus. */ ++struct dbus_message { ++ char *message; ++ size_t len; ++ size_t new_len; ++ ++ /* direct pointers to the fields */ ++ int type; ++ char *path; ++ char *interface; ++ char *member; ++ char *destination; ++ char *sender; ++ char *body_signature; ++ int body_length; ++ char *arg0; ++ char *arg1; ++ char *arg2; ++ char *name_acquired; ++ char *name_lost; ++ ++ /* How to add the 'sender' field in the headers */ ++ int new_header_offset; ++ int len_offset; ++ int padding_end; ++}; ++ ++int dbus_message_type_from_string(const char *type_str); ++ ++int dbus_message_parse(unsigned char *message, size_t len, ++ struct dbus_message *dbus_message); ++ ++#endif /* DBUS_MESSAGE_H */ +Index: git/net/netfilter/nfdbus/nfdbus.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/nfdbus.c 2012-10-05 13:55:08.000000000 +0300 +@@ -0,0 +1,456 @@ ++/* ++ * nfdbus.c - Netfilter module for AF_BUS/BUS_PROTO_DBUS. ++ */ ++ ++#define DRIVER_AUTHOR "Alban Crequy" ++#define DRIVER_DESC "Netfilter module for AF_BUS/BUS_PROTO_DBUS." ++ ++#include "nfdbus.h" ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter.h> ++#include <linux/connector.h> ++#include <net/af_bus.h> ++ ++#include "message.h" ++#include "matchrule.h" ++ ++static struct nf_hook_ops nfho_dbus; ++ ++static struct cb_id cn_cmd_id = { CN_IDX_NFDBUS, CN_VAL_NFDBUS }; ++ ++static unsigned int hash; ++ ++/* Scoped by AF_BUS address */ ++struct hlist_head matchrules_table[BUS_HASH_SIZE]; ++DEFINE_SPINLOCK(matchrules_lock); ++ ++static struct bus_match_maker *find_match_maker(struct sockaddr_bus *addr, ++ bool create, bool delete) ++{ ++ u64 hash; ++ struct hlist_node *node; ++ struct bus_match_maker *matchmaker; ++ int path_len = strlen(addr->sbus_path); ++ ++ hash = csum_partial(addr->sbus_path, ++ strlen(addr->sbus_path), 0); ++ hash ^= addr->sbus_addr.s_addr; ++ hash ^= hash >> 32; ++ hash ^= hash >> 16; ++ hash ^= hash >> 8; ++ hash &= 0xff; ++ ++ spin_lock(&matchrules_lock); ++ hlist_for_each_entry(matchmaker, node, &matchrules_table[hash], ++ table_node) { ++ if (addr->sbus_family == matchmaker->addr.sbus_family && ++ addr->sbus_addr.s_addr == matchmaker->addr.sbus_addr.s_addr && ++ !memcmp(addr->sbus_path, matchmaker->addr.sbus_path, ++ path_len)) { ++ kref_get(&matchmaker->kref); ++ if (delete) ++ hlist_del(&matchmaker->table_node); ++ spin_unlock(&matchrules_lock); ++ pr_debug("Found matchmaker for hash %llu", hash); ++ return matchmaker; ++ } ++ } ++ spin_unlock(&matchrules_lock); ++ ++ if (!create) { ++ pr_debug("Matchmaker for hash %llu not found", hash); ++ return NULL; ++ } ++ ++ matchmaker = bus_matchmaker_new(GFP_ATOMIC); ++ matchmaker->addr.sbus_family = addr->sbus_family; ++ matchmaker->addr.sbus_addr.s_addr = addr->sbus_addr.s_addr; ++ memcpy(matchmaker->addr.sbus_path, addr->sbus_path, BUS_PATH_MAX); ++ ++ pr_debug("Create new matchmaker for hash %llu\n", hash); ++ spin_lock(&matchrules_lock); ++ hlist_add_head(&matchmaker->table_node, &matchrules_table[hash]); ++ kref_get(&matchmaker->kref); ++ spin_unlock(&matchrules_lock); ++ return matchmaker; ++} ++ ++static unsigned int dbus_filter(unsigned int hooknum, ++ struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct bus_send_context *sendctx; ++ struct bus_match_maker *matchmaker = NULL; ++ struct bus_match_maker *sender = NULL; ++ struct dbus_message msg = {0,}; ++ unsigned char *data; ++ size_t len; ++ int err; ++ int ret; ++ ++ if (!skb->sk || skb->sk->sk_family != PF_BUS) { ++ WARN(1, "netfilter_dbus received an invalid skb"); ++ return NF_DROP; ++ } ++ ++ data = skb->data; ++ sendctx = BUSCB(skb).sendctx; ++ if (!sendctx || !sendctx->sender || !sendctx->sender_socket) { ++ WARN(1, "netfilter_dbus received an AF_BUS packet" \ ++ " without context. This is a bug. Dropping the" ++ " packet."); ++ return NF_DROP; ++ } ++ ++ if (sendctx->sender_socket->sk->sk_protocol != BUS_PROTO_DBUS) { ++ /* This kernel module is for D-Bus. It must not ++ * interfere with other users of AF_BUS. */ ++ return NF_ACCEPT; ++ } ++ if (sendctx->recipient) ++ matchmaker = find_match_maker(sendctx->recipient, false, false); ++ ++ len = skb_tail_pointer(skb) - data; ++ ++ if (sendctx->to_master && sendctx->main_recipient) { ++ pr_debug("AF_BUS packet to the bus master. ACCEPT.\n"); ++ ret = NF_ACCEPT; ++ goto out; ++ } ++ ++ if (sendctx->main_recipient && !sendctx->bus_master_side) { ++ pr_debug("AF_BUS packet from a peer to a peer (unicast). ACCEPT.\n"); ++ ret = NF_ACCEPT; ++ goto out; ++ } ++ ++ err = dbus_message_parse(data, len, &msg); ++ if (err) { ++ if (!sendctx->main_recipient) { ++ pr_debug("AF_BUS packet for an eavesdropper or " \ ++ "multicast is not parsable. DROP.\n"); ++ ret = NF_DROP; ++ goto out; ++ } else if (sendctx->bus_master_side) { ++ pr_debug("AF_BUS packet from bus master is not parsable. ACCEPT.\n"); ++ ret = NF_ACCEPT; ++ goto out; ++ } else { ++ pr_debug("AF_BUS packet from peer is not parsable. DROP.\n"); ++ ret = NF_DROP; ++ goto out; ++ } ++ } ++ ++ if (sendctx->bus_master_side && !sendctx->main_recipient) { ++ pr_debug("AF_BUS packet '%s' from the bus master is for an " \ ++ "eavesdropper. DROP.\n", ++ msg.member ? msg.member : ""); ++ ret = NF_DROP; ++ goto out; ++ } ++ if (sendctx->bus_master_side) { ++ if (msg.name_acquired) { ++ pr_debug("New name: %s [%p %p].\n", ++ msg.name_acquired, sendctx->sender, ++ sendctx->recipient); ++ ++ sender = find_match_maker(sendctx->sender, true, false); ++ bus_matchmaker_add_name(sender, msg.name_acquired, ++ GFP_ATOMIC); ++ } ++ if (msg.name_lost) { ++ pr_debug("Lost name: %s [%p %p].\n", ++ msg.name_lost, sendctx->sender, ++ sendctx->recipient); ++ ++ sender = find_match_maker(sendctx->sender, true, false); ++ bus_matchmaker_remove_name(sender, msg.name_acquired); ++ } ++ ++ pr_debug("AF_BUS packet '%s' from the bus master. ACCEPT.\n", ++ msg.member ? msg.member : ""); ++ ret = NF_ACCEPT; ++ goto out; ++ } ++ ++ pr_debug("Multicast AF_BUS packet, %ld bytes, " \ ++ "considering recipient %lld...\n", len, ++ sendctx->recipient ? sendctx->recipient->sbus_addr.s_addr : 0); ++ ++ pr_debug("Message type %d %s->%s [iface: %s][member: %s][matchmaker=%p]...\n", ++ msg.type, ++ msg.sender ? msg.sender : "", ++ msg.destination ? msg.destination : "", ++ msg.interface ? msg.interface : "", ++ msg.member ? msg.member : "", ++ matchmaker); ++ ++ if (!matchmaker) { ++ pr_debug("No match rules for this recipient. DROP.\n"); ++ ret = NF_DROP; ++ goto out; ++ } ++ ++ sender = find_match_maker(sendctx->sender, true, false); ++ err = bus_matchmaker_filter(matchmaker, sender, sendctx->eavesdropper, ++ &msg); ++ if (err) { ++ pr_debug("Matchmaker: ACCEPT.\n"); ++ ret = NF_ACCEPT; ++ goto out; ++ } else { ++ pr_debug("Matchmaker: DROP.\n"); ++ ret = NF_DROP; ++ goto out; ++ } ++ ++out: ++ if (matchmaker) ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ if (sender) ++ kref_put(&sender->kref, bus_matchmaker_free); ++ return ret; ++} ++ ++/* Taken from drbd_nl_send_reply() */ ++static void nfdbus_nl_send_reply(struct cn_msg *msg, int ret_code) ++{ ++ char buffer[sizeof(struct cn_msg)+sizeof(struct nfdbus_nl_cfg_reply)]; ++ struct cn_msg *cn_reply = (struct cn_msg *) buffer; ++ struct nfdbus_nl_cfg_reply *reply = ++ (struct nfdbus_nl_cfg_reply *)cn_reply->data; ++ int rr; ++ ++ memset(buffer, 0, sizeof(buffer)); ++ cn_reply->id = msg->id; ++ ++ cn_reply->seq = msg->seq; ++ cn_reply->ack = msg->ack + 1; ++ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply); ++ cn_reply->flags = 0; ++ ++ reply->ret_code = ret_code; ++ ++ rr = cn_netlink_send(cn_reply, 0, GFP_NOIO); ++ if (rr && rr != -ESRCH) ++ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr); ++} ++ ++/** ++ * nfdbus_check_perm - check if a pid is allowed to update match rules ++ * @sockaddr_bus: the socket address of the bus ++ * @pid: the process id that wants to update the match rules set ++ * ++ * Test if a given process id is allowed to update the match rules set ++ * for this bus. Only the process that owns the bus master listen socket ++ * is allowed to update the match rules set for the bus. ++ */ ++static bool nfdbus_check_perm(struct sockaddr_bus *sbusname, pid_t pid) ++{ ++ struct net *net = get_net_ns_by_pid(pid); ++ struct sock *s; ++ struct bus_address *addr; ++ struct hlist_node *node; ++ int offset = (sbusname->sbus_path[0] == '\0'); ++ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX); ++ int len; ++ if (!net) ++ return false; ++ ++ len = path_len + 1 + sizeof(__kernel_sa_family_t) + ++ sizeof(struct bus_addr); ++ ++ spin_lock(&bus_address_lock); ++ ++ hlist_for_each_entry(addr, node, &bus_address_table[hash], ++ table_node) { ++ s = addr->sock; ++ ++ if (s->sk_protocol != BUS_PROTO_DBUS) ++ continue; ++ ++ if (!net_eq(sock_net(s), net)) ++ continue; ++ ++ if (addr->len == len && ++ addr->name->sbus_family == sbusname->sbus_family && ++ addr->name->sbus_addr.s_addr == BUS_MASTER_ADDR && ++ bus_same_bus(addr->name, sbusname) && ++ pid_nr(s->sk_peer_pid) == pid) { ++ spin_unlock(&bus_address_lock); ++ return true; ++ } ++ } ++ ++ spin_unlock(&bus_address_lock); ++ ++ return false; ++} ++ ++static void cn_cmd_cb(struct cn_msg *msg, struct netlink_skb_parms *nsp) ++{ ++ struct nfdbus_nl_cfg_req *nlp = (struct nfdbus_nl_cfg_req *)msg->data; ++ struct cn_msg *cn_reply; ++ struct nfdbus_nl_cfg_reply *reply; ++ int retcode, rr; ++ pid_t pid = task_tgid_vnr(current); ++ int reply_size = sizeof(struct cn_msg) ++ + sizeof(struct nfdbus_nl_cfg_reply); ++ ++ pr_debug("nfdbus: %s nsp->pid=%d pid=%d\n", __func__, nsp->pid, pid); ++ ++ if (!nfdbus_check_perm(&nlp->addr, pid)) { ++ pr_debug(KERN_ERR "nfdbus: pid=%d is not allowed!\n", pid); ++ retcode = EPERM; ++ goto fail; ++ } ++ ++ cn_reply = kzalloc(reply_size, GFP_KERNEL); ++ if (!cn_reply) { ++ retcode = ENOMEM; ++ goto fail; ++ } ++ reply = (struct nfdbus_nl_cfg_reply *) cn_reply->data; ++ ++ if (msg->len < sizeof(struct nfdbus_nl_cfg_req)) { ++ reply->ret_code = EINVAL; ++ } else if (nlp->cmd == NFDBUS_CMD_ADDMATCH) { ++ struct bus_match_rule *rule; ++ struct bus_match_maker *matchmaker; ++ reply->ret_code = 0; ++ ++ if (msg->len == 0) ++ reply->ret_code = EINVAL; ++ ++ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC); ++ if (rule) { ++ matchmaker = find_match_maker(&nlp->addr, true, false); ++ pr_debug("Add match rule for matchmaker %p\n", ++ matchmaker); ++ bus_matchmaker_add_rule(matchmaker, rule); ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ } else { ++ reply->ret_code = EINVAL; ++ } ++ } else if (nlp->cmd == NFDBUS_CMD_REMOVEMATCH) { ++ struct bus_match_rule *rule; ++ struct bus_match_maker *matchmaker; ++ ++ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC); ++ matchmaker = find_match_maker(&nlp->addr, false, false); ++ if (!matchmaker) { ++ reply->ret_code = EINVAL; ++ } else { ++ pr_debug("Remove match rule for matchmaker %p\n", ++ matchmaker); ++ bus_matchmaker_remove_rule_by_value(matchmaker, rule); ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ reply->ret_code = 0; ++ } ++ bus_match_rule_free(rule); ++ ++ } else if (nlp->cmd == NFDBUS_CMD_REMOVEALLMATCH) { ++ struct bus_match_maker *matchmaker; ++ ++ matchmaker = find_match_maker(&nlp->addr, false, true); ++ if (!matchmaker) { ++ reply->ret_code = EINVAL; ++ } else { ++ pr_debug("Remove matchmaker %p\n", matchmaker); ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ reply->ret_code = 0; ++ } ++ ++ } else { ++ reply->ret_code = EINVAL; ++ } ++ ++ cn_reply->id = msg->id; ++ cn_reply->seq = msg->seq; ++ cn_reply->ack = msg->ack + 1; ++ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply); ++ cn_reply->flags = 0; ++ ++ rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL); ++ if (rr && rr != -ESRCH) ++ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr); ++ pr_debug("nfdbus: cn_netlink_reply(pid=%d)=%d\n", nsp->pid, rr); ++ ++ kfree(cn_reply); ++ return; ++fail: ++ nfdbus_nl_send_reply(msg, retcode); ++} ++ ++static int __init nfdbus_init(void) ++{ ++ int err; ++ struct bus_addr master_addr; ++ ++ master_addr.s_addr = BUS_MASTER_ADDR; ++ hash = bus_compute_hash(master_addr); ++ ++ pr_debug("Loading netfilter_dbus\n"); ++ ++ /* Install D-Bus netfilter hook */ ++ nfho_dbus.hook = dbus_filter; ++ nfho_dbus.hooknum = NF_BUS_SENDING; ++ nfho_dbus.pf = NFPROTO_BUS; /* Do not use PF_BUS, you fool! */ ++ nfho_dbus.priority = 0; ++ nfho_dbus.owner = THIS_MODULE; ++ err = nf_register_hook(&nfho_dbus); ++ if (err) ++ return err; ++ pr_debug("Netfilter hook for D-Bus: installed.\n"); ++ ++ /* Install connector hook */ ++ err = cn_add_callback(&cn_cmd_id, "nfdbus", cn_cmd_cb); ++ if (err) ++ goto err_cn_cmd_out; ++ pr_debug("Connector hook: installed.\n"); ++ ++ return 0; ++ ++err_cn_cmd_out: ++ nf_unregister_hook(&nfho_dbus); ++ ++ return err; ++} ++ ++static void __exit nfdbus_cleanup(void) ++{ ++ int i; ++ struct hlist_node *node, *tmp; ++ struct bus_match_maker *matchmaker; ++ nf_unregister_hook(&nfho_dbus); ++ ++ cn_del_callback(&cn_cmd_id); ++ ++ spin_lock(&matchrules_lock); ++ for (i = 0; i < BUS_HASH_SIZE; i++) { ++ hlist_for_each_entry_safe(matchmaker, node, tmp, ++ &matchrules_table[i], table_node) { ++ hlist_del(&matchmaker->table_node); ++ kref_put(&matchmaker->kref, bus_matchmaker_free); ++ } ++ } ++ spin_unlock(&matchrules_lock); ++ ++ pr_debug("Unloading netfilter_dbus\n"); ++} ++ ++module_init(nfdbus_init); ++module_exit(nfdbus_cleanup); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_ALIAS_NET_PF_PROTO(PF_BUS, BUS_PROTO_DBUS); +Index: git/net/netfilter/nfdbus/nfdbus.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ git/net/netfilter/nfdbus/nfdbus.h 2012-10-05 13:56:39.000000000 +0300 +@@ -0,0 +1,44 @@ ++/* ++ * nfdbus.h Netfilter module for AF_BUS/BUS_PROTO_DBUS. ++ * ++ * Copyright (C) 2012 Collabora Ltd ++ * ++ * 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef NETFILTER_DBUS_H ++#define NETFILTER_DBUS_H ++ ++#include <linux/types.h> ++#include <linux/bus.h> ++ ++#define NFDBUS_CMD_ADDMATCH 0x01 ++#define NFDBUS_CMD_REMOVEMATCH 0x02 ++#define NFDBUS_CMD_REMOVEALLMATCH 0x03 ++ ++struct nfdbus_nl_cfg_req { ++ __u32 cmd; ++ __u32 len; ++ struct sockaddr_bus addr; ++ __u64 pad; ++ unsigned char data[0]; ++}; ++ ++struct nfdbus_nl_cfg_reply { ++ __u32 ret_code; ++}; ++ ++#endif /* NETFILTER_DBUS_H */ +Index: git/security/capability.c +=================================================================== +--- git.orig/security/capability.c 2012-10-05 12:14:13.000000000 +0300 ++++ git/security/capability.c 2012-10-05 13:58:36.000000000 +0300 +@@ -563,6 +563,12 @@ + return 0; + } + ++static int cap_bus_connect(struct sock *sock, struct sock *other, ++ struct sock *newsk) ++{ ++return 0; ++} ++ + static int cap_socket_create(int family, int type, int protocol, int kern) + { + return 0; +@@ -1015,6 +1021,7 @@ + #ifdef CONFIG_SECURITY_NETWORK + set_to_cap_if_null(ops, unix_stream_connect); + set_to_cap_if_null(ops, unix_may_send); ++ set_to_cap_if_null(ops, bus_connect); + set_to_cap_if_null(ops, socket_create); + set_to_cap_if_null(ops, socket_post_create); + set_to_cap_if_null(ops, socket_bind); +Index: git/security/security.c +=================================================================== +--- git.orig/security/security.c 2012-10-05 12:14:13.000000000 +0300 ++++ git/security/security.c 2012-10-05 14:00:06.000000000 +0300 +@@ -1018,6 +1018,12 @@ + } + EXPORT_SYMBOL(security_unix_may_send); + ++int security_bus_connect(struct sock *sock, struct sock *other, struct sock *newsk) ++{ ++ return security_ops->bus_connect(sock, other, newsk); ++} ++EXPORT_SYMBOL(security_bus_connect); ++ + int security_socket_create(int family, int type, int protocol, int kern) + { + return security_ops->socket_create(family, type, protocol, kern); +Index: git/security/selinux/hooks.c +=================================================================== +--- git.orig/security/selinux/hooks.c 2012-10-05 12:14:13.000000000 +0300 ++++ git/security/selinux/hooks.c 2012-10-05 14:04:06.000000000 +0300 +@@ -4102,6 +4102,38 @@ + &ad); + } + ++static int selinux_socket_bus_connect(struct sock *sock, struct sock *other, struct sock *newsk) ++{ ++ struct sk_security_struct *sksec_sock = sock->sk_security; ++ struct sk_security_struct *sksec_other = other->sk_security; ++ struct sk_security_struct *sksec_new = newsk->sk_security; ++ struct common_audit_data ad; ++ struct lsm_network_audit net = {0,}; ++ int err; ++ ++ ad.type = LSM_AUDIT_DATA_NET; ++ ad.u.net = &net; ++ ad.u.net->sk = other; ++ ++ err = avc_has_perm(sksec_sock->sid, sksec_other->sid, ++ sksec_other->sclass, ++ UNIX_STREAM_SOCKET__CONNECTTO, &ad); ++ if (err) ++ return err; ++ ++ /* server child socket */ ++ sksec_new->peer_sid = sksec_sock->sid; ++ err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid, ++ &sksec_new->sid); ++ if (err) ++ return err; ++ ++ /* connecting socket */ ++ sksec_sock->peer_sid = sksec_new->sid; ++ ++ return 0; ++} ++ + static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, + u32 peer_sid, + struct common_audit_data *ad) +@@ -5656,6 +5688,7 @@ + + .unix_stream_connect = selinux_socket_unix_stream_connect, + .unix_may_send = selinux_socket_unix_may_send, ++ .bus_connect = selinux_socket_bus_connect, + + .socket_create = selinux_socket_create, + .socket_post_create = selinux_socket_post_create, diff --git a/recipes-kernel/linux/linux-omap4_3.4.0.bb b/recipes-kernel/linux/linux-omap4_3.4.0.bb new file mode 100644 index 0000000..5228847 --- /dev/null +++ b/recipes-kernel/linux/linux-omap4_3.4.0.bb @@ -0,0 +1,21 @@ +COMPATIBLE_MACHINE = "pandaboard" + +require linux.inc + +# The main PR is now using MACHINE_KERNEL_PR, for omap4 see conf/machine/include/omap4.inc +MACHINE_KERNEL_PR_append = "a" + +CORTEXA8FIXUP = "no" + +# Linaro workign kernel 3.4.11+ +#SRCREV = "a5c60c099296fcfc0c8fa8085c40883971486512" +SRCREV = "67c858c2ac6bf304f700246501d574861ea4b0b3" + + + +SRC_URI = "git://git.linaro.org/landing-teams/working/ti/kernel.git;protocol=git \ + file://kernel_af_bus.patch \ + file://defconfig \ + " + +S = "${WORKDIR}/git" diff --git a/recipes-kernel/linux/linux.inc b/recipes-kernel/linux/linux.inc new file mode 100644 index 0000000..ac51dae --- /dev/null +++ b/recipes-kernel/linux/linux.inc @@ -0,0 +1,277 @@ +DESCRIPTION = "Linux Kernel" +SECTION = "kernel" +LICENSE = "GPLv2" + +LIC_FILES_CHKSUM = "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7" + +inherit kernel siteinfo + +# Enable OABI compat for people stuck with obsolete userspace +ARM_KEEP_OABI ?= "1" + +# Quirk for udev greater or equal 141 +UDEV_GE_141 ?= "0" + +# Specify the commandline for your device + +# Boot from mmc +CMDLINE_at91sam9263ek = "mem=64M console=ttyS0,115200 root=/dev/mmcblk0p1 rootfstype=ext2 rootdelay=5" +# Boot from nfs +#CMDLINE_at91sam9263ek = "mem=64M console=ttyS0,115200 root=301 root=/dev/nfs nfsroot=172.20.3.1:/data/at91 ip=172.20.0.5:::255.255.0.0" + +# Set the verbosity of kernel messages during runtime +# You can define CMDLINE_DEBUG in your local.conf or distro.conf to override this behaviour +CMDLINE_DEBUG ?= '${@base_conditional("DISTRO_TYPE", "release", "quiet", "debug", d)}' +CMDLINE_append = " ${CMDLINE_DEBUG} " + +# Kernel bootlogo is distro-specific (default is OE logo). +# Logo resolution (qvga, vga, ...) is machine-specific. +LOGO_SIZE ?= "." + +# Support for binary device tree generation + +FILES_kernel-devicetree = "/boot/devicetree*" + +KERNEL_DEVICETREE_boc01 = "${WORKDIR}/boc01.dts" +KERNEL_DEVICETREE_calamari = "arch/${ARCH}/boot/dts/mpc8536ds.dts" +KERNEL_DEVICETREE_canyonlands = "arch/${ARCH}/boot/dts/canyonlands.dts" +KERNEL_DEVICETREE_kilauea = "arch/${ARCH}/boot/dts/kilauea.dts" +KERNEL_DEVICETREE_lite5200 = "arch/${ARCH}/boot/dts/lite5200.dts" +KERNEL_DEVICETREE_lsppchd = "arch/${ARCH}/boot/dts/kuroboxHD.dts" +KERNEL_DEVICETREE_lsppchg = "arch/${ARCH}/boot/dts/kuroboxHG.dts" +KERNEL_DEVICETREE_mpc8313e-rdb = "arch/${ARCH}/boot/dts/mpc8313erdb.dts" +KERNEL_DEVICETREE_mpc8315e-rdb = "arch/${ARCH}/boot/dts/mpc8315erdb.dts" +KERNEL_DEVICETREE_mpc8323e-rdb = "arch/${ARCH}/boot/dts/mpc832x_rdb.dts" +KERNEL_DEVICETREE_mpc8544ds = "arch/${ARCH}/boot/dts/mpc8544ds.dts" +KERNEL_DEVICETREE_mpc8641-hpcn = "arch/${ARCH}/boot/dts/mpc8641_hpcn.dts" +KERNEL_DEVICETREE_p1020rdb = "arch/${ARCH}/boot/dts/p1020rdb.dts" +KERNEL_DEVICETREE_p2020ds = "arch/${ARCH}/boot/dts/p2020ds.dts" +KERNEL_DEVICETREE_sequoia = "arch/${ARCH}/boot/dts/sequoia.dts" +KERNEL_DEVICETREE_tqm8540 = "arch/${ARCH}/boot/dts/tqm8540.dts" +KERNEL_DEVICETREE_xilinx-ml507 = "arch/${ARCH}/boot/dts/virtex440-ml507.dts" + +KERNEL_DEVICETREE_FLAGS = "-R 8 -S 0x3000" + +CORTEXA8FIXUP ?= "yes" + +python __anonymous () { + + import bb + + devicetree = bb.data.getVar('KERNEL_DEVICETREE', d, 1) or '' + if devicetree: + depends = bb.data.getVar("DEPENDS", d, 1) + bb.data.setVar("DEPENDS", "%s dtc-native" % depends, d) + packages = bb.data.getVar("PACKAGES", d, 1) + bb.data.setVar("PACKAGES", "%s kernel-devicetree" % packages, d) +} + +do_configure_prepend() { + + # Rename getline in ./scripts/unifdef.c + # Kernels up to 2.6.29 are currently failing to build unifdef.c, + # clashing with exposed getline() from <stdio.h> + # see https://patchwork.kernel.org/patch/11166/ + # committed in 2.6.29 (commit d15bd1067b1fcb2b7250d22bc0c7c7fea0b759f7) + + sed -i -e 's/getline/parseline/g' ${S}/scripts/unifdef.c + + + echo "" > ${S}/.config + + # + # logo support, if you supply logo_linux_clut224.ppm in SRC_URI, then it's going to be used + # + if [ -e ${WORKDIR}/${LOGO_SIZE}/logo_linux_clut224.ppm ]; then + install -m 0644 ${WORKDIR}/${LOGO_SIZE}/logo_linux_clut224.ppm drivers/video/logo/logo_linux_clut224.ppm + echo "CONFIG_LOGO=y" >> ${S}/.config + echo "CONFIG_LOGO_LINUX_CLUT224=y" >> ${S}/.config + fi + + # + # oabi / eabi support + # + if [ "${TARGET_OS}" = "linux-gnueabi" -o "${TARGET_OS}" = "linux-uclibceabi" ]; then + echo "CONFIG_AEABI=y" >> ${S}/.config + if [ "${ARM_KEEP_OABI}" = "1" ] ; then + echo "CONFIG_OABI_COMPAT=y" >> ${S}/.config + else + echo "# CONFIG_OABI_COMPAT is not set" >> ${S}/.config + fi + else + echo "# CONFIG_AEABI is not set" >> ${S}/.config + echo "# CONFIG_OABI_COMPAT is not set" >> ${S}/.config + fi + + # When enabling thumb for userspace we also need thumb support in the kernel + if [ "${ARM_INSTRUCTION_SET}" = "thumb" ] ; then + sed -i -e /CONFIG_ARM_THUMB/d ${WORKDIR}/defconfig + echo "CONFIG_ARM_THUMB=y" >> ${S}/.config + fi + + # Enable thumb2 fixup for specific issue in angstrom toolchains when used on A8 r1p[012] silicon + if [ "${CORTEXA8FIXUP}" = "yes" ] ; then + sed -i -e /CONFIG_ARM_ERRATA_430973/d ${WORKDIR}/defconfig + echo "CONFIG_ARM_ERRATA_430973=y" >> ${S}/.config + fi + + # + # endian support + # + if [ "${SITEINFO_ENDIANNESS}" = "be" ]; then + echo "CONFIG_CPU_BIG_ENDIAN=y" >> ${S}/.config + fi + + echo "CONFIG_CMDLINE=\"${CMDLINE}\"" >> ${S}/.config + + sed -e '/CONFIG_AEABI/d' \ + -e '/CONFIG_OABI_COMPAT=/d' \ + -e '/CONFIG_CMDLINE=/d' \ + -e '/CONFIG_CPU_BIG_ENDIAN/d' \ + -e '/CONFIG_LOGO=/d' \ + -e '/CONFIG_LOGO_LINUX_CLUT224=/d' \ + -e '/CONFIG_LOCALVERSION/d' \ + -e '/CONFIG_LOCALVERSION_AUTO/d' \ + < '${WORKDIR}/defconfig' >>'${S}/.config' + + echo 'CONFIG_LOCALVERSION=""' >>${S}/.config + echo '# CONFIG_LOCALVERSION_AUTO is not set' >>${S}/.config + + # + # Udev quirks + # + + # Newer versions of udev mandate that sysfs doesn't have deprecated entries + if [ "${UDEV_GE_141}" = "1" ] ; then + sed -e /CONFIG_SYSFS_DEPRECATED/d \ + -e /CONFIG_SYSFS_DEPRECATED_V2/d \ + -e /CONFIG_HOTPLUG/d \ + -e /CONFIG_UEVENT_HELPER_PATH/d \ + -e /CONFIG_UNIX/d \ + -e /CONFIG_SYSFS/d \ + -e /CONFIG_PROC_FS/d \ + -e /CONFIG_TMPFS/d \ + -e /CONFIG_INOTIFY_USER/d \ + -e /CONFIG_SIGNALFD/d \ + -e /CONFIG_TMPFS_POSIX_ACL/d \ + -e /CONFIG_BLK_DEV_BSG/d \ + -i '${S}/.config' + + echo '# CONFIG_SYSFS_DEPRECATED is not set' >> ${S}/.config + echo '# CONFIG_SYSFS_DEPRECATED_V2 is not set' >> ${S}/.config + echo 'CONFIG_HOTPLUG=y' >> ${S}/.config + echo 'CONFIG_UEVENT_HELPER_PATH=""' >> ${S}/.config + echo 'CONFIG_UNIX=y' >> ${S}/.config + echo 'CONFIG_SYSFS=y' >> ${S}/.config + echo 'CONFIG_PROC_FS=y' >> ${S}/.config + echo 'CONFIG_TMPFS=y' >> ${S}/.config + echo 'CONFIG_INOTIFY_USER=y' >> ${S}/.config + echo 'CONFIG_SIGNALFD=y' >> ${S}/.config + echo 'CONFIG_TMPFS_POSIX_ACL=y' >> ${S}/.config + echo 'CONFIG_BLK_DEV_BSG=y' >> ${S}/.config + echo 'CONFIG_DEVTMPFS=y' >> ${S}/.config + echo 'CONFIG_DEVTMPFS_MOUNT=y' >> ${S}/.config + fi + + # Newer inits like systemd need cgroup support + if [ "${KERNEL_ENABLE_CGROUPS}" = "1" ] ; then + sed -e /CONFIG_CGROUP_SCHED/d \ + -e /CONFIG_CGROUPS/d \ + -i '${S}/.config' + + echo 'CONFIG_CGROUP_SCHED=y' >> ${S}/.config + echo 'CONFIG_CGROUPS=y' >> ${S}/.config + echo 'CONFIG_CGROUP_NS=y' >> ${S}/.config + echo 'CONFIG_CGROUP_FREEZER=y' >> ${S}/.config + echo 'CONFIG_CGROUP_DEVICE=y' >> ${S}/.config + echo 'CONFIG_CPUSETS=y' >> ${S}/.config + echo 'CONFIG_PROC_PID_CPUSET=y' >> ${S}/.config + echo 'CONFIG_CGROUP_CPUACCT=y' >> ${S}/.config + echo 'CONFIG_RESOURCE_COUNTERS=y' >> ${S}/.config + fi + + # + # root-over-nfs-over-usb-eth support. Limited, but should cover some cases. + # Enable this by setting a proper CMDLINE_NFSROOT_USB. + # + if [ ! -z "${CMDLINE_NFSROOT_USB}" ]; then + oenote "Configuring the kernel for root-over-nfs-over-usb-eth with CMDLINE ${CMDLINE_NFSROOT_USB}" + sed -e '/CONFIG_INET/d' \ + -e '/CONFIG_IP_PNP=/d' \ + -e '/CONFIG_USB_GADGET=/d' \ + -e '/CONFIG_USB_GADGET_SELECTED=/d' \ + -e '/CONFIG_USB_ETH=/d' \ + -e '/CONFIG_NFS_FS=/d' \ + -e '/CONFIG_ROOT_NFS=/d' \ + -e '/CONFIG_CMDLINE=/d' \ + -i ${S}/.config + echo "CONFIG_INET=y" >> ${S}/.config + echo "CONFIG_IP_PNP=y" >> ${S}/.config + echo "CONFIG_USB_GADGET=y" >> ${S}/.config + echo "CONFIG_USB_GADGET_SELECTED=y" >> ${S}/.config + echo "CONFIG_USB_ETH=y" >> ${S}/.config + echo "CONFIG_NFS_FS=y" >> ${S}/.config + echo "CONFIG_ROOT_NFS=y" >> ${S}/.config + echo "CONFIG_CMDLINE=\"${CMDLINE_NFSROOT_USB}\"" >> ${S}/.config + fi + yes '' | oe_runmake oldconfig +} + +do_configure_append() { + if test -e scripts/Makefile.fwinst ; then + sed -i -e "s:-m0644:-m 0644:g" scripts/Makefile.fwinst + fi +} + +# bitbake.conf only prepends PARALLEL make in tasks called do_compile, which isn't the case for compile_modules +# So explicitly enable it for that in here +EXTRA_OEMAKE = "${PARALLEL_MAKE} " + +do_install_append() { + oe_runmake headers_install INSTALL_HDR_PATH=${D}${exec_prefix}/src/linux-${KERNEL_VERSION} ARCH=$ARCH +} + +PACKAGES =+ "kernel-headers" +FILES_kernel-headers = "${exec_prefix}/src/linux*" + +do_devicetree_image() { + if test -n "${KERNEL_DEVICETREE}" ; then + dtc -I dts -O dtb ${KERNEL_DEVICETREE_FLAGS} -o devicetree ${KERNEL_DEVICETREE} + install -d ${D}/boot + install -m 0644 devicetree ${D}/boot/devicetree-${KERNEL_VERSION} + install -d ${DEPLOY_DIR_IMAGE} + install -m 0644 devicetree ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGE_BASE_NAME}.dtb + package_stagefile_shell ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGE_BASE_NAME}.dtb + cd ${DEPLOY_DIR_IMAGE} + rm -f ${KERNEL_IMAGE_SYMLINK_NAME}.dtb + ln -sf ${KERNEL_IMAGE_BASE_NAME}.dtb ${KERNEL_IMAGE_SYMLINK_NAME}.dtb + package_stagefile_shell ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGE_SYMLINK_NAME}.dtb + fi +} + +addtask devicetree_image after do_install before do_package do_deploy + +pkg_postinst_kernel-devicetree () { + cd /${KERNEL_IMAGEDEST}; update-alternatives --install /${KERNEL_IMAGEDEST}/devicetree devicetree devicetree-${KERNEL_VERSION} ${KERNEL_PRIORITY} || true +} + +pkg_postrm_kernel-devicetree () { + cd /${KERNEL_IMAGEDEST}; update-alternatives --remove devicetree devicetree-${KERNEL_VERSION} || true +} + +# Automatically depend on lzop-native if CONFIG_KERNEL_LZO is enabled +python () { + try: + defconfig = bb.fetch2.localpath('file://defconfig', d) + except bb.fetch2.FetchError: + return + + try: + configfile = open(defconfig) + except IOError: + return + + if 'CONFIG_KERNEL_LZO=y\n' in configfile.readlines(): + depends = d.getVar('DEPENDS', False) + d.setVar('DEPENDS', depends + ' lzop-native') +} |