[OpenWrt-Devel] [PATCH] RFC: OSMOCOM DECT stack on OpenWrt

Daniel daniel at makrotopia.org
Fri Jun 27 15:02:22 EDT 2014


Hi!
Thanks for having a look at stuff and sharing your thoughts!


On 2014-06-26 19:11, Florian Fainelli wrote:
> 2014-06-26 9:27 GMT-07:00 Daniel Golle <daniel at makrotopia.org>:
>> Many of todays routers got Sitel SC1442x or Dialog's SC14452 DECT
>> chips which makes them not entirely unlike hardware which is already
>> supported by Osmocom's DECT stack. I started exploring the idea to
>> make use of these devices in OpenWrt and thus ported the kernel-part
>> of the DECT stack to OpenWrt.
>> First of all, I'd be thankful for anyone to see if including this
>> patch breaks any existing OpenWrt builds on any kernel version.
>> (it really shouldn't)
>> 
>> Unfortunately, the
>> git://dect.osmocom.org/linux-2.6.git
>> tree is currently empty :(
>> However Patrick, indicated that he might push more recent code-base
>> soon, see
>> http://lists.osmocom.org/pipermail/linux-dect/2014-March/000241.html
> 
> Please wait until there is a better way to get these drivers
> delivered, the diffstat is just ridiculous, and we already carry a lot
> of out of tree code (e.g: ocf-crypto). At least, make that code a
> tarball for now and ask us to host it on downloads.openwrt.org if you
> want to.

I thought about splitting-off the drivers (which can go into packages 
eg. in the VoIP feed)  from the protocol stack which has to go into 
target/linux/generic/files/net/dect and at least include AF_DECT and 
netlink enumeration in all builds for compatibility (doesn't hurt nor 
consume space if CONFIG_DECT is disabled).
I wanted to try to build the stack out-of-tree as well (if possible 
without diverting too much from the upstream version)and only patch 
where really unavoidable...

> 
> Thanks!
> 
>> 
>> I must admit that I did terrible things to struct dect_cctrl in order
>> to get it to be portable enough to compile, but as the alignment was
>> previously implicit I most likely didn't make things better not 
>> knowing
>> what I'm doing (but got everything to build).
>> Also, I'm pretty sure that there is still stuff missing, also because
>> I had to use a quite outdated refernce and starting point for the
>> kernel-patch:
>> http://dect.osmocom.org/attachment/wiki/Patches/linux-3.0.diff
>> 
>> As the TIPC kernel-internal interfaces were widely pruned away
>> (probably due to the lack of in-kernel users?), I didn't decide on
>> how to revive the DECT Cell Control Protocol support which previously
>> used these interfaces which are no longer present in recent kernels.
>> 
>> With the patch attached allows to build and package the existing
>> drivers from linux-3.0.diff to OpenWrt targets based on kernel v3.10
>> and above.
>> I'd be glad to know if the driver loads and probes correctly on
>> com-on-air-{pci,cs} hardware (there is some com-on-air-cs hardware
>> flying around here but I didn't yet get hold of a PCMCIA host to use
>> it with)
>> 
>> 
>> Have fun!
>> 
>> Signed-off-by: Daniel Golle <daniel at makrotopia.org>
>> ---
>>  package/kernel/linux/modules/netdevices.mk         |  104 +
>>  target/linux/generic/files/drivers/dect/Kconfig    |   11 +
>>  target/linux/generic/files/drivers/dect/Makefile   |    2 +
>>  .../generic/files/drivers/dect/coa/.gitignore      |    4 +
>>  .../linux/generic/files/drivers/dect/coa/Kconfig   |   38 +
>>  .../linux/generic/files/drivers/dect/coa/Makefile  |   41 +
>>  .../linux/generic/files/drivers/dect/coa/bin2c.c   |   57 +
>>  .../generic/files/drivers/dect/coa/com_on_air.h    |   99 +
>>  .../generic/files/drivers/dect/coa/com_on_air_cs.c |  271 +
>>  .../files/drivers/dect/coa/com_on_air_pci.c        |  165 +
>>  .../generic/files/drivers/dect/coa/dip_opcodes.h   |  157 +
>>  .../generic/files/drivers/dect/coa/radio_lmx3161.c |   84 +
>>  .../generic/files/drivers/dect/coa/radio_u2785.c   |  261 +
>>  .../linux/generic/files/drivers/dect/coa/sc1442x.c | 1020 ++++
>>  .../files/drivers/dect/coa/sc1442x_firmware.asm    |  389 ++
>>  .../files/drivers/dect/coa/sc1442x_firmware.c      |   73 +
>>  .../files/drivers/dect/coa/sc1442x_firmware.h      |   66 +
>>  .../linux/generic/files/drivers/dect/vtrx/Kconfig  |    5 +
>>  .../linux/generic/files/drivers/dect/vtrx/Makefile |    2 +
>>  .../generic/files/drivers/dect/vtrx/mw_to_dbm.c    |  164 +
>>  .../generic/files/drivers/dect/vtrx/vtrx-sysfs.c   |  229 +
>>  .../linux/generic/files/drivers/dect/vtrx/vtrx.c   |  397 ++
>>  .../linux/generic/files/drivers/dect/vtrx/vtrx.h   |   42 +
>>  target/linux/generic/files/include/linux/dect.h    |  167 +
>>  .../generic/files/include/linux/dect_netlink.h     |  395 ++
>>  target/linux/generic/files/include/net/dect/ccp.h  |  110 +
>>  target/linux/generic/files/include/net/dect/dect.h |  319 ++
>>  target/linux/generic/files/include/net/dect/dlc.h  |  462 ++
>>  target/linux/generic/files/include/net/dect/dsc.h  |   12 +
>>  .../generic/files/include/net/dect/identities.h    |  194 +
>>  target/linux/generic/files/include/net/dect/mac.h  |  861 ++++
>>  .../linux/generic/files/include/net/dect/mac_ccf.h |  250 +
>>  .../linux/generic/files/include/net/dect/mac_csf.h |  596 +++
>>  .../generic/files/include/net/dect/transceiver.h   |  726 +++
>>  target/linux/generic/files/net/dect/Kconfig        |   66 +
>>  target/linux/generic/files/net/dect/Makefile       |   17 +
>>  target/linux/generic/files/net/dect/af_dect.c      |  456 ++
>>  target/linux/generic/files/net/dect/ccp.c          |  906 ++++
>>  target/linux/generic/files/net/dect/core.c         |  183 +
>>  target/linux/generic/files/net/dect/dect_netlink.c |  150 +
>>  target/linux/generic/files/net/dect/dlc.c          |  282 ++
>>  target/linux/generic/files/net/dect/dlc_b_sap.c    |  277 ++
>>  target/linux/generic/files/net/dect/dlc_cplane.c   |  981 ++++
>>  target/linux/generic/files/net/dect/dlc_lu1_sap.c  |  474 ++
>>  target/linux/generic/files/net/dect/dlc_s_sap.c    |  659 +++
>>  target/linux/generic/files/net/dect/dlc_uplane.c   |   86 +
>>  target/linux/generic/files/net/dect/dsc.c          |  141 +
>>  target/linux/generic/files/net/dect/identities.c   |  221 +
>>  target/linux/generic/files/net/dect/mac_ccf.c      | 2070 ++++++++
>>  target/linux/generic/files/net/dect/mac_csf.c      | 5151 
>> ++++++++++++++++++++
>>  target/linux/generic/files/net/dect/raw.c          |  267 +
>>  target/linux/generic/files/net/dect/transceiver.c  | 1031 ++++
>>  .../generic/patches-3.10/780-dect-support.patch    |  155 +
>>  .../generic/patches-3.12/780-dect-support.patch    |  155 +
>>  .../generic/patches-3.13/780-dect-support.patch    |  155 +
>>  .../generic/patches-3.14/780-dect-support.patch    |  155 +
>>  56 files changed, 21811 insertions(+)
>>  create mode 100644 target/linux/generic/files/drivers/dect/Kconfig
>>  create mode 100644 target/linux/generic/files/drivers/dect/Makefile
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/.gitignore
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/Kconfig
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/Makefile
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/bin2c.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/com_on_air.h
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/com_on_air_cs.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/com_on_air_pci.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/dip_opcodes.h
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/radio_lmx3161.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/radio_u2785.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/sc1442x.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.asm
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.h
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/Kconfig
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/Makefile
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/mw_to_dbm.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/vtrx-sysfs.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/vtrx.c
>>  create mode 100644 
>> target/linux/generic/files/drivers/dect/vtrx/vtrx.h
>>  create mode 100644 target/linux/generic/files/include/linux/dect.h
>>  create mode 100644 
>> target/linux/generic/files/include/linux/dect_netlink.h
>>  create mode 100644 target/linux/generic/files/include/net/dect/ccp.h
>>  create mode 100644 target/linux/generic/files/include/net/dect/dect.h
>>  create mode 100644 target/linux/generic/files/include/net/dect/dlc.h
>>  create mode 100644 target/linux/generic/files/include/net/dect/dsc.h
>>  create mode 100644 
>> target/linux/generic/files/include/net/dect/identities.h
>>  create mode 100644 target/linux/generic/files/include/net/dect/mac.h
>>  create mode 100644 
>> target/linux/generic/files/include/net/dect/mac_ccf.h
>>  create mode 100644 
>> target/linux/generic/files/include/net/dect/mac_csf.h
>>  create mode 100644 
>> target/linux/generic/files/include/net/dect/transceiver.h
>>  create mode 100644 target/linux/generic/files/net/dect/Kconfig
>>  create mode 100644 target/linux/generic/files/net/dect/Makefile
>>  create mode 100644 target/linux/generic/files/net/dect/af_dect.c
>>  create mode 100644 target/linux/generic/files/net/dect/ccp.c
>>  create mode 100644 target/linux/generic/files/net/dect/core.c
>>  create mode 100644 target/linux/generic/files/net/dect/dect_netlink.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc_b_sap.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc_cplane.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc_lu1_sap.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc_s_sap.c
>>  create mode 100644 target/linux/generic/files/net/dect/dlc_uplane.c
>>  create mode 100644 target/linux/generic/files/net/dect/dsc.c
>>  create mode 100644 target/linux/generic/files/net/dect/identities.c
>>  create mode 100644 target/linux/generic/files/net/dect/mac_ccf.c
>>  create mode 100644 target/linux/generic/files/net/dect/mac_csf.c
>>  create mode 100644 target/linux/generic/files/net/dect/raw.c
>>  create mode 100644 target/linux/generic/files/net/dect/transceiver.c
>>  create mode 100644 
>> target/linux/generic/patches-3.10/780-dect-support.patch
>>  create mode 100644 
>> target/linux/generic/patches-3.12/780-dect-support.patch
>>  create mode 100644 
>> target/linux/generic/patches-3.13/780-dect-support.patch
>>  create mode 100644 
>> target/linux/generic/patches-3.14/780-dect-support.patch
>> 
>> diff --git a/package/kernel/linux/modules/netdevices.mk 
>> b/package/kernel/linux/modules/netdevices.mk
>> index 221eb2f..ec85b7e 100644
>> --- a/package/kernel/linux/modules/netdevices.mk
>> +++ b/package/kernel/linux/modules/netdevices.mk
>> @@ -772,3 +772,107 @@ define KernelPackage/vmxnet3/description
>>  endef
>> 
>>  $(eval $(call KernelPackage,vmxnet3))
>> +
>> +define KernelPackage/dect
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT subsystem
>> +  DEPENDS:=@!LINUX_3_3 @!LINUX_3_6 @!LINUX_3_8 @!LINUX_3_9
>> +  KCONFIG:= \
>> +       CONFIG_DECT \
>> +       CONFIG_DECTDEVICES=y \
>> +       CONFIG_DECT_DEBUG=n
>> +  FILES:=$(LINUX_DIR)/net/dect/dect.ko
>> +  AUTOLOAD:=$(call AutoProbe,dect)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect))
>> +
>> +
>> +define KernelPackage/dect-ccf
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT Cluster Control Functions (CCF) support
>> +  KCONFIG:=CONFIG_DECT_CCF
>> +  FILES:=$(LINUX_DIR)/net/dect/dect_ccf.ko
>> +  DEPENDS:=kmod-dect
>> +  AUTOLOAD:=$(call AutoProbe,dect-ccf)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-ccf))
>> +
>> +define KernelPackage/dect-csf
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT Cell Site Functions
>> +  KCONFIG:=CONFIG_DECT_CSF
>> +  FILES:=$(LINUX_DIR)/net/dect/dect_csf.ko
>> +  DEPENDS:=kmod-dect
>> +  AUTOLOAD:=$(call AutoProbe,dect-csf)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-csf))
>> +
>> +define KernelPackage/dect-dlc-lu1-sap
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT DLC LU1 SAP sockets
>> +  KCONFIG:=CONFIG_DECT_LU1_SAP
>> +  FILES:=$(LINUX_DIR)/net/dect/dlc_lu1_sap.ko
>> +  DEPENDS:=kmod-dect +kmod-dect-ccf
>> +  AUTOLOAD:=$(call AutoProbe,dlc-lu1-sap)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-dlc-lu1-sap))
>> +
>> +define KernelPackage/dect-raw
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT RAW
>> +  KCONFIG:=CONFIG_DECT_RAW
>> +  FILES:=$(LINUX_DIR)/net/dect/dect_raw.ko
>> +  DEPENDS:=kmod-dect +kmod-dect-csf
>> +  AUTOLOAD:=$(call AutoProbe,dect-raw)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-raw))
>> +
>> +define KernelPackage/dect-comonair
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT com-on-air common
>> +  KCONFIG:=CONFIG_DECT_COA \
>> +       CONFIG_DECT_COA_FIRMWARE=n
>> +  FILES:=$(LINUX_DIR)/drivers/dect/coa/com_on_air.ko
>> +  DEPENDS:=kmod-dect +kmod-dect-csf
>> +  AUTOLOAD:=$(call AutoProbe,com-on-air)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-comonair))
>> +
>> +define KernelPackage/dect-comonair-pci
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=Com-on-Air PCI DECT support
>> +  KCONFIG:=CONFIG_DECT_COA_PCI
>> +  FILES:=$(LINUX_DIR)/drivers/dect/coa/com_on_air_pci.ko
>> +  DEPENDS:=+kmod-dect-comonair @PCI_SUPPORT
>> +  AUTOLOAD:=$(call AutoProbe,com-on-air-pci)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-comonair-pci))
>> +
>> +define KernelPackage/dect-comonair-cs
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=Com-on-Air PCMCIA DECT support
>> +  KCONFIG:=CONFIG_DECT_COA_CS
>> +  FILES:=$(LINUX_DIR)/drivers/dect/coa/com_on_air_cs.ko
>> +  DEPENDS:=+kmod-dect-comonair @PCMCIA_SUPPORT
>> +  AUTOLOAD:=$(call AutoProbe,com-on-air-cs)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-comonair-cs))
>> +
>> +define KernelPackage/dect-vtrx
>> +  SUBMENU:=$(NETWORK_DEVICES_MENU)
>> +  TITLE:=DECT virtual transceiver (for testing)
>> +  KCONFIG:=CONFIG_DECT_VTRX
>> +  FILES:=$(LINUX_DIR)/drivers/dect/vtrx/dect-vtrx.ko
>> +  DEPENDS:=+kmod-dect-csf
>> +  AUTOLOAD:=$(call AutoProbe,dect-vtrx)
>> +endef
>> +
>> +$(eval $(call KernelPackage,dect-vtrx))
>> diff --git a/target/linux/generic/files/drivers/dect/Kconfig 
>> b/target/linux/generic/files/drivers/dect/Kconfig
>> new file mode 100644
>> index 0000000..baba4c1
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/Kconfig
>> @@ -0,0 +1,11 @@
>> +menuconfig DECTDEVICES
>> +       bool "DECT device support"
>> +       help
>> +         Say Y here to show DECT device driver options.
>> +
>> +if DECTDEVICES
>> +
>> +source "drivers/dect/vtrx/Kconfig"
>> +source "drivers/dect/coa/Kconfig"
>> +
>> +endif
>> diff --git a/target/linux/generic/files/drivers/dect/Makefile 
>> b/target/linux/generic/files/drivers/dect/Makefile
>> new file mode 100644
>> index 0000000..c58af58
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/Makefile
>> @@ -0,0 +1,2 @@
>> +obj-$(CONFIG_DECT_VTRX)        += vtrx/
>> +obj-$(CONFIG_DECT_COA) += coa/
>> diff --git a/target/linux/generic/files/drivers/dect/coa/.gitignore 
>> b/target/linux/generic/files/drivers/dect/coa/.gitignore
>> new file mode 100644
>> index 0000000..7890f99
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/.gitignore
>> @@ -0,0 +1,4 @@
>> +bin2c
>> +*.p
>> +*.h.tmp
>> +*.bin
>> diff --git a/target/linux/generic/files/drivers/dect/coa/Kconfig 
>> b/target/linux/generic/files/drivers/dect/coa/Kconfig
>> new file mode 100644
>> index 0000000..8773ad7
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/Kconfig
>> @@ -0,0 +1,38 @@
>> +config DECT_COA_PCI
>> +       tristate "Com-on-Air PCI DECT support"
>> +       depends on DECT
>> +       depends on PCI
>> +       select DECT_COA
>> +       select DECT_COA_U2785
>> +       help
>> +         This option enables support for the Com-on-Air DECT PCI 
>> devices.
>> +
>> +config DECT_COA_CS
>> +       tristate "Com-on-Air PCMCIA DECT support"
>> +       depends on DECT
>> +       depends on PCMCIA
>> +       select DECT_COA
>> +       select DECT_COA_U2785
>> +       select DECT_COA_LMX3161
>> +       select CRC32
>> +       help
>> +         This option enables support for the Com-on-Air DECT PCMCIA 
>> devices.
>> +
>> +config DECT_COA
>> +       tristate
>> +
>> +config DECT_COA_U2785
>> +       bool
>> +
>> +config DECT_COA_LMX3161
>> +       bool
>> +
>> +config DECT_COA_FIRMWARE
>> +       bool "Build Com-on-Air firmware (requires ASL macro 
>> assembler)"
>> +       depends on DECT_COA
>> +       help
>> +         This option enables rebuild of the firmware for the 
>> Com-on-Air
>> +         devices during the kernel build process. The ASL macro 
>> compiler
>> +         is required for this.
>> +
>> +         If unsure, say N.
>> diff --git a/target/linux/generic/files/drivers/dect/coa/Makefile 
>> b/target/linux/generic/files/drivers/dect/coa/Makefile
>> new file mode 100644
>> index 0000000..8ac23c3
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/Makefile
>> @@ -0,0 +1,41 @@
>> +com_on_air-objs                                := sc1442x_firmware.o 
>> sc1442x.o
>> +com_on_air-$(CONFIG_DECT_COA_U2785)    += radio_u2785.o
>> +com_on_air-$(CONFIG_DECT_COA_LMX3161)  += radio_lmx3161.o
>> +
>> +obj-$(CONFIG_DECT_COA)                 += com_on_air.o
>> +obj-$(CONFIG_DECT_COA_PCI)             += com_on_air_pci.o
>> +obj-$(CONFIG_DECT_COA_CS)              += com_on_air_cs.o
>> +
>> +$(obj)/sc1442x.o:                      $(obj)/sc1442x_firmware.c
>> +$(obj)/sc1442x_firmware.c:             NAME=sc1442x
>> +clean-files                            += sc1442x_firmware.p
>> +clean-files                            += sc1442x_firmware.bin
>> +clean-files                            += sc1442x_firmware.h.tmp
>> +
>> +hostprogs-$(CONFIG_DECT_COA_FIRMWARE)  += bin2c
>> +
>> +ifeq ($(CONFIG_DECT_COA_FIRMWARE),y)
>> +
>> +ASL            = asl
>> +P2BIN          = p2bin
>> +BIN2C          = $(obj)/bin2c
>> +
>> +quiet_cmd_asl  = ASL     $<
>> +      cmd_asl  = $(ASL) -q -c $< -o $(<:.asm=.p) -shareout 
>> $(<:.asm=.h.tmp); \
>> +                 $(P2BIN) $(<:.asm=.p) $(<:.asm=.bin) -r 0-509; \
>> +                 $(BIN2C) $(<:.asm=.bin) $(NAME)_firmware > $@; \
>> +                 ( \
>> +                       echo "\#ifndef $$(echo $(NAME) | tr a-z 
>> A-Z)_FIRMWARE"; \
>> +                       echo "\#define $$(echo $(NAME) | tr a-z 
>> A-Z)_FIRMWARE"; \
>> +                       echo;\
>> +                       echo "extern const unsigned char 
>> $(NAME)_firmware[510];"; \
>> +                       echo;\
>> +                       grep define $(<:.asm=.h.tmp); \
>> +                       echo;\
>> +                       echo "\#endif /* $$(echo $(NAME) | tr a-z 
>> A-Z)_FIRMWARE */"; \
>> +                 ) > $(@:.c=.h)
>> +
>> +$(obj)/%_firmware.c: $(src)/%_firmware.asm $(BIN2C)
>> +       $(call if_changed,asl)
>> +
>> +endif
>> diff --git a/target/linux/generic/files/drivers/dect/coa/bin2c.c 
>> b/target/linux/generic/files/drivers/dect/coa/bin2c.c
>> new file mode 100644
>> index 0000000..bab08fa
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/bin2c.c
>> @@ -0,0 +1,57 @@
>> +#include <stdio.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +#include <string.h>
>> +#include <errno.h>
>> +#include <stdint.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +
>> +#define HEADER_FMT \
>> +       "/*\n"                                          \
>> +       " * automatically generated file\n"             \
>> +       " * DO NOT EDIT\n"                              \
>> +       " * edit firmware/filename.asm instead\n"       \
>> +       " */\n"                                         \
>> +       "\n"                                            \
>> +       "#include \"%s.h\"\n"                           \
>> +       "\n"                                            \
>> +       "const unsigned char %s[] = {\n"
>> +
>> +#define FOOTER "};\n"
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +       uint32_t wordcount = 0;
>> +       uint16_t w;
>> +       int f;
>> +
>> +       if (argc < 3) {
>> +               printf("usage: bin2c bin-file varname > c-file\n");
>> +               exit(1);
>> +       }
>> +
>> +       f = open(argv[1], O_RDONLY);
>> +       if (f < 0) {
>> +               printf("cant open(\"%s\"): %s\n", argv[1], 
>> strerror(errno));
>> +               exit(1);
>> +       }
>> +
>> +       printf(HEADER_FMT, argv[2], argv[2]);
>> +
>> +       while (2 == read(f, &w, 2)) {
>> +               if (!wordcount)
>> +                       printf("\t");
>> +               else
>> +                       if (!(wordcount % 4))
>> +                               printf(",\n\t");
>> +                       else
>> +                               printf(", ");
>> +               printf("0x%.2x, 0x%.2x", (w & 0xff00) >> 8, w & 0xff);
>> +               wordcount++;
>> +       }
>> +       printf(FOOTER);
>> +       close(f);
>> +       return 0;
>> +}
>> diff --git a/target/linux/generic/files/drivers/dect/coa/com_on_air.h 
>> b/target/linux/generic/files/drivers/dect/coa/com_on_air.h
>> new file mode 100644
>> index 0000000..37c2b0a
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/com_on_air.h
>> @@ -0,0 +1,99 @@
>> +/*
>> + * com_on_air - basic driver for the Dosch and Amand "com on air" 
>> cards
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * authors:
>> + * (C) 2008  Andreas Schuler <krater at badterrorist dot com>
>> + * (C) 2008  Matthias Wenzel <dect at mazzoo dot de>
>> + * (C) 2009  Patrick McHardy <kaber at trash.net>
>> + *
>> + */
>> +
>> +#ifndef COM_ON_AIR_H
>> +#define COM_ON_AIR_H
>> +
>> +#include <linux/types.h>
>> +
>> +struct coa_freq_map_entry {
>> +       struct {
>> +               u8      divisor;
>> +               u8      swcnt;
>> +       } rx, tx;
>> +};
>> +
>> +struct coa_freq_map {
>> +       struct coa_freq_map_entry       carrier[DECT_CARRIER_NUM];
>> +};
>> +
>> +struct coa_device;
>> +struct coa_radio_ops {
>> +       void            (*rx_init)(const struct coa_device *dev, u16 
>> offset);
>> +       void            (*tx_init)(const struct coa_device *dev, u16 
>> offset);
>> +       void            (*set_carrier)(const struct coa_device *dev, 
>> u16 offset,
>> +                                      enum dect_slot_states mode, u8 
>> carrier);
>> +       u64             (*map_band)(struct coa_device *dev,
>> +                                   const struct dect_band *band);
>> +       const char      *type;
>> +};
>> +
>> +extern const struct coa_radio_ops coa_u2785_radio_ops;
>> +extern const struct coa_radio_ops coa_lmx3161_radio_ops;
>> +
>> +/**
>> + * struct sc1442x_phase_state - per-slot phase offset state
>> + *
>> + * @framenum:  frame number the information was last updated
>> + * @tap:       sc1442x internal clock cycle which sampled the data
>> + * @phase:     offset of number of symbol periods to nominal 11520 
>> symbols per frame
>> + *
>> + * This structure is used to store the measured values for one 
>> particular
>> + * frame. The actual phase offset is calculated from the differences 
>> of two
>> + * consequitive frames.
>> + */
>> +struct sc1442x_phase_state {
>> +       u8      framenum;
>> +       u8      tap;
>> +       s8      phase;
>> +};
>> +
>> +enum coa_device_types {
>> +       COA_TYPE_PCI,
>> +       COA_TYPE_PCMCIA,
>> +};
>> +
>> +struct coa_device {
>> +       const struct device             *dev;
>> +       unsigned int                    irq;
>> +
>> +       enum coa_device_types           type;
>> +
>> +       const struct coa_radio_ops      *radio_ops;
>> +       struct coa_freq_map             freq_map;
>> +       struct sc1442x_phase_state      phase_state[DECT_FRAME_SIZE / 
>> 2];
>> +
>> +       spinlock_t                      lock;
>> +       uint                            config_base;
>> +       u8 __iomem                      *sc1442x_base;
>> +       u16                             cfg_reg;
>> +       u16                             irq_reg;
>> +       u16                             code_base;
>> +       u16                             data_base;
>> +       u16                             data_mask;
>> +
>> +       u8                              ctrl;
>> +       u8                              led;
>> +};
>> +
>> +extern irqreturn_t sc1442x_interrupt(int irq, void *dev_id);
>> +extern const struct dect_transceiver_ops sc1442x_transceiver_ops;
>> +
>> +extern int sc1442x_init_device(struct coa_device *dev);
>> +extern void sc1442x_shutdown_device(struct coa_device *dev);
>> +
>> +extern void sc1442x_rfdesc_write(const struct coa_device *dev, u16 
>> offset,
>> +                                const u8 *src, u16 length);
>> +
>> +#endif
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/com_on_air_cs.c 
>> b/target/linux/generic/files/drivers/dect/coa/com_on_air_cs.c
>> new file mode 100644
>> index 0000000..e1f2231
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/com_on_air_cs.c
>> @@ -0,0 +1,271 @@
>> +/*
>> + * com_on_air_cs - basic driver for the Dosch and Amand "com on air" 
>> cards
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * authors:
>> + * (C) 2008  Andreas Schuler <krater at badterrorist dot com>
>> + * (C) 2008  Matthias Wenzel <dect at mazzoo dot de>
>> + * (C) 2009  Patrick McHardy <kaber at trash.net>
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/init.h>
>> +#include <linux/crc32.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +#include <pcmcia/cistpl.h>
>> +#include <pcmcia/ciscode.h>
>> +#include <pcmcia/ds.h>
>> +#include <pcmcia/cisreg.h>
>> +
>> +#include "com_on_air.h"
>> +
>> +MODULE_AUTHOR("Matthias Wenzel comonair<a>mazzoo.de;"
>> +              "Andreas Schuler dect<a>badterrorist.com");
>> +MODULE_DESCRIPTION("Dosch&Amand COM-ON-AIR PCMCIA driver");
>> +MODULE_LICENSE("GPL");
>> +
>> +static int get_card_id(const struct pcmcia_device *link);
>> +
>> +static int com_on_air_probe(struct pcmcia_device *link)
>> +{
>> +       struct dect_transceiver *trx;
>> +       struct coa_device *dev;
>> +       int err;
>> +
>> +       trx = dect_transceiver_alloc(&sc1442x_transceiver_ops, 
>> sizeof(*dev));
>> +       if (!trx) {
>> +               err = -ENOMEM;
>> +               goto err1;
>> +       }
>> +
>> +       link->priv = trx;
>> +       dev = dect_transceiver_priv(trx);
>> +       dev->type      = COA_TYPE_PCMCIA;
>> +       dev->code_base = 0x0;
>> +       dev->data_base = 0x0;
>> +       dev->data_mask = 0x0ff;
>> +       dev->cfg_reg   = 0x1ff;
>> +       dev->irq_reg   = 0x0;
>> +       dev->dev       = &link->dev;
>> +
>> +       dev_info(dev->dev, "%s %s %s %s\n", link->prod_id[0], 
>> link->prod_id[1],
>> +                link->prod_id[2] ? : "", link->prod_id[3] ? : "");
>> +
>> +       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
>> +       link->resource[0]->end    = 16;
>> +       link->resource[1]->flags |= 0;
>> +
>> +       link->config_flags        = CONF_ENABLE_IRQ;
>> +       link->config_index        = 1;
>> +       link->config_regs         = PRESENT_OPTION;
>> +       link->config_base         = 0x1020;
>> +
>> +       link->resource[2]->flags  = WIN_DATA_WIDTH_16 | WIN_ENABLE;
>> +       link->resource[2]->start  = 0;
>> +       link->resource[2]->end    = 0x1000;
>> +
>> +       err = pcmcia_request_window(link, link->resource[2], 500);
>> +       if (err < 0) {
>> +               dev_err(dev->dev, "failed to obtain PCMCIA window\n");
>> +               goto err2;
>> +       }
>> +
>> +       dev->sc1442x_base = ioremap_nocache(link->resource[2]->start,
>> +                                           
>> resource_size(link->resource[2]));
>> +       if (!dev->sc1442x_base) {
>> +               dev_err(dev->dev, "failed to remap PCMCIA 
>> resource\n");
>> +               err = -EIO;
>> +               goto err3;
>> +       }
>> +
>> +       link->socket->functions = 0;
>> +
>> +       err = pcmcia_request_irq(link, sc1442x_interrupt);
>> +       if (err < 0) {
>> +               dev_err(dev->dev, "failed to request IRQ%d\n", 
>> link->irq);
>> +               goto err4;
>> +       }
>> +
>> +       err = pcmcia_enable_device(link);
>> +       if (err < 0) {
>> +               dev_err(dev->dev, "failed to enable PCMCIA device\n");
>> +               goto err5;
>> +       }
>> +
>> +       dev_dbg(dev->dev, "%svalid client.\n", (link->config_flags) ? 
>> "":"in");
>> +       dev_dbg(dev->dev, "Type          0x%x\n", 
>> link->socket->state);
>> +       dev_dbg(dev->dev, "Function      0x%x\n", link->func);
>> +       dev_dbg(dev->dev, "config_flags  %d\n", link->config_flags);
>> +       dev_dbg(dev->dev, "config_base   0x%x\n", link->config_base);
>> +       dev_dbg(dev->dev, "config_regs   %d\n", link->config_regs);
>> +       dev_dbg(dev->dev, "IRQ           0x%x\n", link->irq);
>> +       dev_dbg(dev->dev, "BasePort1     0x%llx\n", 
>> link->resource[0]->start);
>> +       dev_dbg(dev->dev, "NumPorts1     0x%llx\n", 
>> link->resource[0]->end);
>> +       dev_dbg(dev->dev, "Attributes1   0x%lx\n", 
>> link->resource[0]->flags);
>> +       dev_dbg(dev->dev, "BasePort2     0x%llx\n", 
>> link->resource[1]->start);
>> +       dev_dbg(dev->dev, "NumPorts2     0x%llx\n", 
>> link->resource[1]->end);
>> +       dev_dbg(dev->dev, "Attributes2   0x%lx\n", 
>> link->resource[1]->flags);
>> +       dev_dbg(dev->dev, "IOAddrLines   0x%x\n", link->io_lines);
>> +       dev_dbg(dev->dev, "has%s function_config\n",
>> +               link->function_config ? "":" no");
>> +
>> +       switch (get_card_id(link)) {
>> +       case 0:
>> +       case 3:
>> +               dev->radio_ops = &coa_u2785_radio_ops;
>> +               break;
>> +       case 1:
>> +       case 2:
>> +               dev->radio_ops = &coa_lmx3161_radio_ops;
>> +               break;
>> +       default:
>> +               dev_err(dev->dev, "unknown radio type\n");
>> +               err = -EINVAL;
>> +               goto err5;
>> +       }
>> +
>> +       dev_info(dev->dev, "Radio type %s\n", dev->radio_ops->type);
>> +
>> +       dev->irq         = link->irq;
>> +       dev->config_base = link->config_base;
>> +       err = sc1442x_init_device(dev);
>> +       if (err < 0)
>> +               goto err5;
>> +
>> +       err = dect_register_transceiver(trx);
>> +       if (err < 0)
>> +               goto err6;
>> +
>> +       return 0;
>> +
>> +err6:
>> +       sc1442x_shutdown_device(dev);
>> +err5:
>> +       pcmcia_disable_device(link);
>> +err4:
>> +       iounmap(dev->sc1442x_base);
>> +err3:
>> +       pcmcia_release_window(link, link->resource[2]);
>> +err2:
>> +       dect_transceiver_free(trx);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static void com_on_air_remove(struct pcmcia_device *link)
>> +{
>> +       struct dect_transceiver *trx = link->priv;
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       u8 __iomem *sc1442x_base = dev->sc1442x_base;
>> +
>> +       sc1442x_shutdown_device(dev);
>> +       pcmcia_disable_device(link);
>> +       dect_unregister_transceiver(trx);
>> +       iounmap(sc1442x_base);
>> +}
>> +
>> +static int com_on_air_suspend(struct pcmcia_device *link)
>> +{
>> +       struct dect_transceiver *trx = link->priv;
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       sc1442x_shutdown_device(dev);
>> +       return 0;
>> +}
>> +
>> +static int com_on_air_resume(struct pcmcia_device *link)
>> +{
>> +       struct dect_transceiver *trx = link->priv;
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       return sc1442x_init_device(dev);
>> +}
>> +
>> +static struct pcmcia_device_id com_on_air_ids[] = {
>> +       /*
>> +        * The crc32 hashes below are generated by the tool in
>> +        * Documentation/pcmcia/devicetable.txt
>> +        */
>> +       PCMCIA_DEVICE_PROD_ID12  ("DECTDataDevice", "PCMCIA F22",
>> +                                  0x11fe69e9,       0x253670b2),
>> +       PCMCIA_DEVICE_PROD_ID12  ("DECTDataDevice", "PCMCIA",
>> +                                  0x11fe69e9,       0x281f1c5d),
>> +       PCMCIA_DEVICE_PROD_ID1234("DOSCH-AMAND",    "MMAP PCMCIA",
>> +                                 "MXM500",         "V1.00",
>> +                                  0x4bc552e7,       0x0df519bb,
>> +                                  0x09e43c7c,       0x3488c81a),
>> +       PCMCIA_DEVICE_PROD_ID12  ("DECTVoIPDevice", "PCMCIA DA099",
>> +                                  0xeabb0be4,       0xd7b915fe),
>> +#if 0
>> +       There are more devices out there, I only own the above three.
>> +       an excerpt from win32 dna.inf:
>> +
>> +%String1%=pcmcia.install,PCMCIA\DOSCH-AMAND-MMAP_PCMCIA-C7D7
>> +%String1%=pcmcia.install,PCMCIA\Dosch-Amand-DECT_MultiMedia-BD0D
>> +%String1%=pcmcia.install,PCMCIA\DOSCH_&_AMAND-DECT_MULTIMEDIA-1A9F
>> +%String1%=pcmcia.install,PCMCIA\DECTDataDevice-F13-6433
>> +%String1%=pcmcia.install,PCMCIA\DECTDataDevice-PCMCIA-0EF8
>> +%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_000111E3&REV_00
>> +%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_00011786&REV_32
>> +%String4%=pci.install,PCI\VEN_1786&DEV_0001&SUBSYS_000111E3&REV_00
>> +%String5%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA-FEF2
>> +%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-4BD3
>> +%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-BBD9
>> +
>> +#endif
>> +       PCMCIA_DEVICE_NULL
>> +};
>> +
>> +MODULE_DEVICE_TABLE(pcmcia, com_on_air_ids);
>> +
>> +/* returns an index into com_on_air_ids[] */
>> +static int get_card_id(const struct pcmcia_device *link)
>> +{
>> +       u32 hash[4] = {};
>> +       unsigned int i;
>> +
>> +       for (i = 0; i < 4; i++) {
>> +               if (link->prod_id[i] == NULL)
>> +                       continue;
>> +               hash[i] = crc32(0, link->prod_id[i], 
>> strlen(link->prod_id[i]));
>> +       }
>> +
>> +       for (i = 0; i < ARRAY_SIZE(com_on_air_ids) - 1; i++) {
>> +               if ((hash[0] == com_on_air_ids[i].prod_id_hash[0]) &&
>> +                   (hash[1] == com_on_air_ids[i].prod_id_hash[1]) &&
>> +                   (hash[2] == com_on_air_ids[i].prod_id_hash[2]) &&
>> +                   (hash[3] == com_on_air_ids[i].prod_id_hash[3]))
>> +                       return i;
>> +       }
>> +       return -1;
>> +}
>> +
>> +static struct pcmcia_driver coa_driver = {
>> +       .owner          = THIS_MODULE,
>> +       .name           = KBUILD_MODNAME,
>> +       .probe          = com_on_air_probe,
>> +       .remove         = com_on_air_remove,
>> +       .suspend        = com_on_air_suspend,
>> +       .resume         = com_on_air_resume,
>> +       .id_table       = com_on_air_ids,
>> +};
>> +
>> +static int __init init_com_on_air_cs(void)
>> +{
>> +       return pcmcia_register_driver(&coa_driver);
>> +}
>> +
>> +static void __exit exit_com_on_air_cs(void)
>> +{
>> +       pcmcia_unregister_driver(&coa_driver);
>> +}
>> +
>> +module_init(init_com_on_air_cs);
>> +module_exit(exit_com_on_air_cs);
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/com_on_air_pci.c 
>> b/target/linux/generic/files/drivers/dect/coa/com_on_air_pci.c
>> new file mode 100644
>> index 0000000..a266f75
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/com_on_air_pci.c
>> @@ -0,0 +1,165 @@
>> +/*
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/pci.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +#include "com_on_air.h"
>> +
>> +#define PCI_VENDOR_ID_QUICKLOGIC       0x11e3
>> +#define PCI_DEVICE_ID_COA              0x0001
>> +
>> +static int coa_probe(struct pci_dev *pdev,
>> +                              const struct pci_device_id *ent)
>> +{
>> +       struct dect_transceiver *trx;
>> +       struct coa_device *dev;
>> +       void __iomem *base;
>> +       int err;
>> +
>> +       err = pci_enable_device(pdev);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "failed to enable PCI device\n");
>> +               goto err1;
>> +       }
>> +       pci_set_master(pdev);
>> +
>> +       err = pci_request_regions(pdev, KBUILD_MODNAME);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "failed to obtain PCI 
>> resources\n");
>> +               goto err2;
>> +       }
>> +
>> +       base = ioremap_nocache(pci_resource_start(pdev, 0),
>> +                              pci_resource_len(pdev, 0));
>> +       if (base == NULL) {
>> +               dev_err(&pdev->dev, "failed to remap PCI resource\n");
>> +               err = -EIO;
>> +               goto err3;
>> +       }
>> +
>> +       trx = dect_transceiver_alloc(&sc1442x_transceiver_ops, 
>> sizeof(*dev));
>> +       if (trx == NULL) {
>> +               err = -ENOMEM;
>> +               goto err4;
>> +       }
>> +       pci_set_drvdata(pdev, trx);
>> +
>> +       dev = dect_transceiver_priv(trx);
>> +       dev->type         = COA_TYPE_PCI;
>> +       dev->dev          = &pdev->dev;
>> +       dev->sc1442x_base = base;
>> +       dev->radio_ops    = &coa_u2785_radio_ops;
>> +       dev->data_base    = 0x0a00;
>> +       dev->data_mask    = 0x7ff;
>> +       dev->cfg_reg      = 0x1fe2;
>> +       dev->code_base    = 0x1a00;
>> +
>> +       err = sc1442x_init_device(dev);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "failed to initialize chip\n");
>> +               goto err5;
>> +       }
>> +
>> +       err = request_irq(pdev->irq, sc1442x_interrupt, IRQF_SHARED,
>> +                         KBUILD_MODNAME, trx);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "failed to request IRQ%d\n", 
>> pdev->irq);
>> +               goto err6;
>> +       }
>> +
>> +       dev->irq = pdev->irq;
>> +       err = dect_register_transceiver(trx);
>> +       if (err < 0)
>> +               goto err7;
>> +
>> +       return 0;
>> +
>> +err7:
>> +       free_irq(pdev->irq, trx);
>> +err6:
>> +       sc1442x_shutdown_device(dev);
>> +err5:
>> +       dect_transceiver_free(trx);
>> +err4:
>> +       iounmap(base);
>> +err3:
>> +       pci_release_regions(pdev);
>> +err2:
>> +       pci_disable_device(pdev);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static void coa_remove(struct pci_dev *pdev)
>> +{
>> +       struct dect_transceiver *trx = pci_get_drvdata(pdev);
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       u8 __iomem *sc1442x_base = dev->sc1442x_base;
>> +
>> +       sc1442x_shutdown_device(dev);
>> +       free_irq(pdev->irq, trx);
>> +       dect_unregister_transceiver(trx);
>> +       iounmap(sc1442x_base);
>> +       pci_release_regions(pdev);
>> +       pci_disable_device(pdev);
>> +}
>> +
>> +static int coa_suspend(struct pci_dev *pdev, pm_message_t state)
>> +{
>> +       struct dect_transceiver *trx = pci_get_drvdata(pdev);
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       sc1442x_shutdown_device(dev);
>> +       pci_save_state(pdev);
>> +       return 0;
>> +}
>> +
>> +static int coa_resume(struct pci_dev *pdev)
>> +{
>> +       struct dect_transceiver *trx = pci_get_drvdata(pdev);
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       pci_restore_state(pdev);
>> +       return sc1442x_init_device(dev);
>> +}
>> +
>> +static DEFINE_PCI_DEVICE_TABLE(coa_pci_tbl) = {
>> +       {PCI_DEVICE(PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_COA)},
>> +       {}
>> +};
>> +
>> +static struct pci_driver coa_driver = {
>> +       .name           = KBUILD_MODNAME,
>> +       .id_table       = coa_pci_tbl,
>> +       .probe          = coa_probe,
>> +       .remove         = coa_remove,
>> +       .suspend        = coa_suspend,
>> +       .resume         = coa_resume,
>> +};
>> +
>> +static int __init coa_pci_init(void)
>> +{
>> +       return pci_register_driver(&coa_driver);
>> +}
>> +
>> +static void __exit coa_pci_exit(void)
>> +{
>> +       pci_unregister_driver(&coa_driver);
>> +}
>> +
>> +module_init(coa_pci_init);
>> +module_exit(coa_pci_exit);
>> +
>> +MODULE_DESCRIPTION("Dosch&Amand COM-ON-AIR PCI driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_DEVICE_TABLE(pci, coa_pci_tbl);
>> diff --git a/target/linux/generic/files/drivers/dect/coa/dip_opcodes.h 
>> b/target/linux/generic/files/drivers/dect/coa/dip_opcodes.h
>> new file mode 100644
>> index 0000000..bd50056
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/dip_opcodes.h
>> @@ -0,0 +1,157 @@
>> +/*
>> + * com_on_air - basic driver for the Dosch and Amand "com on air" 
>> cards
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * authors:
>> + * (C) 2008  Andreas Schuler <krater at badterrorist dot com>
>> + * (C) 2008  Matthias Wenzel <dect at mazzoo dot de>
>> + *
>> + */
>> +
>> +#ifndef DIP_OPCODE_H
>> +#define DIP_OPCODE_H
>> +
>> +#define        BR              0x01
>> +#define        JMP             0x02
>> +#define        JMP1            0x03
>> +#define        RTN             0x04
>> +#define        BK_A1           0x05
>> +#define        WNTM1           0x06
>> +#define        WNTP1           0x07
>> +#define        WNT             0x08
>> +#define        WT              0x09
>> +#define        RFDIS           0x0a
>> +#define        RFEN            0x0b
>> +#define        LD_PTR          0x0c
>> +#define        SLOTZERO        0x0d
>> +#define        BK_A            0x0e
>> +#define        BK_C            0x0f
>> +
>> +
>> +#define        B_RST           0x20
>> +#define        B_ST2           0x21
>> +#define        B_XT            0x24
>> +#define        B_BT2           0x25
>> +#define        B_BTFU          0x25
>> +#define        B_XOFF          0x26
>> +#define        B_ON            0x27
>> +#define        B_XON           0x27
>> +#define        UNLCK           0x28
>> +#define        B_SR            0x29
>> +#define        B_XR            0x2b
>> +#define        EN_SL_ADJ       0x2c
>> +#define        B_BR2           0x2d
>> +#define        B_BRFU          0x2d
>> +#define        B_RINV          0x2e
>> +#define        B_RON           0x2f
>> +
>> +
>> +#define        B_ST            0x31
>> +#define        B_TX            0x31
>> +#define        B_AT            0x32
>> +#define        B_RC            0x33
>> +#define        B_BT            0x34
>> +#define        B_BTFP          0x35
>> +#define        B_BTP           0x35
>> +#define        B_AT2           0x37
>> +#define        B_WRS           0x39
>> +#define        B_AR            0x3a
>> +#define        B_BR            0x3c
>> +#define        B_BRP           0x3d
>> +#define        B_BRFP          0x3d
>> +#define        B_AR2           0x3f
>> +
>> +
>> +#define        D_RST           0x40
>> +#define        D_ON            0x42
>> +#define        D_OFF           0x43
>> +#define        D_PREP          0x44
>> +#define        WSC             0x48
>> +
>> +
>> +#define        D_LDK           0x50
>> +#define        D_LDS           0x57
>> +#define        D_WRS           0x5f
>> +
>> +
>> +#define        U_PSC           0x60
>> +#define        U_INT0          0x61
>> +#define        RCK_INT         0x62
>> +#define        RCK_EXT         0x63
>> +#define        B_WB_OFF        0x64
>> +#define        B_WB_ON         0x65
>> +#define        CLK1            0x66
>> +#define        CLK3            0x67
>> +#define        U_CK8           0x68
>> +#define        U_CK4           0x69
>> +#define        U_CK2           0x6a
>> +#define        U_INT1          0x6b
>> +#define        U_CK1           0x6c
>> +#define        U_INT2          0x6d
>> +#define        U_INT3          0x6f
>> +
>> +
>> +#define        A_RCV0          0x80
>> +#define        A_RCV36         0x82
>> +#define        A_RCV30         0x83
>> +#define        A_RCV24         0x84
>> +#define        A_RCV18         0x85
>> +#define        A_RCV12         0x86
>> +#define        A_RCV6          0x87
>> +#define        A_RCV33         0x8a
>> +#define        A_RCV27         0x8b
>> +#define        A_RCV21         0x8c
>> +#define        A_RCV15         0x8d
>> +#define        A_RCV9          0x8e
>> +#define        A_RCV3          0x8f
>> +
>> +
>> +#define        MEN3N           0xa2
>> +#define        MEN3            0xa3
>> +#define        MEN1N           0xa4
>> +#define        MEN1            0xa5
>> +#define        MEN2N           0xa6
>> +#define        MEN2            0xa7
>> +#define        M_RD            0xa8
>> +#define        M_RST           0xa9
>> +
>> +
>> +#define        M_WRS           0xb8
>> +#define        M_WR            0xb9
>> +
>> +
>> +#define        A_RST           0xc0
>> +#define        A_MUTE          0xc1
>> +#define        A_STOFF         0xc2
>> +#define        A_ALAW          0xc3
>> +#define        A_DT            0xc4
>> +#define        A_NORM          0xc5
>> +#define        A_LDR           0xc6
>> +#define        A_LDW           0xc7
>> +#define        A_LIN           0xc8
>> +#define        A_MTOFF         0xc9
>> +#define        A_MUTE1         0xca
>> +#define        A_MTOFF1        0xcb
>> +#define        A_STON          0xcc
>> +#define        A_DT1           0xcd
>> +#define        A_LDR1          0xce
>> +#define        A_LDW1          0xcf
>> +
>> +
>> +#define        A_STRN          0xe0
>> +#define        P_LD            0xe8
>> +#define        P_EN            0xe9
>> +#define        P_SC            0xea
>> +#define        A_RST1          0xeb
>> +#define        P_LDL           0xec
>> +#define        P_LDH           0xed
>> +#define        C_ON            0xee
>> +#define        C_OFF           0xef
>> +
>> +
>> +#define        C_LD            0xfa
>> +
>> +#endif
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/radio_lmx3161.c 
>> b/target/linux/generic/files/drivers/dect/coa/radio_lmx3161.c
>> new file mode 100644
>> index 0000000..9f6d5ae
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/radio_lmx3161.c
>> @@ -0,0 +1,84 @@
>> +/*
>> + * radio_lmx3161 - NSC LMX3161 Single Chip Radio Transceiver radio 
>> operations
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +#include "com_on_air.h"
>> +
>> +/* Intermediate frequency */
>> +#define RADIO_LMX3161_FREQ_IF  110592  /* kHz */
>> +
>> +/*
>> + * Control Bits
>> + */
>> +
>> +/* N-counter */
>> +#define RADIO_LMX3161_CTRL_N   0x0
>> +/* R-counter */
>> +#define RADIO_LMX3161_CTRL_R   0x2
>> +/* F-latch */
>> +#define RADIO_LMX3161_CTRL_F   0x1
>> +
>> +/*
>> + * Function Register (18 bit F-latch)
>> + */
>> +
>> +/* Prescaler modules select */
>> +#define RADIO_LMX3161_PRESCALER_32_33
>> +#define RADIO_LMX3161_PRESCALER_64_65
>> +/* Phase detector polarity: 0 = negative, 1 = positive */
>> +#define RADIO_LMX3161_PD               (1 << 3)
>> +/* Charge pump current gain select: 0 = LOW (1*I_cpo), 1 = high 
>> (4*I_cpo) */
>> +#define RADIO_LMX3161_CP               (1 << 4)
>> +/* tri-state charge pump output: 0 = normal, 1 = tri-state */
>> +#define RADIO_LMX3161_CP_TRISTATE      (1 << 5)
>> +/* Receive chain power down control: 0 = power up, 1 = power down */
>> +#define RADIO_LMX3161_RX_POWER         (1 << 7)
>> +/* Transmit chain power down control: 0 = power up, 1 = power down */
>> +#define RADIO_LMX3161_TX_POWER         (1 << 8)
>> +/* Out 0 CMOS output: 0 = low, 1 = high */
>> +#define RADIO_LMX3161_CMOS0A           (1 << 9)
>> +/* Out 1 CMOS output: 0 = low, 1 = high */
>> +#define RADIO_LMX3161_CMOS1            (1 << 10)
>> +/* Out 2 CMOS output: 0 = low, 1 = high */
>> +#define RADIO_LMX3161_CMOS2            (1 << 11)
>> +/* Power down mode select: */
>> +#define RADIO_LMX3161_POWER_DOWN_MASK          (0x3 << 12)
>> +#define RADIO_LMX3161_POWER_DOWN_SW            0
>> +#define RADIO_LMX3161_POWER_DOWN_HARDWIRE      (0x3 << 12)
>> +/* Demodulator gain select */
>> +/* Demodulator DC level shifting polarity */
>> +/* Demodulator DC level shift */
>> +
>> +static u64 lmx3161_map_band(struct coa_device *dev, const struct 
>> dect_band *band)
>> +{
>> +       struct coa_freq_map_entry *fe;
>> +       u32 frequency;
>> +       u8 carrier;
>> +
>> +       for (carrier = 0; carrier < band->carriers; carrier++) {
>> +               frequency = band->frequency[carrier];
>> +               fe = &dev->freq_map.carrier[carrier];
>> +       }
>> +       return 0;
>> +}
>> +
>> +const struct coa_radio_ops coa_lmx3161_radio_ops = {
>> +       .type           = "LMX3161",
>> +       .rx_init        = NULL,
>> +       .tx_init        = NULL,
>> +       .set_carrier    = NULL,
>> +       .map_band       = lmx3161_map_band,
>> +};
>> +EXPORT_SYMBOL_GPL(coa_lmx3161_radio_ops);
>> diff --git a/target/linux/generic/files/drivers/dect/coa/radio_u2785.c 
>> b/target/linux/generic/files/drivers/dect/coa/radio_u2785.c
>> new file mode 100644
>> index 0000000..dab53a0
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/radio_u2785.c
>> @@ -0,0 +1,261 @@
>> +/*
>> + * radio_u2785 - ATMEL U2785 RF IC radio operations
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +//#define DEBUG
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +#include "com_on_air.h"
>> +
>> +#define u2785_debug(dev, fmt, args...) \
>> +       dev_dbg(dev->dev, "u2785: " fmt, ## args)
>> +
>> +/* Intermediate frequencies */
>> +#define RADIO_U2785_FREQ_IF1   110592  /* kHz */
>> +#define RADIO_U2785_FREQ_IF2   112320  /* kHz */
>> +
>> +/*
>> + *  RC (Reference Divider)
>> + */
>> +#define RADIO_U2785_RC_SHIFT   22
>> +#define RADIO_U2785_RC_12      (0x1 << RADIO_U2785_RC_SHIFT)
>> +#define RADIO_U2785_RC_16      (0x2 << RADIO_U2785_RC_SHIFT)
>> +#define RADIO_U2785_RC_24      (0x3 << RADIO_U2785_RC_SHIFT)
>> +
>> +/*
>> + * SC (Swallow Counter) 0-31
>> + */
>> +#define RADIO_U2785_SC_SHIFT   17
>> +#define RADIO_U2785_SC_MAX     31
>> +#define RADIO_U2785_SC_MASK    (0x1F << RADIO_U2785_SC_SHIFT)
>> +
>> +/*
>> + *  MC (Main Divider)
>> + */
>> +#define RADIO_U2785_MC_SHIFT   15
>> +#define RADIO_U2785_MC_MIN     31
>> +#define RADIO_U2785_MC_MAX     34
>> +#define RADIO_U2785_MC_31      (0x0 << RADIO_U2785_MC_SHIFT)
>> +#define RADIO_U2785_MC_32      (0x1 << RADIO_U2785_MC_SHIFT)
>> +#define RADIO_U2785_MC_33      (0x2 << RADIO_U2785_MC_SHIFT)
>> +#define RADIO_U2785_MC_34      (0x3 << RADIO_U2785_MC_SHIFT)
>> +
>> +/*
>> + *  PS (Phase Settings)
>> + */
>> +
>> +/* Phase of GF_DATA */
>> +#define RADIO_U2785_PS_GF      (0x1 << 14)
>> +/* Phase of MCC Internal Connection */
>> +#define RADIO_U2785_PS_MCC     (0x1 << 13)
>> +/* Phase of Charge Pump */
>> +#define RADIO_U2785_PS_CP      (0x1 << 12)
>> +
>> +/*
>> + * Current-Saving Power-up/down Settings
>> + */
>> +
>> +/* Gaussian Filter */
>> +#define RADIO_U2785_GF         (0x1 << 11)
>> +/* Modulation Compensation Circuit */
>> +#define RADIO_U2785_MCC                (0x1 << 10)
>> +/* Frequency Doubler */
>> +#define RADIO_U2785_FD         (0x1 << 8)
>> +/* OP1 + OP2 (Op Amps) */
>> +#define RADIO_U2785_OP         (0x1 << 7)
>> +
>> +/*
>> + *  Current Gain Settings (in percent)
>> + */
>> +#define RADIO_U2785_CGS_60     0x0
>> +#define RADIO_U2785_CGS_70     0x1
>> +#define RADIO_U2785_CGS_80     0x2
>> +#define RADIO_U2785_CGS_90     0x3
>> +#define RADIO_U2785_CGS_100    0x4
>> +#define RADIO_U2785_CGS_110    0x5
>> +#define RADIO_U2785_CGS_120    0x6
>> +#define RADIO_U2785_CGS_130    0x7
>> +
>> +/* GFCS (Gaussian-Filter Current Settings) */
>> +#define RADIO_U2785_GFCS_SHIFT 7
>> +/* CPCS (Charge-Pump Current Settings) */
>> +#define RADIO_U2785_CPCS_SHIFT 1
>> +/* MCCS (Modulation-Compensation Current Settings) */
>> +#define RADIO_U2785_MCCS_SHIFT 4
>> +
>> +/*
>> + * Pretune DAC Voltage
>> + */
>> +#define RADIO_U2785_DAC_SHIFT  4
>> +#define RADIO_U2785_DAC_300mV  (0x0 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_600mV  (0x1 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_900mV  (0x2 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_1200mV (0x3 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_1400mV (0x4 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_1700mV (0x5 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_2000mV (0x6 << RADIO_U2785_DAC_SHIFT)
>> +#define RADIO_U2785_DAC_2300mV (0x7 << RADIO_U2785_DAC_SHIFT)
>> +
>> +/*
>> + * Address bit
>> + */
>> +#define RADIO_U2785_ADDRESS_BIT        0x1
>> +
>> +static void u2785_write_config(const struct coa_device *dev, u16 
>> offset,
>> +                              u32 init1, u32 init2)
>> +{
>> +       u8 init[5] = {
>> +               /* first word: 24 bits */
>> +               [0]     = init1 >> 16,
>> +               [1]     = init1 >> 8,
>> +               [2]     = init1 | RADIO_U2785_ADDRESS_BIT,
>> +               /* second word: 9 bits */
>> +               [3]     = init2 >> 1,
>> +               [4]     = 0,
>> +       };
>> +
>> +       sc1442x_rfdesc_write(dev, offset, init, sizeof(init));
>> +}
>> +
>> +static void u2785_rx_init(const struct coa_device *dev, u16 offset)
>> +{
>> +       u32 init1 = 0, init2 = 0;
>> +
>> +       init1 |= RADIO_U2785_RC_12;
>> +       init1 |= RADIO_U2785_MC_32;
>> +       init1 |= 10 << RADIO_U2785_SC_SHIFT;
>> +
>> +       init1 |= RADIO_U2785_CGS_100 << RADIO_U2785_CPCS_SHIFT;
>> +
>> +       init2 |= RADIO_U2785_FD;
>> +       init2 |= RADIO_U2785_CGS_100 << RADIO_U2785_MCCS_SHIFT;
>> +
>> +       u2785_write_config(dev, offset, init1, init2);
>> +}
>> +
>> +static void u2785_tx_init(const struct coa_device *dev, u16 offset)
>> +{
>> +       u32 init1 = 0, init2 = 0;
>> +
>> +       init1 |= RADIO_U2785_RC_12;
>> +       init1 |= RADIO_U2785_MC_34;
>> +       init1 |= 7 << RADIO_U2785_SC_SHIFT;
>> +
>> +       init1 |= RADIO_U2785_GF;
>> +       init1 |= RADIO_U2785_MCC;
>> +       init1 |= RADIO_U2785_CGS_120 << RADIO_U2785_GFCS_SHIFT;
>> +       init1 |= RADIO_U2785_DAC_1400mV;
>> +       init1 |= RADIO_U2785_CGS_60 << RADIO_U2785_CPCS_SHIFT;
>> +
>> +       init2 |= RADIO_U2785_FD;
>> +       init2 |= RADIO_U2785_CGS_130 << RADIO_U2785_MCCS_SHIFT;
>> +
>> +       u2785_write_config(dev, offset, init1, init2);
>> +}
>> +
>> +static void u2785_write_carrier(const struct coa_device *dev, u16 
>> offset,
>> +                               u32 init1)
>> +{
>> +       u8 init[3] = {
>> +               /* first word: 24 bits */
>> +               [0]     = init1 >> 16,
>> +               [1]     = init1 >> 8,
>> +               [2]     = init1 | RADIO_U2785_ADDRESS_BIT,
>> +       };
>> +
>> +       sc1442x_rfdesc_write(dev, offset, init, sizeof(init));
>> +}
>> +
>> +static void u2785_set_carrier(const struct coa_device *dev, u16 
>> offset,
>> +                             enum dect_slot_states mode, u8 carrier)
>> +{
>> +       const struct coa_freq_map_entry *fe = 
>> &dev->freq_map.carrier[carrier];
>> +       u32 init1 = 0;
>> +
>> +       init1 |= RADIO_U2785_RC_12;
>> +
>> +       switch (mode) {
>> +       case DECT_SLOT_SCANNING:
>> +       case DECT_SLOT_RX:
>> +               init1 |= (fe->rx.divisor - RADIO_U2785_MC_MIN) <<
>> +                        RADIO_U2785_MC_SHIFT;
>> +               init1 |= fe->rx.swcnt << RADIO_U2785_SC_SHIFT;
>> +
>> +               init1 |= RADIO_U2785_CGS_100 << 
>> RADIO_U2785_CPCS_SHIFT;
>> +               break;
>> +       case DECT_SLOT_TX:
>> +               init1 |= (fe->tx.divisor - RADIO_U2785_MC_MIN) <<
>> +                        RADIO_U2785_MC_SHIFT;
>> +               init1 |= fe->tx.swcnt << RADIO_U2785_SC_SHIFT;
>> +
>> +               init1 |= RADIO_U2785_GF;
>> +               init1 |= RADIO_U2785_MCC;
>> +               init1 |= RADIO_U2785_CGS_120 << 
>> RADIO_U2785_GFCS_SHIFT;
>> +               init1 |= RADIO_U2785_DAC_1400mV;
>> +               init1 |= RADIO_U2785_CGS_60 << RADIO_U2785_CPCS_SHIFT;
>> +               break;
>> +       default:
>> +               return;
>> +       }
>> +
>> +       u2785_write_carrier(dev, offset, init1);
>> +}
>> +
>> +static int u2785_map_freq(u32 frequency, u8 *s_mc, u8 *s_sc)
>> +{
>> +       frequency /= DECT_CARRIER_WIDTH;
>> +
>> +       *s_mc = frequency / 32;
>> +       if (*s_mc < RADIO_U2785_MC_MIN || *s_mc > RADIO_U2785_MC_MAX)
>> +               return false;
>> +       *s_sc = frequency % 32;
>> +       return true;
>> +}
>> +
>> +static u64 u2785_map_band(struct coa_device *dev, const struct 
>> dect_band *band)
>> +{
>> +       struct coa_freq_map_entry *fe;
>> +       u64 carriers = 0;
>> +       u32 frequency;
>> +       u8 carrier;
>> +
>> +       for (carrier = 0; carrier < band->carriers; carrier++) {
>> +               frequency = band->frequency[carrier];
>> +               fe = &dev->freq_map.carrier[carrier];
>> +
>> +               if (!u2785_map_freq(frequency - RADIO_U2785_FREQ_IF1,
>> +                                   &fe->rx.divisor, &fe->rx.swcnt))
>> +                       continue;
>> +               if (!u2785_map_freq(frequency,
>> +                                   &fe->tx.divisor, &fe->tx.swcnt))
>> +                       continue;
>> +
>> +               carriers |= 1 << carrier;
>> +               u2785_debug(dev, "carrier %u (%u.%03uMHz) => "
>> +                           "rx: div: %u sw: %u tx: div: %u sw: %u\n",
>> +                           carrier, frequency / 1000, frequency % 
>> 1000,
>> +                           fe->rx.divisor, fe->rx.swcnt,
>> +                           fe->tx.divisor, fe->tx.swcnt);
>> +       }
>> +
>> +       return carriers;
>> +}
>> +
>> +const struct coa_radio_ops coa_u2785_radio_ops = {
>> +       .type           = "U2785B",
>> +       .rx_init        = u2785_rx_init,
>> +       .tx_init        = u2785_tx_init,
>> +       .set_carrier    = u2785_set_carrier,
>> +       .map_band       = u2785_map_band,
>> +};
>> +EXPORT_SYMBOL_GPL(coa_u2785_radio_ops);
>> diff --git a/target/linux/generic/files/drivers/dect/coa/sc1442x.c 
>> b/target/linux/generic/files/drivers/dect/coa/sc1442x.c
>> new file mode 100644
>> index 0000000..b5458cd
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/sc1442x.c
>> @@ -0,0 +1,1020 @@
>> +/*
>> + * com_on_air - basic driver for the Dosch and Amand "com on air" 
>> cards
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * authors:
>> + * (C) 2008  Andreas Schuler <krater at badterrorist dot com>
>> + * (C) 2008  Matthias Wenzel <dect at mazzoo dot de>
>> + * (C) 2009  Patrick McHardy <kaber at trash.net>
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_csf.h>
>> +#include <net/dect/dsc.h>
>> +#include <net/dect/transceiver.h>
>> +#include <asm/io.h>
>> +
>> +#include "com_on_air.h"
>> +#include "sc1442x_firmware.h"
>> +#include "dip_opcodes.h"
>> +
>> +/*
>> + * The sc1442x contain a 2k data RAM and 512b code RAM. The two 
>> primary
>> + * methods for memory access are direct and indirect access. In 
>> indirect
>> + * mode, the access goes through the DIP and the memory bank needs to 
>> be
>> + * mapped by writting its number to the control register. In direct 
>> mode
>> + * the memory can be accessed directly, the three modes differ only 
>> in
>> + * the address space layout. The choice between direct and indirect 
>> mode
>> + * is made by the device vendor.
>> + *
>> + * The address space is layed out as follows:
>> + *
>> + * PCI - size 8k:
>> + *
>> + * 0x0a00 - 0x11ff:    data memory
>> + * 0x1a00 - 0x1bff:    code memory
>> + * 0x1f00 - 0x1fff:    DIP control and status registers
>> + *
>> + * PCMCIA - size 1k:
>> + *
>> + * 0x0000 - 0x01ff:    256 bytes memory
>> + * 0x0200 - 0x02ff:    DIP control and status registers
>> + *
>> + * Memory of the PCMCIA device is addressed in 16 bit little endian 
>> quantities.
>> + *
>> + * The first bank of the data memory contains DIP specific control 
>> data,
>> + * the remaining banks are used to store packet and slot 
>> configuration data,
>> + * with each slot having one half memory bank assigned.
>> + *
>> + * The per slot data of 128 bytes is layed out as follows:
>> + *
>> + * Offset              RX              TX
>> + *
>> + * 0x00 - 0x05:                Status          Preamble
>> + * 0x06 - 0x0d:                A-Field         A-Field
>> + * 0x0e - 0x35:                B-Field         B-Field
>> + *
>> + * 0x65 - 0x68:                Radio Cfg       Radio Cfg
>> + * 0x69 - 0x6f:                BMC Ctrl        BMC Ctrl
>> + * 0x70 - 0x7f:                DCS IV/Key      DCS IV/Key
>> + * 0x70 - 0x7a:                DCS state       DCS state
>> + */
>> +
>> +#define SC1442X_DIPSTOPPED             0x80
>> +#define SC1442X_PRESCALER_ENABLED      0x40
>> +#define SC1442X_TIMER_INTERRUPT_ENABLED        0x02
>> +
>> +/* Memory access modes */
>> +#define SC1442X_LINEAR_MODE            0x01
>> +#define SC1442X_LINEAR_MODE_0          (SC14421_LINEAR_MODE | 0x0)
>> +#define SC1442X_LINEAR_MODE_1          (SC14421_LINEAR_MODE | 0x2)
>> +#define SC1442X_LINEAR_MODE_2          (SC14421_LINEAR_MODE | 0x3)
>> +
>> +/* Indirect mode RAM bank select */
>> +#define SC1442X_RAMBANK0               0x00
>> +#define SC1442X_RAMBANK1               0x04
>> +#define SC1442X_RAMBANK2               0x08
>> +#define SC1442X_RAMBANK3               0x0c
>> +#define SC1442X_RAMBANK4               0x10
>> +#define SC1442X_RAMBANK5               0x14
>> +#define SC1442X_RAMBANK6               0x18
>> +#define SC1442X_RAMBANK7               0x1c
>> +#define SC1442X_CODEBANK               0x20
>> +#define SC1442X_BANKSIZE               0x100
>> +
>> +/* Interrupts 0-3 */
>> +#define SC1442X_IRQ_SLOT_0_5           0x01
>> +#define SC1442X_IRQ_SLOT_6_11          0x02
>> +#define SC1442X_IRQ_SLOT_12_17         0x04
>> +#define SC1442X_IRQ_SLOT_18_23         0x08
>> +#define SC1442X_IRQ_TIMER              0x10
>> +#define SC1442X_IRQ_MASK               0x1f
>> +
>> +/* Interrupt status 1: DIP/CLK100/TIM1/TIM0/SPI/UART/P10/KEYB */
>> +#define SC14424_RESET_INT_PENDING_1    0x1f02
>> +/* Interrupt status 2: CLK8K/TONE */
>> +#define SC14424_RESET_INT_PENDING_2    0x1f03
>> +
>> +/* DIP_INT and CLK100_INT priority level */
>> +#define SC14424_INT_PRIORITY_1         0x1f06
>> +
>> +/* P1 output control */
>> +#define SC14424_P1_SET_OUTPUT_DATA     0x1f21
>> +#define SC14424_P1_RESET_OUTPUT_DATA   0x1f22
>> +
>> +/* P1 input/output direction */
>> +#define SC14424_P1_DIR_REG             0x1f23
>> +
>> +/*
>> + * Burst Mode Controller control information
>> + */
>> +
>> +/* Maximum number of unmasked errors in S-field bits 8 to 31 */
>> +#define SC1442X_BC0_S_ERR_SHIFT                4
>> +/* Invert incoming data (RDI) */
>> +#define SC1442X_BC0_INV_RDI            0x08
>> +/* Invert outgoing data (TDO) */
>> +#define SC1442X_BC0_INV_TDO            0x04
>> +/* Disable writing B-field on A-field CRC error */
>> +#define SC1442X_BC0_SENS_A             0x02
>> +/* PP/FP mode */
>> +#define SC1442X_BC0_PP_MODE            0x01
>> +
>> +/* Error test mask for S-field bits 15-8 */
>> +#define SC1442X_BC1_MASK_MASK          0xff
>> +
>> +/* Sliding error test mask for S-field bits 15-8 */
>> +#define SC1442X_BC2_SLIDE_MASK         0xff
>> +
>> +/* DAC output value when BCM is active (for frequency control?) */
>> +#define SC1442X_BC3_DAC_MASK           0x1f
>> +
>> +/* Only perform phase jump for correct A-field CRC + SL_EN_ADJ 
>> command */
>> +#define SC1442X_BC4_ADP                        0x10
>> +/* Window in which S-field is accepted */
>> +#define SC1442X_BC4_WIN_MASK           0x0f
>> +
>> +/* Amplitude-trimming of gaussian shape */
>> +#define SC1442X_BC5_VOL_SHIFT          4
>> +/* Disable scrambling */
>> +#define SC1442X_BC5_SC_OFF             0x08
>> +/* PD1 synchronization pattern:
>> + * 0 = S-field received, 1 = preamble + first 2 bits of 
>> synchronization word */
>> +#define SC1442X_BC5_DO_FR              0x04
>> +/* TDO output shape */
>> +#define SC1442X_BC5_TDO_DIGITAL                0x00
>> +#define SC1442X_BC5_TDO_GAUSIAN                0x01
>> +#define SC1442X_BC5_TDO_POWER_DOWN     0x02
>> +#define SC1442X_BC5_TDO_MID_LEVEL      0x03
>> +
>> +/* Low 4 bits of multiframe number */
>> +#define SC1442X_BC6_MFR_SHIFT          4
>> +#define SC1442X_BC6_MFR_MASK           0xf0
>> +/* Frame number */
>> +#define SC1442X_BC6_FR_MASK            0x0f
>> +
>> +/*
>> + * Burst Mode Controller status information
>> + */
>> +
>> +/* Peak binary value of ADC (RSSI) */
>> +#define SC1442X_ST0_ADC_MASK           0x3f
>> +
>> +/* S-pattern recognized according to BMC configuration */
>> +#define SC1442X_ST1_IN_SYNC            0x80
>> +
>> +/* A-field R-CRC correct */
>> +#define SC1442X_ST1_A_CRC              0x40
>> +
>> +/* Protected Bn-subfield R-CRC correct */
>> +#define SC1442X_ST1_B_CRC_MASK         0x3c
>> +#define SC1442X_ST1_B1_CRC             0x20
>> +#define SC1442X_ST1_B2_CRC             0x10
>> +#define SC1442X_ST1_B3_CRC             0x08
>> +#define SC1442X_ST1_B4_CRC             0x04
>> +
>> +/* B-field X-CRC correct */
>> +#define SC1442X_ST1_X_CRC              0x02
>> +
>> +/* Z-field equals X-CRC */
>> +#define SC1442X_ST1_Z_CRC              0x01
>> +
>> +/* Phase offset of received S-field: which of the nine internal clock 
>> cycles
>> + * per symbol sampled the incoming data. The frequency deviation can 
>> be
>> + * calculated from the difference of the offsets of two consequitive 
>> frames as:
>> + *
>> + * K * (T / 9) / 10m = K * 96ns / 10m = K * 9.6ppm
>> + */
>> +#define SC1442X_ST2_TAP_SHIFT          4
>> +#define SC1442X_ST2_TAP_MASK           0xf0
>> +#define SC1442X_ST2_TAP_SCALE          (DECT_PHASE_OFFSET_SCALE * 96 
>> / 10)
>> +
>> +/* Number of unmasked S-field errors according to BMC configuration 
>> */
>> +#define SC1442X_ST2_S_ERR_SHIFT                0
>> +#define SC1442X_ST2_S_ERR_MASK         0x0f
>> +
>> +/* Phase offset of received S-field: difference of number of symbol 
>> periods
>> + * between nominal 11520 symbols per frame and actual number of 
>> symbols. The
>> + * frequency deviation can be calculated from the difference of two
>> + * consequitive frames as:
>> + *
>> + * N * T / 10m = N * 870ns / 10m = N * 87ppm
>> + */
>> +#define SC1442X_ST3_PHASE_MASK         0xff
>> +#define SC1442X_ST3_PHASE_SCALE                
>> (DECT_PHASE_OFFSET_SCALE * 87)
>> +
>> +/* DC offset of received data to comparator reference input (DAC) */
>> +#define SC1442X_ST4_DC_MASK            0x3f
>> +
>> +/*
>> + * Codec configuration
>> + */
>> +
>> +#define SC1442X_CC_SIZE                        6
>> +
>> +#define SC1442X_CC0_STANDBY            0xc2
>> +#define SC1442X_CC0_POWERDOWN          0x3d
>> +
>> +/* Logical memory banks */
>> +#define SC1442X_BANK_UNITS             8
>> +#define SC1442X_SLOT_BANK_SIZE         128
>> +
>> +static const u8 banktable[] = {
>> +       SC1442X_RAMBANK1,
>> +       SC1442X_RAMBANK2,
>> +       SC1442X_RAMBANK3,
>> +       SC1442X_RAMBANK4,
>> +       SC1442X_RAMBANK5,
>> +       SC1442X_RAMBANK6,
>> +};
>> +
>> +static const u8 slottable[] = {
>> +       Slot00, Slot01, Slot02, Slot03, Slot04, Slot05, Slot06, 
>> Slot07,
>> +       Slot08, Slot09, Slot10, Slot11, Slot12, Slot13, Slot14, 
>> Slot15,
>> +       Slot16, Slot17, Slot18, Slot19, Slot20, Slot21, Slot22, 
>> Slot23,
>> +};
>> +
>> +static const u8 sc1442x_rx_funcs[DECT_PACKET_MAX + 1][DECT_B_MAX + 
>> 1][2][2] = {
>> +       [DECT_PACKET_P00][DECT_B_NONE][0][0]            = RX_P00,
>> +       [DECT_PACKET_P00][DECT_B_NONE][0][1]            = RX_P00_Sync,
>> +       [DECT_PACKET_P32][DECT_B_UNPROTECTED][0][0]     = RX_P32U,
>> +       [DECT_PACKET_P32][DECT_B_UNPROTECTED][1][0]     = RX_P32U_Enc,
>> +};
>> +
>> +static const u8 sc1442x_tx_funcs[DECT_PACKET_MAX + 1][DECT_B_MAX + 
>> 1][2] = {
>> +       [DECT_PACKET_P00][DECT_B_NONE][0]               = TX_P00,
>> +       [DECT_PACKET_P32][DECT_B_UNPROTECTED][0]        = TX_P32U,
>> +       [DECT_PACKET_P32][DECT_B_UNPROTECTED][1]        = TX_P32U_Enc,
>> +};
>> +
>> +/*
>> + * Raw IO functions
>> + */
>> +
>> +static void sc1442x_lock_mem(struct coa_device *dev) 
>> __acquires(dev->lock)
>> +{
>> +       spin_lock_irq(&dev->lock);
>> +}
>> +
>> +static void sc1442x_unlock_mem(struct coa_device *dev) 
>> __releases(dev->lock)
>> +{
>> +       mmiowb();
>> +       spin_unlock_irq(&dev->lock);
>> +}
>> +
>> +static u8 sc1442x_readb(const struct coa_device *dev, u16 offset)
>> +{
>> +       switch (dev->type) {
>> +       case COA_TYPE_PCI:
>> +               return readb(dev->sc1442x_base + offset);
>> +       case COA_TYPE_PCMCIA:
>> +               return le16_to_cpu(readw(dev->sc1442x_base + 2 * 
>> offset));
>> +       default:
>> +               BUG();
>> +       }
>> +}
>> +
>> +static u16 sc1442x_readw(const struct coa_device *dev, u16 offset)
>> +{
>> +       u32 tmp;
>> +
>> +       switch (dev->type) {
>> +       case COA_TYPE_PCI:
>> +               return le16_to_cpu(readw(dev->sc1442x_base + offset));
>> +       case COA_TYPE_PCMCIA:
>> +               tmp = le32_to_cpu(readl(dev->sc1442x_base + 2 * 
>> offset));
>> +               return (tmp >> 8) | (tmp & 0xff);
>> +       default:
>> +               BUG();
>> +       }
>> +}
>> +
>> +static void sc1442x_writeb(const struct coa_device *dev, u16 offset, 
>> u8 value)
>> +{
>> +       switch (dev->type) {
>> +       case COA_TYPE_PCI:
>> +               writeb(value, dev->sc1442x_base + offset);
>> +               break;
>> +       case COA_TYPE_PCMCIA:
>> +               writew(cpu_to_le16(value), dev->sc1442x_base + 2 * 
>> offset);
>> +               break;
>> +       }
>> +}
>> +
>> +static void sc1442x_writew(const struct coa_device *dev, u16 offset, 
>> u16 value)
>> +{
>> +       u32 tmp;
>> +
>> +       switch (dev->type) {
>> +       case COA_TYPE_PCI:
>> +               writew(cpu_to_le16(value), dev->sc1442x_base + 
>> offset);
>> +               break;
>> +       case COA_TYPE_PCMCIA:
>> +               tmp = ((value & 0xff00) << 8) | (value & 0xff);
>> +               writel(cpu_to_le32(tmp), dev->sc1442x_base + 2 * 
>> offset);
>> +               break;
>> +       }
>> +}
>> +
>> +static void sc1442x_stop_dip(struct coa_device *dev)
>> +{
>> +       /* Prevent the interrupt handler from restarting the DIP */
>> +       dev->ctrl = SC1442X_DIPSTOPPED;
>> +
>> +       /* Stop the DIP and wait for interrupt handler to complete */
>> +       sc1442x_writeb(dev, dev->cfg_reg, SC1442X_DIPSTOPPED);
>> +       synchronize_irq(dev->irq);
>> +}
>> +
>> +static void sc1442x_start_dip(struct coa_device *dev)
>> +{
>> +       dev->ctrl = 0;
>> +       sc1442x_writeb(dev, dev->cfg_reg, 0x00);
>> +}
>> +
>> +static void sc1442x_switch_to_bank(const struct coa_device *dev, u8 
>> bank)
>> +{
>> +       if (dev->type != COA_TYPE_PCMCIA)
>> +               return;
>> +       sc1442x_writeb(dev, dev->cfg_reg, bank | dev->ctrl);
>> +       /* need to wait for 4 IO cycles */
>> +       inb_p(dev->config_base);
>> +       inb_p(dev->config_base);
>> +       inb_p(dev->config_base);
>> +       inb_p(dev->config_base);
>> +}
>> +
>> +static void sc1442x_toggle_led(struct coa_device *dev)
>> +{
>> +       if (dev->type != COA_TYPE_PCI)
>> +               return;
>> +
>> +       if ((dev->led & 0xf) > 0x7)
>> +               sc1442x_writeb(dev, SC14424_P1_SET_OUTPUT_DATA, 0x40);
>> +       else
>> +               sc1442x_writeb(dev, SC14424_P1_RESET_OUTPUT_DATA, 
>> 0x40);
>> +       dev->led++;
>> +}
>> +
>> +/*
>> + * Code memory IO functions
>> + */
>> +static void sc1442x_write_cmd(const struct coa_device *dev, u16 
>> label,
>> +                             u8 opcode, u8 operand)
>> +{
>> +       sc1442x_writew(dev, dev->code_base + 2 * label, operand << 8 | 
>> opcode);
>> +}
>> +
>> +static void sc1442x_to_cmem(const struct coa_device *dev,
>> +                           const u8 *src, u16 length)
>> +{
>> +       u16 i;
>> +
>> +       for (i = 0; i < length; i++)
>> +               sc1442x_writeb(dev, dev->code_base + i, src[i]);
>> +}
>> +
>> +/*
>> + * Data memory IO functions
>> + */
>> +static inline u8 sc1442x_dreadb(const struct coa_device *dev, u16 
>> offset)
>> +{
>> +       return sc1442x_readb(dev, dev->data_base + (offset & 
>> dev->data_mask));
>> +}
>> +
>> +static inline u16 sc1442x_dreadw(const struct coa_device *dev, u16 
>> offset)
>> +{
>> +       return sc1442x_readw(dev, dev->data_base + (offset & 
>> dev->data_mask));
>> +}
>> +
>> +static inline void sc1442x_dwriteb(const struct coa_device *dev,
>> +                                 u16 offset, u8 value)
>> +{
>> +       sc1442x_writeb(dev, dev->data_base + (offset & 
>> dev->data_mask), value);
>> +}
>> +
>> +static inline void sc1442x_dwritew(const struct coa_device *dev,
>> +                                  u16 offset, u16 value)
>> +{
>> +       sc1442x_writew(dev, dev->data_base + (offset & 
>> dev->data_mask), value);
>> +}
>> +
>> +static void sc1442x_to_dmem(const struct coa_device *dev, u16 offset,
>> +                           const void *src, u16 length)
>> +{
>> +       u16 i = 0;
>> +
>> +       for (; length >= 2; length -= 2, i += 2)
>> +               sc1442x_dwritew(dev, offset + i, *(u16 *)(src + i));
>> +       for (; length >= 1; length -= 1, i += 1)
>> +               sc1442x_dwriteb(dev, offset + i, *(u8 *)(src + i));
>> +}
>> +
>> +static void sc1442x_from_dmem(const struct coa_device *dev, void 
>> *dst,
>> +                             u16 offset, u16 length)
>> +{
>> +       u16 i = 0;
>> +
>> +       for (; length >= 2; length -= 2, i += 2)
>> +               *(u16 *)(dst +  i) = sc1442x_dreadw(dev, offset + i);
>> +       for (; length >= 1; length -= 1, i += 1)
>> +               *(u8 *)(dst + i) = sc1442x_dreadb(dev, offset + i);
>> +}
>> +
>> +static u8 sc1442x_dip_bankaddress(u8 slot)
>> +{
>> +       return (slot / 2 + 2) * SC1442X_SLOT_BANK_SIZE / 
>> SC1442X_BANK_UNITS;
>> +}
>> +
>> +static u8 sc1442x_slot_bank(u8 slot)
>> +{
>> +       return banktable[slot / 4];
>> +}
>> +
>> +static u16 sc1442x_slot_offset(u8 slot)
>> +{
>> +       u16 offset;
>> +
>> +       offset = SC1442X_BANKSIZE + slot / 4 * SC1442X_BANKSIZE;
>> +       if (slot & 0x2)
>> +               offset += SC1442X_BANKSIZE / 2;
>> +       return offset;
>> +}
>> +
>> +void sc1442x_rfdesc_write(const struct coa_device *dev, u16 offset,
>> +                         const u8 *src, u16 length)
>> +{
>> +       sc1442x_to_dmem(dev, offset + RF_DESC, src, length);
>> +}
>> +
>> +/*
>> + * Ciphering
>> + */
>> +
>> +static void sc1442x_dcs_init(const struct coa_device *dev,
>> +                            const struct dect_transceiver *trx,
>> +                            u8 slot, u32 mfn, u8 framenum)
>> +{
>> +       const struct dect_transceiver_slot *ts = &trx->slots[slot];
>> +       u16 off = sc1442x_slot_offset(slot);
>> +       __le64 iv;
>> +
>> +       iv = dect_dsc_iv(mfn, framenum);
>> +       sc1442x_to_dmem(dev, off + DCS_IV, &iv, 8);
>> +       sc1442x_to_dmem(dev, off + DCS_CK, &ts->ck, 8);
>> +}
>> +
>> +/* Transfer DCS cipher state between two TDD slots of a MAC 
>> connection */
>> +static void sc1442x_transfer_dcs_state(struct coa_device *dev,
>> +                                      struct dect_transceiver *trx,
>> +                                      u8 slot)
>> +{
>> +       u8 slot2 = slot + DECT_HALF_FRAME_SIZE;
>> +       struct dect_transceiver_slot *ts1 = &trx->slots[slot];
>> +       struct dect_transceiver_slot *ts2 = &trx->slots[slot2];
>> +       u8 dcs_state[DCS_STATE_SIZE];
>> +       u16 off;
>> +
>> +       if (!(ts1->flags & DECT_SLOT_CIPHER) ||
>> +           !(ts2->flags & DECT_SLOT_CIPHER))
>> +               return;
>> +
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +       off = sc1442x_slot_offset(slot);
>> +       sc1442x_from_dmem(dev, dcs_state, off + DCS_STATE, 
>> DCS_STATE_SIZE);
>> +
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot2));
>> +       off = sc1442x_slot_offset(slot2);
>> +       sc1442x_to_dmem(dev, off + DCS_STATE, dcs_state, 
>> DCS_STATE_SIZE);
>> +}
>> +
>> +/*
>> + * Transceiver operations
>> + */
>> +
>> +static void sc1442x_disable(const struct dect_transceiver *trx)
>> +{
>> +       sc1442x_stop_dip(dect_transceiver_priv(trx));
>> +}
>> +
>> +static void sc1442x_enable(const struct dect_transceiver *trx)
>> +{
>> +       const struct coa_device *dev = dect_transceiver_priv(trx);
>> +       u8 slot;
>> +
>> +       /* Restore slot table to a pristine state */
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +       for (slot = 0; slot < DECT_FRAME_SIZE; slot++) {
>> +               sc1442x_write_cmd(dev, slottable[slot] + 0, WT, 1);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 1, WNT, 1);
>> +       }
>> +
>> +       if (trx->cell->mode == DECT_MODE_FP) {
>> +               sc1442x_write_cmd(dev, ClockSyncOn, WT, 1);
>> +               sc1442x_write_cmd(dev, ClockAdjust, WT, 1);
>> +               sc1442x_write_cmd(dev, ClockSyncOff, WT, 1);
>> +
>> +               sc1442x_write_cmd(dev, TX_P32U_Enc, JMP, LoadEncKey);
>> +               sc1442x_write_cmd(dev, RX_P32U_Enc, JMP, 
>> LoadEncState);
>> +       } else {
>> +               sc1442x_write_cmd(dev, ClockSyncOn, P_SC, 
>> PSC_S_SYNC_ON);
>> +               sc1442x_write_cmd(dev, ClockAdjust, EN_SL_ADJ, 1);
>> +               sc1442x_write_cmd(dev, ClockSyncOff, P_SC, 0x00);
>> +
>> +               sc1442x_write_cmd(dev, RX_P32U_Enc, JMP, LoadEncKey);
>> +               sc1442x_write_cmd(dev, TX_P32U_Enc, JMP, 
>> LoadEncState);
>> +       }
>> +
>> +       if (trx->mode == DECT_TRANSCEIVER_MASTER)
>> +               sc1442x_write_cmd(dev, RFStart, BR, SlotTable);
>> +       else {
>> +               sc1442x_write_cmd(dev, RFStart, BR, SyncInit);
>> +               sc1442x_write_cmd(dev, SyncLoop, BR, Sync);
>> +       }
>> +
>> +       sc1442x_start_dip(dect_transceiver_priv(trx));
>> +}
>> +
>> +static void sc1442x_confirm(const struct dect_transceiver *trx)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       /*
>> +        * This locks the firmware into a cycle where it will receive 
>> every
>> +        * 24th slot. This must happen within the time it takes to 
>> transmit
>> +        * 22 slots after the interrupt to lock to the correct signal.
>> +        */
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +       sc1442x_write_cmd(dev, SyncLoop, BR, SyncLock);
>> +       sc1442x_unlock_mem(dev);
>> +}
>> +
>> +static void sc1442x_unlock(const struct dect_transceiver *trx)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       /* Restore jump into Sync loop */
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +       sc1442x_write_cmd(dev, SyncLoop, BR, Sync);
>> +       sc1442x_write_cmd(dev, SlotTable, BR, SyncInit);
>> +       sc1442x_unlock_mem(dev);
>> +}
>> +
>> +static void sc1442x_lock(const struct dect_transceiver *trx, u8 slot)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       /*
>> +        * We're receiving the single slot "slot". Adjust the firmware 
>> so it
>> +        * will jump into the correct slottable position on the next 
>> receive
>> +        * event. This will automagically establish the correct slot 
>> numbers
>> +        * and thereby interrupt timing for all slots.
>> +        */
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +       sc1442x_write_cmd(dev, SlotTable, SLOTZERO, 0);
>> +       sc1442x_write_cmd(dev, SyncLoop, BR, slottable[slot]);
>> +       sc1442x_unlock_mem(dev);
>> +}
>> +
>> +static void sc1442x_write_bmc_config(const struct coa_device *dev,
>> +                                    u8 slot, bool tx)
>> +{
>> +       u16 off;
>> +       u8 cfg;
>> +
>> +       off = sc1442x_slot_offset(slot) + BMC_CTRL;
>> +
>> +       cfg  = 2 << SC1442X_BC0_S_ERR_SHIFT;
>> +       cfg |= SC1442X_BC0_INV_TDO;
>> +       cfg |= SC1442X_BC0_SENS_A;
>> +       if (slot < 12 && !tx)
>> +               cfg |= SC1442X_BC0_PP_MODE;
>> +       sc1442x_dwriteb(dev, off + 0, cfg);
>> +
>> +       /* S-field error mask */
>> +       sc1442x_dwriteb(dev, off + 1, 0);
>> +       /* S-field sliding window error mask */
>> +       sc1442x_dwriteb(dev, off + 2, 0x3f);
>> +
>> +       /* DAC output */
>> +       sc1442x_dwriteb(dev, off + 3, 0);
>> +
>> +       cfg  = SC1442X_BC4_ADP;
>> +       cfg |= 0xf & SC1442X_BC4_WIN_MASK;
>> +       cfg |= 0x80;
>> +       sc1442x_dwriteb(dev, off + 4, cfg);
>> +
>> +       cfg  = SC1442X_BC5_DO_FR;
>> +       cfg |= tx ? SC1442X_BC5_TDO_DIGITAL : 
>> SC1442X_BC5_TDO_POWER_DOWN;
>> +       sc1442x_dwriteb(dev, off + 5, cfg);
>> +
>> +       /* Frame number */
>> +       sc1442x_dwriteb(dev, off + 6, 0);
>> +}
>> +
>> +static void sc1442x_set_mode(const struct dect_transceiver *trx,
>> +                            const struct dect_channel_desc *chd,
>> +                            enum dect_slot_states mode)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       bool cipher = trx->slots[chd->slot].flags & DECT_SLOT_CIPHER;
>> +       bool sync = trx->slots[chd->slot].flags & DECT_SLOT_SYNC;
>> +       u8 slot = chd->slot, prev = dect_slot_sub(slot, 1);
>> +
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +
>> +       switch (mode) {
>> +       case DECT_SLOT_IDLE:
>> +               sc1442x_write_cmd(dev, slottable[prev] + 0, WT, 1);
>> +               sc1442x_write_cmd(dev, slottable[prev] + 1, WNT, 1);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 0, WT, 1);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 1, WNT, 1);
>> +               break;
>> +       case DECT_SLOT_SCANNING:
>> +       case DECT_SLOT_RX:
>> +               sc1442x_write_cmd(dev, slottable[prev] + 0, BK_C,
>> +                                 sc1442x_dip_bankaddress(slot));
>> +               sc1442x_write_cmd(dev, slottable[prev] + 1, JMP, 
>> RFInit);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 0, WT, 1);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 1, JMP,
>> +                                 
>> sc1442x_rx_funcs[chd->pkt][chd->b_fmt][cipher][sync]);
>> +
>> +               sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +               sc1442x_write_bmc_config(dev, slot, false);
>> +               break;
>> +       case DECT_SLOT_TX:
>> +               sc1442x_write_cmd(dev, slottable[prev] + 0, BK_C,
>> +                                 sc1442x_dip_bankaddress(slot));
>> +               sc1442x_write_cmd(dev, slottable[prev] + 1, JMP, 
>> RFInit);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 0, WT, 1);
>> +               sc1442x_write_cmd(dev, slottable[slot] + 1, JMP,
>> +                                 
>> sc1442x_tx_funcs[chd->pkt][chd->b_fmt][cipher]);
>> +
>> +               sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +               sc1442x_write_bmc_config(dev, slot, true);
>> +               break;
>> +       }
>> +       sc1442x_unlock_mem(dev);
>> +}
>> +
>> +static void sc1442x_set_carrier(const struct dect_transceiver *trx,
>> +                               u8 slot, u8 carrier)
>> +{
>> +       const struct dect_transceiver_slot *ts = &trx->slots[slot];
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       u16 off;
>> +
>> +       WARN_ON(ts->state == DECT_SLOT_IDLE);
>> +
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +       off = sc1442x_slot_offset(slot);
>> +       dev->radio_ops->set_carrier(dev, off, ts->state, carrier);
>> +       sc1442x_unlock_mem(dev);
>> +}
>> +
>> +static u64 sc1442x_set_band(const struct dect_transceiver *trx,
>> +                           const struct dect_band *band)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +
>> +       return dev->radio_ops->map_band(dev, band);
>> +}
>> +
>> +static void sc1442x_tx(const struct dect_transceiver *trx, struct 
>> sk_buff *skb)
>> +{
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       const struct dect_skb_trx_cb *cb = DECT_TRX_CB(skb);
>> +       const struct dect_transceiver_slot *ts = 
>> &trx->slots[cb->slot];
>> +       u8 slot = cb->slot;
>> +       u16 off;
>> +
>> +       sc1442x_lock_mem(dev);
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +       off = sc1442x_slot_offset(slot);
>> +
>> +       /* Duplicate first byte for transmission during ramp-up */
>> +       sc1442x_dwriteb(dev, off + SD_PREAMBLE_OFF - 1, 
>> *skb_mac_header(skb));
>> +       sc1442x_to_dmem(dev, off + SD_PREAMBLE_OFF,
>> +                       skb_mac_header(skb), skb->mac_len);
>> +       sc1442x_to_dmem(dev, off + SD_DATA_OFF, skb->data, skb->len);
>> +       sc1442x_dwriteb(dev, off + BMC_CTRL + BMC_CTRL_MFR_OFF, 
>> cb->frame);
>> +
>> +       /* Init DCS for slots in the first half frame */
>> +       if (ts->flags & DECT_SLOT_CIPHER && slot < 
>> DECT_HALF_FRAME_SIZE)
>> +               sc1442x_dcs_init(dev, trx, slot, cb->mfn, cb->frame);
>> +
>> +       sc1442x_toggle_led(dev);
>> +       sc1442x_unlock_mem(dev);
>> +       kfree_skb(skb);
>> +}
>> +
>> +const struct dect_transceiver_ops sc1442x_transceiver_ops = {
>> +       .name                   = "sc1442x",
>> +       .features               = DECT_TRANSCEIVER_SLOW_HOPPING,
>> +       .eventrate              = 6,
>> +       .latency                = 6,
>> +       .disable                = sc1442x_disable,
>> +       .enable                 = sc1442x_enable,
>> +       .confirm                = sc1442x_confirm,
>> +       .unlock                 = sc1442x_unlock,
>> +       .lock                   = sc1442x_lock,
>> +       .set_mode               = sc1442x_set_mode,
>> +       .set_carrier            = sc1442x_set_carrier,
>> +       .set_band               = sc1442x_set_band,
>> +       .tx                     = sc1442x_tx,
>> +       .destructor             = dect_transceiver_free,
>> +};
>> +EXPORT_SYMBOL_GPL(sc1442x_transceiver_ops);
>> +
>> +static u8 sc1442x_clear_interrupt(const struct coa_device *dev)
>> +{
>> +       u8 int1, int2, cnt = 0;
>> +
>> +       int1 = sc1442x_readb(dev, dev->cfg_reg);
>> +       /* is the card still plugged? */
>> +       if (int1 == 0xff)
>> +               return 0;
>> +
>> +       int2 = int1 & SC1442X_IRQ_MASK;
>> +
>> +       /* Clear interrupt status before checking for any remaining 
>> events */
>> +       if (int2 && dev->type == COA_TYPE_PCI)
>> +               sc1442x_writeb(dev, SC14424_RESET_INT_PENDING_1, 
>> 0x80);
>> +
>> +       while (int1) {
>> +               cnt++;
>> +               if (cnt > 254) {
>> +                       int2 = 0;
>> +                       break;
>> +               }
>> +
>> +               int1 = sc1442x_readb(dev, dev->cfg_reg) & 
>> SC1442X_IRQ_MASK;
>> +               int2 |= int1;
>> +       }
>> +
>> +       return int2 & SC1442X_IRQ_MASK;
>> +}
>> +
>> +static void sc1442x_update_phase_offset(struct coa_device *dev,
>> +                                       struct dect_transceiver_slot 
>> *ts,
>> +                                       u8 framenum)
>> +{
>> +       struct sc1442x_phase_state *ps = 
>> &dev->phase_state[ts->chd.slot / 2];
>> +       u16 off = sc1442x_slot_offset(ts->chd.slot);
>> +       s32 phaseoff;
>> +       s8 phase;
>> +       u8 tap;
>> +
>> +       /* The phase offset is calculated from the differences of the 
>> tap and
>> +        * phase status of two consequitive frames. The tap field 
>> contains
>> +        * which of the nine internal clock cycles per symbol sampled 
>> the
>> +        * incoming data and measures small scale frequency deviations 
>> up to
>> +        * +-8 * 9.6ppm == +-86.4ppm. The phase field contains the 
>> absolute
>> +        * phase offset in multiples of 87ppm.
>> +        */
>> +       tap   = sc1442x_dreadb(dev, off + 2) >> SC1442X_ST2_TAP_SHIFT;
>> +       phase = sc1442x_dreadb(dev, off + 3);
>> +
>> +       if (dect_next_framenum(ps->framenum) == framenum) {
>> +               phaseoff = (tap - ps->tap) * SC1442X_ST2_TAP_SCALE;
>> +               phaseoff += (phase - ps->phase) * 
>> SC1442X_ST3_PHASE_SCALE;
>> +
>> +               ts->phaseoff = dect_average_phase_offset(ts->phaseoff, 
>> phaseoff);
>> +       }
>> +
>> +       ps->framenum = framenum;
>> +       ps->tap      = tap;
>> +       ps->phase    = phase;
>> +}
>> +
>> +static void sc1442x_process_slot(struct coa_device *dev,
>> +                                struct dect_transceiver *trx,
>> +                                struct dect_transceiver_event *event,
>> +                                u8 slot)
>> +{
>> +       struct dect_transceiver_slot *ts = &trx->slots[slot];
>> +       struct sk_buff *skb;
>> +       u8 status, framenum, csum, rssi;
>> +       u32 mfn;
>> +       u16 off;
>> +
>> +       if (ts->state == DECT_SLOT_IDLE || ts->state == DECT_SLOT_TX)
>> +               return;
>> +
>> +       mfn = trx->cell->timer_base[DECT_TIMER_RX].mfn;
>> +       framenum = trx->cell->timer_base[DECT_TIMER_RX].framenum;
>> +
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +       off = sc1442x_slot_offset(slot);
>> +
>> +       /*
>> +        * The SC1442X contains a 6 bit ADC for RSSI measurement, 
>> convert to
>> +        * units used by the stack.
>> +        */
>> +       status = sc1442x_dreadb(dev, off + SD_RSSI_OFF);
>> +       rssi = (status & SC1442X_ST0_ADC_MASK) * DECT_RSSI_RANGE / 63;
>> +
>> +       /* validate and clear checksum */
>> +       status = sc1442x_dreadb(dev, off + SD_CSUM_OFF);
>> +       if (!(status & SC1442X_ST1_IN_SYNC))
>> +               goto out;
>> +       sc1442x_dwriteb(dev, off + SD_CSUM_OFF, 0);
>> +
>> +       if (!(status & SC1442X_ST1_A_CRC)) {
>> +               ts->rx_a_crc_errors++;
>> +               if (ts->chd.pkt == DECT_PACKET_P00)
>> +                       goto out;
>> +               csum = 0;
>> +       } else
>> +               csum = DECT_CHECKSUM_A_CRC_OK;
>> +
>> +       if (ts->chd.pkt != DECT_PACKET_P00) {
>> +               if (!(status & SC1442X_ST1_X_CRC))
>> +                       ts->rx_x_crc_errors++;
>> +               else
>> +                       csum |= DECT_CHECKSUM_X_CRC_OK;
>> +
>> +               if (!(status & SC1442X_ST1_Z_CRC))
>> +                       ts->rx_z_crc_errors++;
>> +               else
>> +                       csum |= DECT_CHECKSUM_Z_CRC_OK;
>> +       }
>> +
>> +       /* calculate phase offset */
>> +       sc1442x_update_phase_offset(dev, ts, framenum);
>> +
>> +       skb = dect_transceiver_alloc_skb(trx, slot);
>> +       if (skb == NULL)
>> +               goto out;
>> +       sc1442x_from_dmem(dev, skb->data, off + SD_DATA_OFF, 
>> skb->len);
>> +       DECT_TRX_CB(skb)->csum = csum;
>> +       DECT_TRX_CB(skb)->rssi = rssi;
>> +       __skb_queue_tail(&event->rx_queue, skb);
>> +
>> +       ts->rx_bytes += skb->len;
>> +       ts->rx_packets++;
>> +
>> +       sc1442x_toggle_led(dev);
>> +out:
>> +       ts->rssi = dect_average_rssi(ts->rssi, rssi);
>> +       dect_transceiver_record_rssi(event, slot, rssi);
>> +
>> +       /* Update frame number for next reception */
>> +       sc1442x_dwriteb(dev, off + BMC_CTRL + BMC_CTRL_MFR_OFF, 
>> framenum + 1);
>> +
>> +       /* Init DCS for slots in the first half frame */
>> +       if (ts->flags & DECT_SLOT_CIPHER && slot < 
>> DECT_HALF_FRAME_SIZE)
>> +               sc1442x_dcs_init(dev, trx, slot, mfn, framenum + 1);
>> +}
>> +
>> +irqreturn_t sc1442x_interrupt(int irq, void *dev_id)
>> +{
>> +       struct dect_transceiver *trx = dev_id;
>> +       struct coa_device *dev = dect_transceiver_priv(trx);
>> +       struct dect_transceiver_event *event;
>> +       u8 slot, i;
>> +
>> +       irq = sc1442x_clear_interrupt(dev);
>> +       if (!irq)
>> +               return IRQ_NONE;
>> +
>> +       if (unlikely(hweight8(irq) != 1 && net_ratelimit()))
>> +               dev_info(dev->dev, "lost some interrupts\n");
>> +
>> +       for (i = 0; i < 4; i++) {
>> +               if (!(irq & (1 << i)))
>> +                       continue;
>> +
>> +               event = dect_transceiver_event(trx, i % 2, i * 6);
>> +               if (event == NULL)
>> +                       goto out;
>> +
>> +               spin_lock(&dev->lock);
>> +               for (slot = 6 * i; slot < 6 * (i + 1); slot++) {
>> +                       sc1442x_process_slot(dev, trx, event, slot);
>> +                       if (slot < DECT_HALF_FRAME_SIZE)
>> +                               sc1442x_transfer_dcs_state(dev, trx, 
>> slot);
>> +               }
>> +               spin_unlock(&dev->lock);
>> +
>> +               dect_transceiver_queue_event(trx, event);
>> +       }
>> +out:
>> +       return IRQ_HANDLED;
>> +}
>> +EXPORT_SYMBOL_GPL(sc1442x_interrupt);
>> +
>> +static void sc1442x_init_slot(const struct coa_device *dev, u8 slot)
>> +{
>> +       u16 off;
>> +
>> +       sc1442x_switch_to_bank(dev, sc1442x_slot_bank(slot));
>> +       off = sc1442x_slot_offset(slot);
>> +       dev->radio_ops->rx_init(dev, off);
>> +       dev->radio_ops->tx_init(dev, off);
>> +}
>> +
>> +static int sc1442x_check_dram(const struct coa_device *dev)
>> +{
>> +       unsigned int bank, i;
>> +       unsigned int cnt;
>> +       u16 off;
>> +       u8 val;
>> +
>> +       for (bank = 0; bank < 8; bank++) {
>> +               sc1442x_switch_to_bank(dev, 4 * bank);
>> +
>> +               off = bank * SC1442X_BANKSIZE;
>> +               for (i = 0; i < SC1442X_BANKSIZE - 2; i++)
>> +                       sc1442x_dwriteb(dev, off + i, bank + i);
>> +       }
>> +
>> +       cnt = 0;
>> +       for (bank = 0; bank < 8; bank++) {
>> +               sc1442x_switch_to_bank(dev, 4 * bank);
>> +
>> +               off = bank * SC1442X_BANKSIZE;
>> +               for (i = 0; i < SC1442X_BANKSIZE - 2; i++) {
>> +                       val = sc1442x_dreadb(dev, off + i);
>> +                       if (val != ((bank + i) & 0xff)) {
>> +                               dev_err(dev->dev,
>> +                                       "memory error bank %.2x offset 
>> %.2x: "
>> +                                       "%.2x != %.2x\n", bank, i,
>> +                                       val, (bank + i) & 0xff);
>> +                               cnt++;
>> +                       }
>> +                       sc1442x_dwriteb(dev, off + i, 0);
>> +               }
>> +       }
>> +
>> +       if (cnt > 0)
>> +               dev_err(dev->dev, "found %u memory r/w errors\n", 
>> cnt);
>> +       return cnt ? -1 : 0;
>> +}
>> +
>> +int sc1442x_init_device(struct coa_device *dev)
>> +{
>> +       unsigned int i;
>> +       u8 slot;
>> +
>> +       spin_lock_init(&dev->lock);
>> +       dev->ctrl = SC1442X_DIPSTOPPED;
>> +
>> +       if (sc1442x_check_dram(dev) < 0)
>> +               return -EIO;
>> +
>> +       dev_info(dev->dev, "Loading firmware ...\n");
>> +       sc1442x_switch_to_bank(dev, SC1442X_CODEBANK);
>> +       sc1442x_to_cmem(dev, sc1442x_firmware, 
>> sizeof(sc1442x_firmware));
>> +
>> +       sc1442x_clear_interrupt(dev);
>> +
>> +       /* Init DIP */
>> +       sc1442x_switch_to_bank(dev, SC1442X_RAMBANK0);
>> +
>> +       /* Disable Codec */
>> +       sc1442x_dwriteb(dev, DIP_CC_INIT, SC1442X_CC0_STANDBY);
>> +       for (i = 1; i < SC1442X_CC_SIZE; i++)
>> +               sc1442x_dwriteb(dev, DIP_CC_INIT + i, 0);
>> +
>> +       for (slot = 0; slot < DECT_FRAME_SIZE; slot += 2)
>> +               sc1442x_init_slot(dev, slot);
>> +
>> +       if (dev->type == COA_TYPE_PCI) {
>> +               /* Enable DIP interrupt */
>> +               sc1442x_writeb(dev, SC14424_INT_PRIORITY_1, 0x70);
>> +               /* Enable SPI for LED control */
>> +               sc1442x_writeb(dev, SC14424_P1_DIR_REG, 0xd6);
>> +       }
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(sc1442x_init_device);
>> +
>> +void sc1442x_shutdown_device(struct coa_device *dev)
>> +{
>> +       sc1442x_stop_dip(dev);
>> +
>> +       if (dev->type == COA_TYPE_PCI) {
>> +               /* Clear pening interrupts */
>> +               sc1442x_writeb(dev, SC14424_RESET_INT_PENDING_1, 
>> 0xff);
>> +               sc1442x_writeb(dev, SC14424_RESET_INT_PENDING_2, 
>> 0xff);
>> +               /* Reset LED */
>> +               sc1442x_writeb(dev, SC14424_P1_RESET_OUTPUT_DATA, 
>> 0x40);
>> +       }
>> +}
>> +EXPORT_SYMBOL_GPL(sc1442x_shutdown_device);
>> +
>> +MODULE_LICENSE("GPL");
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.asm 
>> b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.asm
>> new file mode 100644
>> index 0000000..223a760
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.asm
>> @@ -0,0 +1,389 @@
>> +               CPU     SC14421
>> +               ORG     0
>> +
>> +               BR      Start
>> +
>> +PB_LED          EQU     0x80
>> +PB_RX_ON        EQU     0x40
>> +PB_TX_ON        EQU     0x10
>> +PB_RADIOPOWER   EQU     0x04
>> +PB_DCTHRESHOLD  EQU     0x02
>> +PB_RSSI                EQU     0x01
>> +
>> +; synchronisation control
>> +PSC_ARPD1      EQU     0x80
>> +PSC_S_SYNC     EQU     0x40
>> +PSC_S_SYNC_ON  EQU     0x20
>> +PSC_EOPSM      EQU     0x10
>> +
>> +; memory banks 0-7, lower and upper halfs (128 bytes each)
>> +BANK0_LOW      EQU     0x00
>> +BANK0_HIGH     EQU     0x10
>> +BANK1_LOW      EQU     0x20
>> +BANK1_HIGH     EQU     0x30
>> +BANK2_LOW      EQU     0x40
>> +BANK2_HIGH     EQU     0x50
>> +BANK3_LOW      EQU     0x60
>> +BANK3_HIGH     EQU     0x70
>> +BANK4_LOW      EQU     0x80
>> +BANK4_HIGH     EQU     0x90
>> +BANK5_LOW      EQU     0xa0
>> +BANK5_HIGH     EQU     0xb0
>> +BANK6_LOW      EQU     0xc0
>> +BANK6_HIGH     EQU     0xd0
>> +BANK7_LOW      EQU     0xe0
>> +BANK7_HIGH     EQU     0xf0
>> +
>> +; Codec Control
>> +DIP_CC_INIT    EQU     0x10
>> +
>> +; Radio configuration word
>> +RF_DESC                EQU     0x65
>> +
>> +; BMC control information
>> +BMC_CTRL_SIZE  EQU     7
>> +BMC_CTRL       EQU     0x69
>> +
>> +; (multi) frame number for scambler and DCS
>> +BMC_CTRL_MFR_OFF EQU   6
>> +
>> +; Cipher IV/Key
>> +DCS_DESC       EQU     0x70
>> +DCS_IV         EQU     DCS_DESC
>> +DCS_CK         EQU     DCS_DESC + 0x8
>> +
>> +; Cipher state
>> +DCS_STATE      EQU     0x70
>> +DCS_STATE_SIZE EQU     11
>> +
>> +SD_PREAMBLE_OFF        EQU     0x01
>> +SD_A_FIELD_OFF EQU     0x06
>> +SD_B_FIELD_OFF EQU     0x0E
>> +
>> +; status descriptor
>> +SD_BASE_OFF    EQU     0x00
>> +SD_RSSI_OFF    EQU     0x00
>> +SD_CSUM_OFF    EQU     0x01
>> +SD_DATA_OFF    EQU     0x06
>> +
>> +; U2785 radio
>> +U2785_CFG1_LEN EQU     24
>> +U2785_CFG2_LEN EQU     9
>> +
>> +;-------------------------------------------------------------
>> +
>> +Start:         BR      InitDIP
>> +;-------------------------------------------------------------
>> +
>> +SlotTable:     SLOTZERO
>> +
>> +Slot00:                WT      1
>> +               WNT     1
>> +Slot01:                WT      1
>> +               WNT     1
>> +Slot02:                WT      1
>> +               WNT     1
>> +Slot03:                WT      1
>> +               WNT     1
>> +Slot04:                WT      1
>> +               WNT     1
>> +Slot05:                WT      1
>> +               WNT     1
>> +               U_INT0
>> +
>> +Slot06:                WT      1
>> +               WNT     1
>> +Slot07:                WT      1
>> +               WNT     1
>> +Slot08:                WT      1
>> +               WNT     1
>> +Slot09:                WT      1
>> +               WNT     1
>> +Slot10:                WT      1
>> +               WNT     1
>> +Slot11:                WT      1
>> +               WNT     1
>> +               U_INT1
>> +
>> +Slot12:                WT      1
>> +               WNT     1
>> +Slot13:                WT      1
>> +               WNT     1
>> +Slot14:                WT      1
>> +               WNT     1
>> +Slot15:                WT      1
>> +               WNT     1
>> +Slot16:                WT      1
>> +               WNT     1
>> +Slot17:                WT      1
>> +               WNT     1
>> +               U_INT2
>> +
>> +Slot18:                WT      1
>> +               WNT     1
>> +Slot19:                WT      1
>> +               WNT     1
>> +Slot20:                WT      1
>> +               WNT     1
>> +Slot21:                WT      1
>> +               WNT     1
>> +Slot22:                WT      1
>> +               WNT     1
>> +Slot23:                WT      1
>> +               WNT     1
>> +               U_INT3
>> +
>> +               BR      SlotTable
>> +
>> +;-------------------------------------------------------------------------------
>> +; Receive a P00 packet
>> +;
>> +RX_P00:                JMP     Receive         ; Receive S- and 
>> beginning of A-field           |
>> +RX_P00_End:    B_BRFU  SD_B_FIELD_OFF  ; Receive unprotected 
>> full-slot B-field         | p: 95         A: 63
>> +               JMP     ReceiveEnd      ; End reception                
>>                  | p: 96         B:  0
>> +               BR      WriteBMC1       ;
>> +
>> +RX_P00_Sync:   JMP     ReceiveSync     ; Receive S- and beginning of 
>> A-field           |
>> +               BR      RX_P00_End
>> +
>> +; Receive a P32 packet using the the unprotected full slot B-field 
>> format in
>> +; the D32-field
>> +;
>> +RX_P32U_Enc:   JMP     LoadEncKey
>> +RX_P32U:       JMP     Receive
>> +               B_BRFU  SD_B_FIELD_OFF  ; Receive unprotected 
>> full-slot B-field         | p: 95         A: 63
>> +               JMP     RX_P32U_BZ      ; Receive B-field              
>>                  | p: 96         B:  0
>> +               BR      WriteBMC2
>> +
>> +;-------------------------------------------------------------------------------
>> +; Transmit a P00 packet
>> +;
>> +TX_P00:                JMP     Transmit        ; Transmit S- and 
>> beginning of A-field          |
>> +               JMP     TransmitEnd     ; End transmission             
>>                  | p: 94         A: 62
>> +               BR      label_53        ;
>> +
>> +; Transmit a P32 packet using the unprotected full slot B-field 
>> format in the
>> +; D32-field
>> +;
>> +TX_P32U_Enc:   JMP     LoadEncKey
>> +TX_P32U:       JMP     Transmit        ; Transmit S- and beginning of 
>> A-field          |
>> +               B_BTFU  SD_B_FIELD_OFF  ; Transmit unprotected 
>> full-slot B-field data   | p: 95         A: 63
>> +               JMP     TX_P32U_BZ      ; Transmit the B- and Z-fields 
>>                  | p: 96         B: 0
>> +               BR      label_54        ;
>> +
>> +;-------------------------------------------------------------------------------
>> +WriteBMC1:     B_WRS   SD_BASE_OFF     ; write status
>> +               WT      6
>> +
>> +label_53:      B_RST
>> +label_54:      P_LDL   PB_RX_ON | PB_TX_ON
>> +               WT      5
>> +               WNT     1
>> +               RTN
>> +
>> +;-------------------------------------------------------------------------------
>> +WriteBMC2:     B_WRS   SD_BASE_OFF     ; write status
>> +               WT      6
>> +label_58:      B_RST
>> +               P_LDL   PB_RX_ON | PB_TX_ON
>> +               RTN
>> +;-------------------------------------------------------------------------------
>> +; Enable the receiver, receive the S-field and the first 61 bits of 
>> the D-field
>> +; (93 bits total)
>> +;
>> +Receive:       B_RST
>> +               B_RC    BMC_CTRL
>> +               WT      BMC_CTRL_SIZE + 1
>> +               P_LDH   PB_RX_ON
>> +               P_LDL   PB_RSSI         ; enable RSSI measurement
>> +               WT      25
>> +               WNT     1               ; Wait until beginning of slot 
>>                  |
>> +               WT      8               ;                              
>>                  | p: -33--26
>> +               B_XON                   ;                              
>>                  | p: -25
>> +ClockSyncOn:   P_SC    PSC_S_SYNC_ON   ;                              
>>                  | p: -24
>> +               P_LDH   PB_DCTHRESHOLD  ;                              
>>                  | p: -23
>> +               WT      5               ;                              
>>                  | p: -22--16
>> +               B_SR                    ; Receive S-field              
>>                  | p: -17
>> +ClockAdjust:   EN_SL_ADJ               ;                              
>>                  | p: -16        S: 0
>> +               WT      12              ;                              
>>                  | p: -15--4     S: 1-12
>> +               P_LDL   PB_DCTHRESHOLD  ;                              
>>                  | p:  -3        S: 13
>> +               WT      32              ;                              
>>                  | p:  -2-29     S: 14-45
>> +ClockSyncOff:  P_SC    0x00            ;                              
>>                  | p:  30        S: 46
>> +               B_AR2   SD_A_FIELD_OFF  ; Start reception of 
>> A-field/A-field CRC        | p:  31        S: 47
>> +               WT      62              ; Receive first 61 bits of 
>> A-field              | p:  32-92     A:  0-60
>> +               RTN                     ; Return                       
>>                  | p:  93        A: 61
>> +
>> +ReceiveSync:   B_RST
>> +               B_RC    BMC_CTRL
>> +               WT      BMC_CTRL_SIZE + 1
>> +               P_LDH   PB_RX_ON
>> +               P_LDL   PB_RSSI         ; enable RSSI measurement
>> +               WT      25
>> +               WNT     1               ; Wait until beginning of slot 
>>                  |
>> +               WT      8               ;                              
>>                  | p: -33--26
>> +               B_XON                   ;                              
>>                  | p: -25
>> +               P_SC    PSC_S_SYNC_ON   ;                              
>>                  | p: -24
>> +               P_LDH   PB_DCTHRESHOLD  ;                              
>>                  | p: -23
>> +               WT      5               ;                              
>>                  | p: -22--16
>> +               B_SR                    ; Receive S-field              
>>                  | p: -17
>> +               EN_SL_ADJ               ;                              
>>                  | p: -16        S: 0
>> +               WT      12              ;                              
>>                  | p: -15--4     S: 1-12
>> +               P_LDL   PB_DCTHRESHOLD  ;                              
>>                  | p:  -3        S: 13
>> +               WT      32              ;                              
>>                  | p:  -2-29     S: 14-45
>> +               P_SC    0x00            ;                              
>>                  | p:  30        S: 46
>> +               B_AR2   SD_A_FIELD_OFF  ; Start reception of 
>> A-field/A-field CRC        | p:  31        S: 47
>> +               WT      61              ; Receive first 61 bits of 
>> A-field              | p:  32-92     A:  0-60
>> +               RTN                     ; Return                       
>>                  | p:  93        A: 61
>> +
>> +; Receive the B- and Z-fields of a P32 packet using the protected 
>> full slot
>> +; B-field format in the D32-field
>> +RX_P32U_BZ:    WT      249             ;                              
>>                  | p:  97-345    B:   1-249
>> +               WT      79              ;                              
>>                  | p: 346-415    B: 250-319
>> +                                       ;                              
>>                  | p: 416-419    B: 320-323      X: 0-3
>> +                                       ;                              
>>                  | p: 420-423    Z:   0-  3
>> +                                       ;                              
>>                  | p: 424        ??
>> +ReceiveEnd:    P_LDH   PB_RSSI         ;                              
>>                  |
>> +               P_LDL   PB_RX_ON
>> +               BR      SaveEncState
>> +;-------------------------------------------------------------------------------
>> +; Enable transmitter, transmit the S-field and the first 61 bits of 
>> the D-field
>> +; (93 bits total)
>> +;
>> +Transmit:      P_LDH   0x00            ;
>> +               WT      40              ;
>> +               B_RST                   ;
>> +               B_RC    BMC_CTRL        ;
>> +               WNT     1               ; Wait until beginning of slot
>> +               B_ST    0x00            ; Start transmission of 
>> S-field data            |
>> +               WT      1               ; Wait one bit                 
>>                  | p: -8         S:  0
>> +               P_LDH   PB_TX_ON        ; Enable transmitter           
>>                  | p: -7         S:  1
>> +               WT      37              ; Transmit 29 bits S-field     
>>                  | p: -6-30      S:  2-38
>> +               B_AT2   SD_A_FIELD_OFF  ; Start transission of A-field 
>> data/A-field CRC | p: 31         S: 39
>> +               WT      62              ; Transmit first 61 bits of 
>> A-field             | p: 32-92      A:  0-60
>> +               RTN                     ; Return                       
>>                  | p: 93         A: 61
>> +
>> +;-------------------------------------------------------------------------------
>> +;
>> +;
>> +TX_P32U_BZ:    WT      249             ;                              
>>                  | p:  97-345    B:   1-249
>> +               WT      84              ; Last bits of B-field data    
>>                  | p: 346-415    B: 250-319
>> +                                       ; X-field                      
>>                  | p: 416-419    B: 320-323      X: 0-3
>> +                                       ; Z-field (?)                  
>>                  | p: 420-424    Z:   0-  3
>> +                                       ; 5 bits of crap?              
>>                  | p: 425-429
>> +               B_RST                   ; Reset BMC                    
>>                  | p: 430
>> +
>> +TransmitEnd:   P_LDL   PB_TX_ON        ; Disable transmitter          
>>                  |
>> +               WT      8               ; Wait until transmitter is 
>> disabled            |
>> +               P_LDL   0x00            ;
>> +               BR      SaveEncState
>> +
>> +;-------------------------------------------------------------------------------
>> +
>> +RFInit:                RFEN                    ; Enable RF-clock
>> +               WT      2
>> +
>> +               MEN1N                   ; Transfer first radio 
>> configuration word
>> +               M_WR    RF_DESC
>> +               WT      U2785_CFG1_LEN + 1
>> +               M_RST
>> +               MEN1
>> +
>> +               MEN1N                   ; Transfer second radio 
>> configuration word
>> +               M_WR    RF_DESC + U2785_CFG1_LEN / 8
>> +               WT      U2785_CFG2_LEN + 1
>> +               M_RST
>> +               MEN1
>> +               ;WT     1
>> +
>> +               P_LDL   0x20
>> +               WT      10
>> +               MEN2
>> +               WT      182
>> +               MEN2N
>> +               WT      16
>> +               RTN
>> +;--------------------------------------------------------------
>> +;
>> +LoadEncKey:    D_RST
>> +               D_LDK   DCS_DESC        ; load IV (64 bits) and cipher 
>> key (64 bits)
>> +               WT      16
>> +               D_LDK   0
>> +               D_PREP  0
>> +               WT      39
>> +               D_PREP  0
>> +               RTN
>> +
>> +SaveEncState:  D_WRS   DCS_STATE
>> +               WT      DCS_STATE_SIZE  ; actually should be -1, but 
>> does not work
>> +               D_WRS   0
>> +               D_RST
>> +               RTN
>> +
>> +LoadEncState:  D_RST
>> +               D_LDS   DCS_STATE
>> +               WT      DCS_STATE_SIZE  ; actually should be -1, but 
>> does not work
>> +               D_LDS   0
>> +               RTN
>> +;-------------------------------------------------------------
>> +
>> +SyncInit:      BK_C    BANK1_LOW
>> +Sync:          JMP     RFInit
>> +               WT      250
>> +               P_SC    PSC_S_SYNC_ON
>> +               P_LDH   PB_RX_ON | PB_DCTHRESHOLD
>> +               UNLCK
>> +               WT      64
>> +               B_XOFF
>> +               B_SR
>> +               WNT     20
>> +               JMP1    SFieldFound
>> +               B_RST
>> +               U_INT1
>> +               WNT     23
>> +               BR      Sync
>> +;-------------------------------------------------------------
>> +
>> +SFieldFound:   WNT     23
>> +               P_SC    0x00
>> +SyncLock:      JMP     RFInit
>> +               JMP     RX_P00
>> +               U_INT0
>> +               WNT     22
>> +SyncLoop:      BR      Sync
>> +;-------------------------------------------------------------
>> +
>> +InitDIP:       ;B_RST
>> +               BK_C    BANK0_LOW
>> +               C_LD    DIP_CC_INIT
>> +               WT      10
>> +               ;B_RC   BMC_CTRL
>> +               ;WT     BMC_CTRL_SIZE + 1
>> +               B_RST
>> +               ;C_ON
>> +               WT      10
>> +               P_EN
>> +               P_LD    0x04
>> +               RCK_INT
>> +               RFEN
>> +RFStart:       BR      SyncInit
>> +;-------------------------------------------------------------
>> +
>> +               SHARED  DIP_CC_INIT,RF_DESC
>> +               SHARED  BMC_CTRL,BMC_CTRL_MFR_OFF
>> +               SHARED  
>> SD_RSSI_OFF,SD_CSUM_OFF,SD_PREAMBLE_OFF,SD_DATA_OFF
>> +
>> +               SHARED  SlotTable
>> +               SHARED  
>> Slot00,Slot01,Slot02,Slot03,Slot04,Slot05,Slot06,Slot07
>> +               SHARED  
>> Slot08,Slot09,Slot10,Slot11,Slot12,Slot13,Slot14,Slot15
>> +               SHARED  
>> Slot16,Slot17,Slot18,Slot19,Slot20,Slot21,Slot22,Slot23
>> +
>> +               SHARED  RFStart,RFInit
>> +               SHARED  SyncInit,Sync,SyncLock,SyncLoop
>> +               SHARED  ClockSyncOn,ClockSyncOff,ClockAdjust
>> +               SHARED  PSC_ARPD1,PSC_S_SYNC,PSC_S_SYNC_ON,PSC_EOPSM
>> +
>> +               SHARED  RX_P00,RX_P00_Sync,RX_P32U,RX_P32U_Enc
>> +               SHARED  TX_P00,TX_P32U,TX_P32U_Enc
>> +
>> +               SHARED  DCS_IV,DCS_CK,DCS_STATE,DCS_STATE_SIZE
>> +               SHARED  LoadEncKey,LoadEncState
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.c 
>> b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.c
>> new file mode 100644
>> index 0000000..77880ce
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.c
>> @@ -0,0 +1,73 @@
>> +/*
>> + * automatically generated file
>> + * DO NOT EDIT
>> + * edit firmware/filename.asm instead
>> + */
>> +
>> +#include "sc1442x_firmware.h"
>> +
>> +const unsigned char sc1442x_firmware[] = {
>> +       0x01, 0x01, 0x01, 0xd4, 0x0d, 0x00, 0x09, 0x01,
>> +       0x08, 0x01, 0x09, 0x01, 0x08, 0x01, 0x09, 0x01,
>> +       0x08, 0x01, 0x09, 0x01, 0x08, 0x01, 0x09, 0x01,
>> +       0x08, 0x01, 0x09, 0x01, 0x08, 0x01, 0x61, 0x00,
>> +       0x09, 0x01, 0x08, 0x01, 0x09, 0x01, 0x08, 0x01,
>> +       0x09, 0x01, 0x08, 0x01, 0x09, 0x01, 0x08, 0x01,
>> +       0x09, 0x01, 0x08, 0x01, 0x09, 0x01, 0x08, 0x01,
>> +       0x6b, 0x00, 0x09, 0x01, 0x08, 0x01, 0x09, 0x01,
>> +       0x08, 0x01, 0x09, 0x01, 0x08, 0x01, 0x09, 0x01,
>> +       0x08, 0x01, 0x09, 0x01, 0x08, 0x01, 0x09, 0x01,
>> +       0x08, 0x01, 0x6d, 0x00, 0x09, 0x01, 0x08, 0x01,
>> +       0x09, 0x01, 0x08, 0x01, 0x09, 0x01, 0x08, 0x01,
>> +       0x09, 0x01, 0x08, 0x01, 0x09, 0x01, 0x08, 0x01,
>> +       0x09, 0x01, 0x08, 0x01, 0x6f, 0x00, 0x01, 0x02,
>> +       0x02, 0x57, 0x2d, 0x0e, 0x02, 0x83, 0x01, 0x4b,
>> +       0x02, 0x6c, 0x01, 0x39, 0x02, 0xac, 0x02, 0x57,
>> +       0x2d, 0x0e, 0x02, 0x81, 0x01, 0x52, 0x02, 0x86,
>> +       0x02, 0x95, 0x01, 0x4d, 0x02, 0xac, 0x02, 0x86,
>> +       0x25, 0x0e, 0x02, 0x92, 0x01, 0x4e, 0x39, 0x00,
>> +       0x09, 0x06, 0x20, 0x00, 0xec, 0x50, 0x09, 0x05,
>> +       0x08, 0x01, 0x04, 0x00, 0x39, 0x00, 0x09, 0x06,
>> +       0x20, 0x00, 0xec, 0x50, 0x04, 0x00, 0x20, 0x00,
>> +       0x33, 0x69, 0x09, 0x08, 0xed, 0x40, 0xec, 0x01,
>> +       0x09, 0x19, 0x08, 0x01, 0x09, 0x08, 0x27, 0x00,
>> +       0xea, 0x20, 0xed, 0x02, 0x09, 0x05, 0x29, 0x00,
>> +       0x2c, 0x00, 0x09, 0x0c, 0xec, 0x02, 0x09, 0x20,
>> +       0xea, 0x00, 0x3f, 0x06, 0x09, 0x3e, 0x04, 0x00,
>> +       0x20, 0x00, 0x33, 0x69, 0x09, 0x08, 0xed, 0x40,
>> +       0xec, 0x01, 0x09, 0x19, 0x08, 0x01, 0x09, 0x08,
>> +       0x27, 0x00, 0xea, 0x20, 0xed, 0x02, 0x09, 0x05,
>> +       0x29, 0x00, 0x2c, 0x00, 0x09, 0x0c, 0xec, 0x02,
>> +       0x09, 0x20, 0xea, 0x00, 0x3f, 0x06, 0x09, 0x3d,
>> +       0x04, 0x00, 0x09, 0xf9, 0x09, 0x4f, 0xed, 0x01,
>> +       0xec, 0x40, 0x01, 0xb4, 0xed, 0x00, 0x09, 0x28,
>> +       0x20, 0x00, 0x33, 0x69, 0x08, 0x01, 0x31, 0x00,
>> +       0x09, 0x01, 0xed, 0x10, 0x09, 0x25, 0x37, 0x06,
>> +       0x09, 0x3e, 0x04, 0x00, 0x09, 0xf9, 0x09, 0x54,
>> +       0x20, 0x00, 0xec, 0x10, 0x09, 0x08, 0xec, 0x00,
>> +       0x01, 0xb4, 0x0b, 0x00, 0x09, 0x02, 0xa4, 0x00,
>> +       0xb9, 0x65, 0x09, 0x19, 0xa9, 0x00, 0xa5, 0x00,
>> +       0xa4, 0x00, 0xb9, 0x68, 0x09, 0x0a, 0xa9, 0x00,
>> +       0xa5, 0x00, 0xec, 0x20, 0x09, 0x0a, 0xa7, 0x00,
>> +       0x09, 0xb6, 0xa6, 0x00, 0x09, 0x10, 0x04, 0x00,
>> +       0x40, 0x00, 0x50, 0x70, 0x09, 0x10, 0x50, 0x00,
>> +       0x44, 0x00, 0x09, 0x27, 0x44, 0x00, 0x04, 0x00,
>> +       0x5f, 0x70, 0x09, 0x0b, 0x5f, 0x00, 0x40, 0x00,
>> +       0x04, 0x00, 0x40, 0x00, 0x57, 0x70, 0x09, 0x0b,
>> +       0x57, 0x00, 0x04, 0x00, 0x0f, 0x20, 0x02, 0x99,
>> +       0x09, 0xfa, 0xea, 0x20, 0xed, 0x42, 0x28, 0x00,
>> +       0x09, 0x40, 0x26, 0x00, 0x29, 0x00, 0x08, 0x14,
>> +       0x03, 0xcd, 0x20, 0x00, 0x6b, 0x00, 0x08, 0x17,
>> +       0x01, 0xbf, 0x08, 0x17, 0xea, 0x00, 0x02, 0x99,
>> +       0x02, 0x38, 0x61, 0x00, 0x08, 0x16, 0x01, 0xbf,
>> +       0x0f, 0x00, 0xfa, 0x10, 0x09, 0x0a, 0x20, 0x00,
>> +       0x09, 0x0a, 0xe9, 0x00, 0xe8, 0x04, 0x62, 0x00,
>> +       0x0b, 0x00, 0x01, 0xbe, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
>> +       0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
>> diff --git 
>> a/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.h 
>> b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.h
>> new file mode 100644
>> index 0000000..bcf126a
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/coa/sc1442x_firmware.h
>> @@ -0,0 +1,66 @@
>> +#ifndef SC1442X_FIRMWARE
>> +#define SC1442X_FIRMWARE
>> +
>> +extern const unsigned char sc1442x_firmware[510];
>> +
>> +#define DIP_CC_INIT 0x10
>> +#define RF_DESC 0x65
>> +#define BMC_CTRL 0x69
>> +#define BMC_CTRL_MFR_OFF 0x6
>> +#define SD_RSSI_OFF 0x0
>> +#define SD_CSUM_OFF 0x1
>> +#define SD_PREAMBLE_OFF 0x1
>> +#define SD_DATA_OFF 0x6
>> +#define SlotTable 0x2
>> +#define Slot00 0x3
>> +#define Slot01 0x5
>> +#define Slot02 0x7
>> +#define Slot03 0x9
>> +#define Slot04 0xB
>> +#define Slot05 0xD
>> +#define Slot06 0x10
>> +#define Slot07 0x12
>> +#define Slot08 0x14
>> +#define Slot09 0x16
>> +#define Slot10 0x18
>> +#define Slot11 0x1A
>> +#define Slot12 0x1D
>> +#define Slot13 0x1F
>> +#define Slot14 0x21
>> +#define Slot15 0x23
>> +#define Slot16 0x25
>> +#define Slot17 0x27
>> +#define Slot18 0x2A
>> +#define Slot19 0x2C
>> +#define Slot20 0x2E
>> +#define Slot21 0x30
>> +#define Slot22 0x32
>> +#define Slot23 0x34
>> +#define RFStart 0xDD
>> +#define RFInit 0x99
>> +#define SyncInit 0xBE
>> +#define Sync 0xBF
>> +#define SyncLock 0xCF
>> +#define SyncLoop 0xD3
>> +#define ClockSyncOn 0x60
>> +#define ClockSyncOff 0x68
>> +#define ClockAdjust 0x64
>> +#define PSC_ARPD1 0x80
>> +#define PSC_S_SYNC 0x40
>> +#define PSC_S_SYNC_ON 0x20
>> +#define PSC_EOPSM 0x10
>> +#define RX_P00 0x38
>> +#define RX_P00_Sync 0x3C
>> +#define RX_P32U 0x3F
>> +#define RX_P32U_Enc 0x3E
>> +#define TX_P00 0x43
>> +#define TX_P32U 0x47
>> +#define TX_P32U_Enc 0x46
>> +#define DCS_IV 0x70
>> +#define DCS_CK 0x78
>> +#define DCS_STATE 0x70
>> +#define DCS_STATE_SIZE 0xB
>> +#define LoadEncKey 0xAC
>> +#define LoadEncState 0xB9
>> +
>> +#endif /* SC1442X_FIRMWARE */
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/Kconfig 
>> b/target/linux/generic/files/drivers/dect/vtrx/Kconfig
>> new file mode 100644
>> index 0000000..fb86eee
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/Kconfig
>> @@ -0,0 +1,5 @@
>> +config DECT_VTRX
>> +       tristate "DECT virtual transceiver support"
>> +       depends on DECT
>> +       help
>> +         This option enables support for the virtual DECT 
>> transceiver.
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/Makefile 
>> b/target/linux/generic/files/drivers/dect/vtrx/Makefile
>> new file mode 100644
>> index 0000000..08abbf5
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/Makefile
>> @@ -0,0 +1,2 @@
>> +obj-$(CONFIG_DECT_VTRX)                += dect-vtrx.o
>> +dect-vtrx-objs                 := vtrx.o vtrx-sysfs.o mw_to_dbm.o
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/mw_to_dbm.c 
>> b/target/linux/generic/files/drivers/dect/vtrx/mw_to_dbm.c
>> new file mode 100644
>> index 0000000..55122a8
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/mw_to_dbm.c
>> @@ -0,0 +1,164 @@
>> +/*
>> + * DECT virtual transceiver
>> + *
>> + * Copyright (c) 2010 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <net/dect/transceiver.h>
>> +#include "vtrx.h"
>> +
>> +static const struct {
>> +       u64             mw;
>> +       int             dbm;
>> +} mw_to_dbm_tbl[] = {
>> +       { 5ULL,                 -93 },
>> +       { 6ULL,                 -92 },
>> +       { 7ULL,                 -91 },
>> +       { 10ULL,                -90 },
>> +       { 12ULL,                -89 },
>> +       { 15ULL,                -88 },
>> +       { 19ULL,                -87 },
>> +       { 25ULL,                -86 },
>> +       { 31ULL,                -85 },
>> +       { 39ULL,                -84 },
>> +       { 50ULL,                -83 },
>> +       { 63ULL,                -82 },
>> +       { 79ULL,                -81 },
>> +       { 100ULL,               -80 },
>> +       { 125ULL,               -79 },
>> +       { 158ULL,               -78 },
>> +       { 199ULL,               -77 },
>> +       { 251ULL,               -76 },
>> +       { 316ULL,               -75 },
>> +       { 398ULL,               -74 },
>> +       { 501ULL,               -73 },
>> +       { 630ULL,               -72 },
>> +       { 794ULL,               -71 },
>> +       { 1000ULL,              -70 },
>> +       { 1258ULL,              -69 },
>> +       { 1584ULL,              -68 },
>> +       { 1995ULL,              -67 },
>> +       { 2511ULL,              -66 },
>> +       { 3162ULL,              -65 },
>> +       { 3981ULL,              -64 },
>> +       { 5011ULL,              -63 },
>> +       { 6309ULL,              -62 },
>> +       { 7943ULL,              -61 },
>> +       { 10000ULL,             -60 },
>> +       { 12589ULL,             -59 },
>> +       { 15848ULL,             -58 },
>> +       { 19952ULL,             -57 },
>> +       { 25118ULL,             -56 },
>> +       { 31622ULL,             -55 },
>> +       { 39810ULL,             -54 },
>> +       { 50118ULL,             -53 },
>> +       { 63095ULL,             -52 },
>> +       { 79432ULL,             -51 },
>> +       { 100000ULL,            -50 },
>> +       { 125892ULL,            -49 },
>> +       { 158489ULL,            -48 },
>> +       { 199526ULL,            -47 },
>> +       { 251188ULL,            -46 },
>> +       { 316227ULL,            -45 },
>> +       { 398107ULL,            -44 },
>> +       { 501187ULL,            -43 },
>> +       { 630957ULL,            -42 },
>> +       { 794328ULL,            -41 },
>> +       { 1000000ULL,           -40 },
>> +       { 1258925ULL,           -39 },
>> +       { 1584893ULL,           -38 },
>> +       { 1995262ULL,           -37 },
>> +       { 2511886ULL,           -36 },
>> +       { 3162277ULL,           -35 },
>> +       { 3981071ULL,           -34 },
>> +       { 5011872ULL,           -33 },
>> +       { 6309573ULL,           -32 },
>> +       { 7943282ULL,           -31 },
>> +       { 10000000ULL,          -30 },
>> +       { 12589254ULL,          -29 },
>> +       { 15848931ULL,          -28 },
>> +       { 19952623ULL,          -27 },
>> +       { 25118864ULL,          -26 },
>> +       { 31622776ULL,          -25 },
>> +       { 39810717ULL,          -24 },
>> +       { 50118723ULL,          -23 },
>> +       { 63095734ULL,          -22 },
>> +       { 79432823ULL,          -21 },
>> +       { 100000000ULL,         -20 },
>> +       { 125892541ULL,         -19 },
>> +       { 158489319ULL,         -18 },
>> +       { 199526231ULL,         -17 },
>> +       { 251188643ULL,         -16 },
>> +       { 316227766ULL,         -15 },
>> +       { 398107170ULL,         -14 },
>> +       { 501187233ULL,         -13 },
>> +       { 630957344ULL,         -12 },
>> +       { 794328234ULL,         -11 },
>> +       { 1000000000ULL,        -10 },
>> +       { 1258925411ULL,        -9 },
>> +       { 1584893192ULL,        -8 },
>> +       { 1995262314ULL,        -7 },
>> +       { 2511886431ULL,        -6 },
>> +       { 3162277660ULL,        -5 },
>> +       { 3981071705ULL,        -4 },
>> +       { 5011872336ULL,        -3 },
>> +       { 6309573444ULL,        -2 },
>> +       { 7943282347ULL,        -1 },
>> +       { 10000000000ULL,       0 },
>> +       { 12589254117ULL,       1 },
>> +       { 15848931924ULL,       2 },
>> +       { 19952623149ULL,       3 },
>> +       { 25118864315ULL,       4 },
>> +       { 31622776601ULL,       5 },
>> +       { 39810717055ULL,       6 },
>> +       { 50118723362ULL,       7 },
>> +       { 63095734448ULL,       8 },
>> +       { 79432823472ULL,       9 },
>> +       { 100000000000ULL,      10 },
>> +       { 125892541179ULL,      11 },
>> +       { 158489319246ULL,      12 },
>> +       { 199526231496ULL,      13 },
>> +       { 251188643150ULL,      14 },
>> +       { 316227766016ULL,      15 },
>> +       { 398107170553ULL,      16 },
>> +       { 501187233627ULL,      17 },
>> +       { 630957344480ULL,      18 },
>> +       { 794328234724ULL,      19 },
>> +       { 1000000000000ULL,     20 },
>> +       { 1258925411794ULL,     21 },
>> +       { 1584893192461ULL,     22 },
>> +       { 1995262314968ULL,     23 },
>> +       { 2511886431509ULL,     24 },
>> +};
>> +
>> +int dect_mw_to_dbm(u64 mw)
>> +{
>> +       unsigned int min, max, mid;
>> +       u64 val;
>> +
>> +       min = 0;
>> +       max = ARRAY_SIZE(mw_to_dbm_tbl) - 1;
>> +
>> +       while (min < max) {
>> +               mid = min + (max - min) / 2;
>> +
>> +               val = mw_to_dbm_tbl[mid].mw;
>> +               if (val < mw)
>> +                       min = mid + 1;
>> +               else
>> +                       max = mid;
>> +       }
>> +
>> +       if (val > mw) {
>> +               if (mid == 0)
>> +                       return 0;
>> +               mid--;
>> +       }
>> +
>> +       return mw_to_dbm_tbl[mid].dbm;
>> +}
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/vtrx-sysfs.c 
>> b/target/linux/generic/files/drivers/dect/vtrx/vtrx-sysfs.c
>> new file mode 100644
>> index 0000000..32fbea6
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/vtrx-sysfs.c
>> @@ -0,0 +1,229 @@
>> +/*
>> + * DECT virtual transceiver
>> + *
>> + * Copyright (c) 2010 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/stat.h>
>> +#include <net/dect/transceiver.h>
>> +#include "vtrx.h"
>> +
>> +static struct class *dect_class;
>> +
>> +/*
>> + * Transceivers
>> + */
>> +
>> +#define VTRX_ATTR(_name, _mode, _show, _store)                        
>>                  \
>> +       struct device_attribute vtrx_attr_##_name = __ATTR(_name, 
>> _mode, _show, _store)
>> +
>> +#define VTRX_NUMERIC_ATTR(name, field, scale)                         
>>                  \
>> +static ssize_t vtrx_show_##name(struct device *dev, struct 
>> device_attribute *attr,     \
>> +                               char *buf)                             
>>                  \
>> +{                                                                     
>>                  \
>> +       struct dect_vtrx *vtrx = dev_get_drvdata(dev);                 
>>                  \
>> +       return sprintf(buf, "%llu\n",                                  
>>                  \
>> +                      (unsigned long long)div64_u64(vtrx->field, 
>> scale));              \
>> +}                                                                     
>>                  \
>> +                                                                      
>>                  \
>> +static ssize_t vtrx_store_##name(struct device *dev, struct 
>> device_attribute *attr,    \
>> +                                const char *buf, size_t count)        
>>                  \
>> +{                                                                     
>>                  \
>> +       struct dect_vtrx *vtrx = dev_get_drvdata(dev);                 
>>                  \
>> +       char *ptr;                                                     
>>                  \
>> +       u32 val;                                                       
>>                  \
>> +                                                                      
>>                  \
>> +       val = simple_strtoul(buf, &ptr, 10);                           
>>                  \
>> +       if (ptr == buf)                                                
>>                  \
>> +               return -EINVAL;                                        
>>                  \
>> +       vtrx->field = val * scale;                                     
>>                  \
>> +       return count;                                                  
>>                  \
>> +}                                                                     
>>                  \
>> +static VTRX_ATTR(name, S_IRUGO | S_IWUSR, vtrx_show_##name, 
>> vtrx_store_##name)
>> +
>> +VTRX_NUMERIC_ATTR(tx_power, tx_power, DECT_VTRX_POWER_SCALE);
>> +VTRX_NUMERIC_ATTR(pos_x, pos_x, 1000);
>> +VTRX_NUMERIC_ATTR(pos_y, pos_y, 1000);
>> +
>> +static ssize_t vtrx_store_remove(struct device *dev, struct 
>> device_attribute *attr,
>> +                                const char *buf, size_t count)
>> +{
>> +       struct dect_vtrx *vtrx = dev_get_drvdata(dev);
>> +
>> +       dect_vtrx_free(vtrx);
>> +       return count;
>> +}
>> +
>> +static VTRX_ATTR(remove, S_IWUSR, NULL, vtrx_store_remove);
>> +
>> +static struct attribute *vtrx_attrs[] = {
>> +       &vtrx_attr_tx_power.attr,
>> +       &vtrx_attr_pos_x.attr,
>> +       &vtrx_attr_pos_y.attr,
>> +       &vtrx_attr_remove.attr,
>> +       NULL
>> +};
>> +
>> +static struct attribute_group vtrx_attr_group = {
>> +       .attrs          = vtrx_attrs,
>> +};
>> +
>> +static const struct attribute_group *vtrx_attr_groups[] = {
>> +       &vtrx_attr_group,
>> +       NULL,
>> +};
>> +
>> +static void dect_vtrx_release(struct device *dev)
>> +{
>> +       printk("%s\n", __func__);
>> +}
>> +
>> +static struct device_type dect_vtrx_group = {
>> +       .name           = "vtrx",
>> +       .groups         = vtrx_attr_groups,
>> +       .release        = dect_vtrx_release,
>> +};
>> +
>> +int dect_vtrx_register_sysfs(struct dect_vtrx *vtrx)
>> +{
>> +       struct device *dev = &vtrx->dev;
>> +
>> +       dev->type   = &dect_vtrx_group;
>> +       dev->class  = dect_class;
>> +       dev->parent = &vtrx->group->dev;
>> +
>> +       dev_set_name(dev, "%s", vtrx->trx->name);
>> +       dev_set_drvdata(dev, vtrx);
>> +
>> +       return device_register(dev);
>> +}
>> +
>> +void dect_vtrx_unregister_sysfs(struct dect_vtrx *vtrx)
>> +{
>> +       device_del(&vtrx->dev);
>> +}
>> +
>> +/*
>> + * Groups
>> + */
>> +
>> +#define GROUP_ATTR(_name, _mode, _show, _store)                       
>>                          \
>> +       struct device_attribute group_attr_##_name = __ATTR(_name, 
>> _mode, _show, _store)
>> +
>> +#define GROUP_SHOW(name, field, fmt)                                  
>>                  \
>> +static ssize_t group_show_##name(struct device *dev, struct 
>> device_attribute *attr,    \
>> +                                char *buf)                            
>>                  \
>> +{                                                                     
>>                  \
>> +       struct dect_vtrx_group *group = dev_get_drvdata(dev);          
>>                  \
>> +       return sprintf(buf, fmt, group->field);                        
>>                  \
>> +}                                                                     
>>                  \
>> +                                                                      
>>                  \
>> +static ssize_t group_store_##name(struct device *dev, struct 
>> device_attribute *attr,   \
>> +                                 const char *buf, size_t count)       
>>                  \
>> +{                                                                     
>>                  \
>> +       struct dect_vtrx_group *group = dev_get_drvdata(dev);          
>>                  \
>> +       char *ptr;                                                     
>>                  \
>> +       u32 val;                                                       
>>                  \
>> +                                                                      
>>                  \
>> +       val = simple_strtoul(buf, &ptr, 10);                           
>>                  \
>> +       if (ptr == buf)                                                
>>                  \
>> +               return -EINVAL;                                        
>>                  \
>> +       group->field = val;                                            
>>                  \
>> +       return count;                                                  
>>                  \
>> +}                                                                     
>>                  \
>> +static GROUP_ATTR(name, S_IRUGO | S_IWUSR, group_show_##name, 
>> group_store_##name)
>> +
>> +static ssize_t group_store_new(struct device *dev, struct 
>> device_attribute *attr,
>> +                              const char *buf, size_t count)
>> +{
>> +       struct dect_vtrx_group *group = dev_get_drvdata(dev);
>> +       int err;
>> +
>> +       err = dect_vtrx_init(group);
>> +       return err ? err : count;
>> +}
>> +
>> +static GROUP_ATTR(new_trx, S_IWUSR, NULL, group_store_new);
>> +
>> +static struct attribute *group_attrs[] = {
>> +       &group_attr_new_trx.attr,
>> +       NULL
>> +};
>> +
>> +static struct attribute_group group_attr_group = {
>> +       .attrs          = group_attrs,
>> +};
>> +
>> +static const struct attribute_group *group_attr_groups[] = {
>> +       &group_attr_group,
>> +       NULL,
>> +};
>> +
>> +static void dect_vtrx_group_release(struct device *dev)
>> +{
>> +       printk("%s\n", __func__);
>> +}
>> +
>> +static struct device_type dect_vtrx_group_group = {
>> +       .name           = "vtrx-group",
>> +       .groups         = group_attr_groups,
>> +       .release        = dect_vtrx_group_release,
>> +};
>> +
>> +int dect_vtrx_group_register_sysfs(struct dect_vtrx_group *group)
>> +{
>> +       struct device *dev = &group->dev;
>> +
>> +       dev->type   = &dect_vtrx_group_group;
>> +       dev->class  = dect_class;
>> +       dev->parent = NULL;
>> +
>> +       dev_set_name(dev, "%s", group->name);
>> +       dev_set_drvdata(dev, group);
>> +
>> +       return device_register(dev);
>> +}
>> +
>> +static ssize_t store_new_group(struct class *dev, struct 
>> class_attribute *attr,
>> +                              const char *buf, size_t count)
>> +{
>> +       char name[16];
>> +
>> +       sscanf(buf, "%16s", name);
>> +       if (!dect_vtrx_group_init(name))
>> +               return -ENOMEM;
>> +       return count;
>> +}
>> +
>> +static CLASS_ATTR(new_group, S_IWUSR, NULL, store_new_group);
>> +
>> +void dect_vtrx_group_unregister_sysfs(struct dect_vtrx_group *group)
>> +{
>> +       device_del(&group->dev);
>> +}
>> +
>> +int dect_vtrx_sysfs_init(void)
>> +{
>> +       int err;
>> +
>> +       dect_class = class_create(THIS_MODULE, "dect");
>> +       if (dect_class == NULL)
>> +               return -ENOMEM;
>> +
>> +       err = class_create_file(dect_class, &class_attr_new_group);
>> +       if (err < 0)
>> +               class_destroy(dect_class);
>> +
>> +       return err;
>> +}
>> +
>> +void dect_vtrx_sysfs_exit(void)
>> +{
>> +       class_remove_file(dect_class, &class_attr_new_group);
>> +       class_destroy(dect_class);
>> +}
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/vtrx.c 
>> b/target/linux/generic/files/drivers/dect/vtrx/vtrx.c
>> new file mode 100644
>> index 0000000..d6a9084
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/vtrx.c
>> @@ -0,0 +1,397 @@
>> +/*
>> + * DECT virtual transceiver
>> + *
>> + * Copyright (c) 2010 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#define DEBUG
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/kobject.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/skbuff.h>
>> +#include <net/dect/transceiver.h>
>> +#include "vtrx.h"
>> +
>> +#define vtrx_debug(vtrx, fmt, args...) \
>> +       pr_debug("vtrx %s: " fmt, (vtrx)->trx->name, ## args)
>> +
>> +#define DECT_SLOTS_PER_SECOND  (DECT_FRAMES_PER_SECOND * 
>> DECT_FRAME_SIZE)
>> +#define DECT_VTRX_RATE         (NSEC_PER_SEC / DECT_SLOTS_PER_SECOND)
>> +#define DECT_VTRX_DEFAULT_TRX  2
>> +
>> +#define DECT_WAVELEN_SCALE     13
>> +#define DECT_WAVELEN           160 /* mm */
>> +
>> +struct dect_skb_vtrx_cb {
>> +       struct dect_vtrx        *vtrx;
>> +       u8                      rssi;
>> +       u8                      carrier;
>> +};
>> +
>> +static LIST_HEAD(vtrx_groups);
>> +
>> +static inline struct dect_skb_vtrx_cb *DECT_VTRX_CB(const struct 
>> sk_buff *skb)
>> +{
>> +       BUILD_BUG_ON(sizeof(struct dect_skb_vtrx_cb) > 
>> sizeof(skb->cb));
>> +       return (struct dect_skb_vtrx_cb *)skb->cb;
>> +}
>> +
>> +static unsigned int dect_vtrx_distance(const struct dect_vtrx *vtrx1,
>> +                                      const struct dect_vtrx *vtrx2)
>> +{
>> +       int dx, dy;
>> +
>> +       dx = vtrx1->pos_x - vtrx2->pos_x;
>> +       dy = vtrx1->pos_y - vtrx2->pos_y;
>> +
>> +       return int_sqrt(dx * dx + dy * dy);
>> +}
>> +
>> +static u8 dect_vtrx_receive_rssi(const struct dect_vtrx *rx_vtrx,
>> +                                const struct sk_buff *skb)
>> +{
>> +       const struct dect_vtrx *tx_vtrx = DECT_VTRX_CB(skb)->vtrx;
>> +       unsigned int distance;
>> +       u64 rx_power, tmp;
>> +       int dbm = 0;
>> +
>> +       distance = dect_vtrx_distance(rx_vtrx, tx_vtrx);
>> +       if (distance == 0)
>> +               goto out;
>> +
>> +       tmp = 1000 * (DECT_WAVELEN << DECT_WAVELEN_SCALE) / (4 * 3141 
>> * distance);
>> +       rx_power = (tx_vtrx->tx_power * tmp * tmp) >> (2 * 
>> DECT_WAVELEN_SCALE);
>> +       dbm = dect_mw_to_dbm(rx_power);
>> +out:
>> +       if (dbm > -33)
>> +               dbm = -33;
>> +
>> +       return dect_dbm_to_rssi(dbm);
>> +}
>> +
>> +static void dect_vtrx_process_slot(struct dect_vtrx_group *group,
>> +                                  struct dect_vtrx *vtrx)
>> +{
>> +       struct dect_transceiver_event *event;
>> +       struct dect_transceiver_slot *ts;
>> +       struct dect_transceiver *trx = vtrx->trx;
>> +       struct sk_buff *skb, *best;
>> +       u8 slot = group->slot, rcvslot;
>> +       u8 rssi, best_rssi = 0;
>> +
>> +       event = dect_transceiver_event(trx, slot % 12, slot);
>> +       if (event == NULL)
>> +               return;
>> +
>> +       if (trx->state == DECT_TRANSCEIVER_UNLOCKED ||
>> +           trx->state == DECT_TRANSCEIVER_LOCK_PENDING)
>> +               rcvslot = DECT_SCAN_SLOT;
>> +       else
>> +               rcvslot = slot;
>> +
>> +       rssi = dect_dbm_to_rssi(-80);
>> +       best = NULL;
>> +
>> +       ts = &trx->slots[rcvslot];
>> +       if (ts->state != DECT_SLOT_RX &&
>> +           ts->state != DECT_SLOT_SCANNING)
>> +               goto queue;
>> +
>> +       skb_queue_walk(&group->txq[slot], skb) {
>> +               if (DECT_VTRX_CB(skb)->carrier != ts->chd.carrier)
>> +                       continue;
>> +
>> +               rssi = dect_vtrx_receive_rssi(vtrx, skb);
>> +               if (best == NULL || rssi > best_rssi) {
>> +                       best      = skb;
>> +                       best_rssi = rssi;
>> +               }
>> +       }
>> +
>> +       if (best == NULL)
>> +               goto rssi;
>> +       rssi = best_rssi;
>> +
>> +       skb = skb_clone(best, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               goto rssi;
>> +
>> +       DECT_TRX_CB(skb)->trx  = trx;
>> +       DECT_TRX_CB(skb)->slot = rcvslot;
>> +       DECT_TRX_CB(skb)->csum = DECT_CHECKSUM_A_CRC_OK | 
>> DECT_CHECKSUM_X_CRC_OK;
>> +       DECT_TRX_CB(skb)->rssi = rssi;
>> +       __skb_queue_tail(&event->rx_queue, skb);
>> +
>> +       ts->rx_bytes += skb->len;
>> +       ts->rx_packets++;
>> +rssi:
>> +       ts->rssi = dect_average_rssi(ts->rssi, rssi);
>> +       dect_transceiver_record_rssi(event, rcvslot, rssi);
>> +queue:
>> +       if (rcvslot != slot && best == NULL)
>> +               dect_release_transceiver_event(event);
>> +       else
>> +               dect_transceiver_queue_event(trx, event);
>> +}
>> +
>> +static enum hrtimer_restart dect_vtrx_timer(struct hrtimer *timer)
>> +{
>> +       struct dect_vtrx_group *group = container_of(timer, struct 
>> dect_vtrx_group, timer);
>> +       struct dect_vtrx *vtrx;
>> +       ktime_t time;
>> +
>> +       list_for_each_entry(vtrx, &group->act_list, list)
>> +               dect_vtrx_process_slot(group, vtrx);
>> +
>> +       skb_queue_purge(&group->txq[group->slot]);
>> +       group->slot = dect_next_slotnum(group->slot);
>> +
>> +       time = ktime_set(0, DECT_VTRX_RATE);
>> +       hrtimer_forward(timer, hrtimer_cb_get_time(timer), time);
>> +
>> +       return HRTIMER_RESTART;
>> +}
>> +
>> +/*
>> + * Transceiver operations
>> + */
>> +
>> +static void dect_vtrx_enable(const struct dect_transceiver *trx)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +       struct dect_vtrx_group *group = vtrx->group;
>> +       ktime_t time;
>> +
>> +       vtrx_debug(vtrx, "enable");
>> +       if (list_empty(&group->act_list)) {
>> +               time = ktime_set(0, DECT_VTRX_RATE);
>> +               hrtimer_start(&group->timer, time, HRTIMER_MODE_ABS);
>> +       }
>> +       list_move_tail(&vtrx->list, &group->act_list);
>> +}
>> +
>> +static void dect_vtrx_disable(const struct dect_transceiver *trx)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +       struct dect_vtrx_group *group = vtrx->group;
>> +
>> +       vtrx_debug(vtrx, "disable");
>> +       list_move_tail(&vtrx->list, &group->trx_list);
>> +       if (list_empty(&group->act_list))
>> +               hrtimer_cancel(&group->timer);
>> +}
>> +
>> +static void dect_vtrx_confirm(const struct dect_transceiver *trx)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "confirm");
>> +}
>> +
>> +static void dect_vtrx_unlock(const struct dect_transceiver *trx)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "unlock");
>> +}
>> +
>> +static void dect_vtrx_lock(const struct dect_transceiver *trx, u8 
>> slot)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "lock");
>> +}
>> +
>> +static void dect_vtrx_set_mode(const struct dect_transceiver *trx,
>> +                              const struct dect_channel_desc *chd,
>> +                              enum dect_slot_states mode)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "set_mode: slot: %u mode: %u",
>> +                  chd->slot, mode);
>> +}
>> +
>> +static void dect_vtrx_set_carrier(const struct dect_transceiver *trx,
>> +                                 u8 slot, u8 carrier)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "set carrier: slot: %u carrier: %u\n",
>> +                  slot, carrier);
>> +}
>> +
>> +static u64 dect_vtrx_set_band(const struct dect_transceiver *trx,
>> +                             const struct dect_band *band)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +
>> +       vtrx_debug(vtrx, "set band: %u\n", band->band);
>> +       return band->carriers;
>> +}
>> +
>> +static void dect_vtrx_tx(const struct dect_transceiver *trx, struct 
>> sk_buff *skb)
>> +{
>> +       struct dect_vtrx *vtrx = dect_transceiver_priv(trx);
>> +       struct dect_vtrx_group *group = vtrx->group;
>> +       u8 slot = DECT_TRX_CB(skb)->slot;
>> +
>> +       vtrx_debug(vtrx, "vtrx tx: slot: %u skb: %p\n", slot, skb);
>> +       DECT_VTRX_CB(skb)->vtrx    = vtrx;
>> +       DECT_VTRX_CB(skb)->rssi    = vtrx->tx_power;
>> +       DECT_VTRX_CB(skb)->carrier = trx->slots[slot].chd.carrier;
>> +       skb_queue_tail(&group->txq[slot], skb);
>> +}
>> +
>> +static const struct dect_transceiver_ops vtrx_transceiver_ops = {
>> +       .name                   = "vtrx",
>> +       .eventrate              = 1,
>> +       .latency                = 1,
>> +       .enable                 = dect_vtrx_enable,
>> +       .disable                = dect_vtrx_disable,
>> +       .confirm                = dect_vtrx_confirm,
>> +       .unlock                 = dect_vtrx_unlock,
>> +       .lock                   = dect_vtrx_lock,
>> +       .set_mode               = dect_vtrx_set_mode,
>> +       .set_carrier            = dect_vtrx_set_carrier,
>> +       .set_band               = dect_vtrx_set_band,
>> +       .tx                     = dect_vtrx_tx,
>> +       .destructor             = dect_transceiver_free,
>> +};
>> +
>> +int dect_vtrx_init(struct dect_vtrx_group *group)
>> +{
>> +       struct dect_transceiver *trx;
>> +       struct dect_vtrx *vtrx;
>> +       int err;
>> +
>> +       trx = dect_transceiver_alloc(&vtrx_transceiver_ops, 
>> sizeof(*vtrx));
>> +       if (trx == NULL)
>> +               return -ENOMEM;
>> +
>> +       err = dect_register_transceiver(trx);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       vtrx = dect_transceiver_priv(trx);
>> +       vtrx->group     = group;
>> +       vtrx->trx       = trx;
>> +       vtrx->tx_power  = 2 * DECT_VTRX_POWER_SCALE;
>> +       list_add_tail(&vtrx->list, &group->trx_list);
>> +
>> +       dect_vtrx_register_sysfs(vtrx);
>> +       return 0;
>> +
>> +err1:
>> +       dect_transceiver_free(trx);
>> +       return err;
>> +}
>> +
>> +void dect_vtrx_free(struct dect_vtrx *vtrx)
>> +{
>> +       dect_vtrx_unregister_sysfs(vtrx);
>> +       dect_unregister_transceiver(vtrx->trx);
>> +}
>> +
>> +struct dect_vtrx_group *dect_vtrx_group_init(const char *name)
>> +{
>> +       struct dect_vtrx_group *group;
>> +       unsigned int i;
>> +       int err;
>> +
>> +       group = kzalloc(sizeof(*group), GFP_KERNEL);
>> +       if (group == NULL)
>> +               goto err1;
>> +
>> +       strlcpy(group->name, name, sizeof(group->name));
>> +       INIT_LIST_HEAD(&group->trx_list);
>> +       INIT_LIST_HEAD(&group->act_list);
>> +       hrtimer_init(&group->timer, CLOCK_MONOTONIC, 
>> HRTIMER_MODE_ABS);
>> +       group->timer.function = dect_vtrx_timer;
>> +
>> +       for (i = 0; i < ARRAY_SIZE(group->txq); i++)
>> +               skb_queue_head_init(&group->txq[i]);
>> +
>> +       err = dect_vtrx_group_register_sysfs(group);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       list_add_tail(&group->list, &vtrx_groups);
>> +       return group;
>> +
>> +err2:
>> +       kfree(group);
>> +err1:
>> +       return NULL;
>> +}
>> +
>> +void dect_vtrx_group_free(struct dect_vtrx_group *group)
>> +{
>> +       struct dect_vtrx *vtrx, *next;
>> +       unsigned int i;
>> +
>> +       list_for_each_entry_safe(vtrx, next, &group->act_list, list)
>> +               dect_vtrx_free(vtrx);
>> +       list_for_each_entry_safe(vtrx, next, &group->trx_list, list)
>> +               dect_vtrx_free(vtrx);
>> +
>> +       dect_vtrx_group_unregister_sysfs(group);
>> +
>> +       for (i = 0; i < ARRAY_SIZE(group->txq); i++)
>> +               __skb_queue_purge(&group->txq[i]);
>> +
>> +       kfree(group);
>> +}
>> +
>> +static int __init vtrx_init(void)
>> +{
>> +       struct dect_vtrx_group *group;
>> +       unsigned int i;
>> +       int err;
>> +
>> +       err = dect_vtrx_sysfs_init();
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       group = dect_vtrx_group_init("group-1");
>> +       if (group == NULL) {
>> +               err = -ENOMEM;
>> +               goto err2;
>> +       }
>> +
>> +       for (i = 0; i < DECT_VTRX_DEFAULT_TRX; i++) {
>> +               err = dect_vtrx_init(group);
>> +               if (err < 0)
>> +                       goto err3;
>> +       }
>> +
>> +       return 0;
>> +
>> +err3:
>> +       dect_vtrx_group_free(group);
>> +err2:
>> +       dect_vtrx_sysfs_exit();
>> +err1:
>> +       return err;
>> +}
>> +
>> +static void __exit vtrx_exit(void)
>> +{
>> +       struct dect_vtrx_group *group, *next;
>> +
>> +       list_for_each_entry_safe(group, next, &vtrx_groups, list)
>> +               dect_vtrx_group_free(group);
>> +
>> +       dect_vtrx_sysfs_exit();
>> +}
>> +
>> +module_init(vtrx_init);
>> +module_exit(vtrx_exit);
>> +
>> +MODULE_LICENSE("GPL");
>> diff --git a/target/linux/generic/files/drivers/dect/vtrx/vtrx.h 
>> b/target/linux/generic/files/drivers/dect/vtrx/vtrx.h
>> new file mode 100644
>> index 0000000..67aaba6
>> --- /dev/null
>> +++ b/target/linux/generic/files/drivers/dect/vtrx/vtrx.h
>> @@ -0,0 +1,42 @@
>> +#ifndef _DECT_VTRX_H
>> +#define _DECT_VTRX_H
>> +
>> +struct dect_vtrx_group {
>> +       struct list_head        list;
>> +       struct device           dev;
>> +       char                    name[16];
>> +       struct hrtimer          timer;
>> +       struct list_head        trx_list;
>> +       struct list_head        act_list;
>> +       struct sk_buff_head     txq[DECT_FRAME_SIZE];
>> +       unsigned int            slot;
>> +};
>> +
>> +struct dect_vtrx {
>> +       struct list_head        list;
>> +       struct device           dev;
>> +       struct dect_vtrx_group  *group;
>> +       struct dect_transceiver *trx;
>> +       u64                     tx_power;
>> +       unsigned int            pos_x;
>> +       unsigned int            pos_y;
>> +};
>> +
>> +extern struct dect_vtrx_group *dect_vtrx_group_init(const char 
>> *name);
>> +extern void    dect_vtrx_group_free(struct dect_vtrx_group *group);
>> +extern int     dect_vtrx_group_register_sysfs(struct dect_vtrx_group 
>> *group);
>> +extern void    dect_vtrx_group_unregister_sysfs(struct 
>> dect_vtrx_group *group);
>> +
>> +extern int     dect_vtrx_register_sysfs(struct dect_vtrx *vtrx);
>> +extern void    dect_vtrx_unregister_sysfs(struct dect_vtrx *vtrx);
>> +extern int     dect_vtrx_init(struct dect_vtrx_group *group);
>> +extern void    dect_vtrx_free(struct dect_vtrx *vtrx);
>> +
>> +extern int     dect_vtrx_sysfs_init(void);
>> +extern void    dect_vtrx_sysfs_exit(void);
>> +
>> +#define DECT_VTRX_POWER_SCALE          10000000000ULL
>> +
>> +extern int     dect_mw_to_dbm(u64 mw);
>> +
>> +#endif /* _DECT_VTRX_H */
>> diff --git a/target/linux/generic/files/include/linux/dect.h 
>> b/target/linux/generic/files/include/linux/dect.h
>> new file mode 100644
>> index 0000000..7366289
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/linux/dect.h
>> @@ -0,0 +1,167 @@
>> +#ifndef _LINUX_DECT_H
>> +#define _LINUX_DECT_H
>> +
>> +#define DECTNAMSIZ     16
>> +
>> +#include <linux/types.h>
>> +#include <linux/socket.h>
>> +
>> +/* these have to be macros in order to be usable for module aliases 
>> */
>> +#define DECT_RAW       0       /* raw frames */
>> +#define DECT_B_SAP     1       /* DLC Broadcast Service */
>> +#define DECT_S_SAP     2       /* DLC Data Link Service */
>> +#define DECT_LU1_SAP   3       /* LU1 sockets */
>> +#define DECT_PROTO_NUM 4
>> +
>> +/**
>> + * struct sockaddr_dect
>> + *
>> + * @dect_family:       address family (AF_DECT)
>> + * @dect_index:                cluster index
>> + */
>> +struct sockaddr_dect {
>> +       sa_family_t     dect_family;
>> +       int             dect_index;
>> +};
>> +
>> +/* raw sockets */
>> +
>> +#define DECT_RAW_AUXDATA       0
>> +
>> +/**
>> + * struct dect_raw_auxdata - raw socket auxiliary frame data
>> + *
>> + * @mfn:       multi-frame number
>> + * @frame:     frame number
>> + * @slot:      slot numer
>> + * @rssi:      receive signal strength indicator
>> + */
>> +struct dect_raw_auxdata {
>> +       __u32           mfn;
>> +       __u8            frame;
>> +       __u8            slot;
>> +       __u8            rssi;
>> +};
>> +
>> +#define DECT_BSAP_AUXDATA      0
>> +
>> +/**
>> + * struct dect_bsap_auxdata
>> + *
>> + * @long_page: message contains a long page
>> + */
>> +struct dect_bsap_auxdata {
>> +       __u8            long_page;
>> +};
>> +
>> +/**
>> + * enum dect_sapis - S SAP Identifier
>> + *
>> + * @DECT_SAPI_CO_SIGNALLING:   connection oriented signalling
>> + * @DECT_SAPI_CL_SIGNALLING:   connectionless signalling
>> + * @DECT_SAPI_ANY:             wildcard
>> + */
>> +enum dect_sapis {
>> +       DECT_SAPI_CO_SIGNALLING = 0,
>> +       DECT_SAPI_CL_SIGNALLING = 3,
>> +       DECT_SAPI_ANY           = 7,
>> +};
>> +
>> +/**
>> + * enum dect_llns - Logical Link Numbers
>> + *
>> + * @DECT_LLN_CLASS_U:          Class U operation
>> + * @DECT_LLN_CLASS_A:          Class A operation
>> + * @DECT_LLN_ASSIGNABLE*:      Assignable LLN (class B operation)
>> + * @DECT_LLN_UNASSIGNED:       LLN unassigned (class B operation
>> + * @DECT_LLN_ANY:              wildcard
>> + */
>> +enum dect_llns {
>> +       DECT_LLN_CLASS_U        = 0,
>> +       DECT_LLN_CLASS_A        = 1,
>> +       DECT_LLN_ASSIGNABLE_MIN = 2,
>> +       DECT_LLN_ASSIGNABLE_MAX = 6,
>> +       DECT_LLN_UNASSIGNED     = 7,
>> +       DECT_LLN_ANY            = 15,
>> +};
>> +
>> +/**
>> + * struct sockaddr_dect_ssap
>> + *
>> + * @dect_family:       family (AF_DECT)
>> + * @dect_lln:          logical link number
>> + * @dect_sapi:         service access point identifier
>> + * @dect_class:                class A/B
>> + * @dect_index:                cluster index
>> + * @dect_ari:          ARI
>> + * @dect_pmid:         PMID
>> + * @dect_lcn:          logical connection number
>> + */
>> +struct sockaddr_dect_ssap {
>> +       sa_family_t     dect_family;
>> +       __u8            dect_lln:4,
>> +                       dect_sapi:3;
>> +       __u8            dect_class;
>> +       int             dect_index;
>> +       __u64           dect_ari:40,
>> +                       dect_pmid:20,
>> +                       dect_lcn:3;
>> +};
>> +
>> +/* S-SAP primitives */
>> +#define DECT_DL_ENC_KEY        1
>> +#define DECT_DL_ENCRYPT        2
>> +
>> +enum dect_cipher_states {
>> +       DECT_CIPHER_DISABLED,
>> +       DECT_CIPHER_ENABLED,
>> +};
>> +
>> +enum dect_mac_service_types {
>> +       DECT_SERVICE_IN_MIN_DELAY               = 0x0,
>> +       DECT_SERVICE_IPX_ENCODED_PROTECTED      = 0x1,
>> +       DECT_SERVICE_IN_NORMAL_DELAY            = 0x2,
>> +       DECT_SERVICE_UNKNOWN                    = 0x4,
>> +       DECT_SERVICE_C_CHANNEL_ONLY             = 0x5,
>> +       DECT_SERVICE_IP_ERROR_DETECTION         = 0x10,
>> +       DECT_SERVICE_IPQ_ERROR_DETECTION        = 0x14,
>> +       /* Lifetime encoded in low three bits */
>> +       DECT_SERVICE_IP_ERROR_CORRECTION        = 0x18,
>> +       DECT_SERVICE_IPQ_ERROR_CORRECTION       = 0x38,
>> +};
>> +
>> +/**
>> + * struct dect_dl_encrypt - DL_ENCRYPT primitive arguments
>> + *
>> + * @status:            desired/achieved encryption status
>> + */
>> +struct dect_dl_encrypt {
>> +       enum dect_cipher_states status;
>> +};
>> +
>> +/**
>> + * struct sockaddr_dect_lu - DLC U-plane LUx service instance address
>> + *
>> + * @dect_family:       address family (AF_DECT)
>> + * @dect_mci:          MAC Connection Identifier
>> + */
>> +struct sockaddr_dect_lu {
>> +       sa_family_t     dect_family;
>> +       int             dect_index;
>> +       __u64           dect_ari:40,
>> +                       dect_pmid:20,
>> +                       dect_lcn:3;
>> +};
>> +
>> +/* LU1 SAP */
>> +
>> +#define DECT_LU1_QUEUE_STATS   0
>> +
>> +struct dect_lu1_queue_stats {
>> +       __u32           rx_bytes;
>> +       __u32           rx_underflow;
>> +       __u32           tx_bytes;
>> +       __u32           tx_underflow;
>> +};
>> +
>> +#endif /* _LINUX_DECT_H */
>> diff --git a/target/linux/generic/files/include/linux/dect_netlink.h 
>> b/target/linux/generic/files/include/linux/dect_netlink.h
>> new file mode 100644
>> index 0000000..df170fb
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/linux/dect_netlink.h
>> @@ -0,0 +1,395 @@
>> +#ifndef _LINUX_DECT_NETLINK_H
>> +#define _LINUX_DECT_NETLINK_H
>> +
>> +struct dectmsg {
>> +       int     dm_index;
>> +};
>> +
>> +enum dect_nlgroups {
>> +       DECTNLGRP_NONE,
>> +       DECTNLGRP_TRANSCEIVER,
>> +       DECTNLGRP_CELL,
>> +       DECTNLGRP_CLUSTER,
>> +       DECTNLGRP_LLME,
>> +       __DECTNLGRP_MAX
>> +};
>> +#define DECTNLGRP_MAX          (__DECTNLGRP_MAX - 1)
>> +
>> +enum dect_netlink_msg_types {
>> +       DECT_MSG_BASE = 0x10,
>> +       DECT_NEW_TRANSCEIVER,
>> +       DECT_DEL_TRANSCEIVER,
>> +       DECT_GET_TRANSCEIVER,
>> +       DECT_NEW_CELL,
>> +       DECT_DEL_CELL,
>> +       DECT_GET_CELL,
>> +       DECT_NEW_CLUSTER,
>> +       DECT_DEL_CLUSTER,
>> +       DECT_GET_CLUSTER,
>> +       DECT_LLME_MSG,
>> +       __DECT_MSG_MAX
>> +};
>> +#define DECT_MSG_MAX           (__DECT_MSG_MAX - 1)
>> +
>> +#define DECT_NR_MSGTYPES       (DECT_MSG_MAX + 1 - DECT_MSG_BASE)
>> +
>> +enum dect_list_attrs {
>> +       DECTA_LIST_UNSPEC,
>> +       DECTA_LIST_ELEM,
>> +       __DECTA_LIST_MAX
>> +};
>> +#define DECTA_LIST_MAX         (__DECTA_LIST_MAX - 1)
>> +
>> +enum dect_slot_states {
>> +       DECT_SLOT_IDLE,
>> +       DECT_SLOT_SCANNING,
>> +       DECT_SLOT_RX,
>> +       DECT_SLOT_TX,
>> +};
>> +
>> +enum dect_slot_flags {
>> +       DECT_SLOT_SYNC                  = 0x1,
>> +       DECT_SLOT_CIPHER                = 0x2,
>> +};
>> +
>> +/**
>> + * enum dect_packet_types - DECT Physical Packet Types
>> + *
>> + * @DECT_PACKET_P00:   short physical packet P00, 96 bits, A-field 
>> only
>> + * @DECT_PACKET_P08:   low capacity physical packet P08j, 180 bits
>> + * @DECT_PACKET_P32:   basic physical packet P32, 420 bits
>> + * @DECT_PACKET_P80:   high capacity physical packet P80, 900 bits
>> + * @DECT_PACKET_P640j: variable capacity packet P640j, 712 bits
>> + * @DECT_PACKET_P672j: variable capacity packet P640j, 744 bits
>> + */
>> +enum dect_packet_types {
>> +       DECT_PACKET_P00,
>> +       DECT_PACKET_P08,
>> +       DECT_PACKET_P32,
>> +       DECT_PACKET_P80,
>> +       DECT_PACKET_P640j,
>> +       DECT_PACKET_P672j,
>> +       __DECT_PACKET_MAX
>> +};
>> +#define DECT_PACKET_MAX         (__DECT_PACKET_MAX - 1)
>> +
>> +#define DECT_PHASE_OFFSET_SCALE                1024
>> +
>> +enum dect_slot_attrs {
>> +       DECTA_SLOT_UNSPEC,
>> +       DECTA_SLOT_NUM,
>> +       DECTA_SLOT_STATE,
>> +       DECTA_SLOT_FLAGS,
>> +       DECTA_SLOT_PACKET,
>> +       DECTA_SLOT_CARRIER,
>> +       DECTA_SLOT_FREQUENCY,
>> +       DECTA_SLOT_PHASEOFF,
>> +       DECTA_SLOT_RSSI,
>> +       DECTA_SLOT_RX_PACKETS,
>> +       DECTA_SLOT_RX_BYTES,
>> +       DECTA_SLOT_RX_A_CRC_ERRORS,
>> +       DECTA_SLOT_RX_X_CRC_ERRORS,
>> +       DECTA_SLOT_RX_Z_CRC_ERRORS,
>> +       DECTA_SLOT_TX_PACKETS,
>> +       DECTA_SLOT_TX_BYTES,
>> +       __DECTA_SLOT_MAX
>> +};
>> +#define DECTA_SLOT_MAX                 (__DECTA_SLOT_MAX - 1)
>> +
>> +enum dect_transceiver_stats_attrs {
>> +       DECTA_TRANSCEIVER_STATS_UNSPEC,
>> +       DECTA_TRANSCEIVER_STATS_EVENT_BUSY,
>> +       DECTA_TRANSCEIVER_STATS_EVENT_LATE,
>> +       __DECTA_TRANSCEIVER_STATS_MAX
>> +};
>> +#define DECTA_TRANSCEIVER_STATS_MAX    (__DECTA_TRANSCEIVER_STATS_MAX 
>> - 1)
>> +
>> +/**
>> + * @DECT_TRANSCEIVER_SLOW_HOPPING:     transceiver has slow hopping 
>> radio
>> + */
>> +enum dect_transceiver_features {
>> +       DECT_TRANSCEIVER_SLOW_HOPPING   = 0x1,
>> +};
>> +
>> +enum dect_transceiver_attrs {
>> +       DECTA_TRANSCEIVER_UNSPEC,
>> +       DECTA_TRANSCEIVER_NAME,
>> +       DECTA_TRANSCEIVER_TYPE,
>> +       DECTA_TRANSCEIVER_FEATURES,
>> +       DECTA_TRANSCEIVER_LINK,
>> +       DECTA_TRANSCEIVER_STATS,
>> +       DECTA_TRANSCEIVER_BAND,
>> +       DECTA_TRANSCEIVER_SLOTS,
>> +       __DECTA_TRANSCEIVER_MAX
>> +};
>> +#define DECTA_TRANSCEIVER_MAX          (__DECTA_TRANSCEIVER_MAX - 1)
>> +
>> +enum dect_cell_flags {
>> +       DECT_CELL_CCP           = (1 << 0),
>> +       DECT_CELL_SLAVE         = (1 << 1),
>> +       DECT_CELL_MONITOR       = (1 << 2),
>> +};
>> +
>> +enum dect_cell_attrs {
>> +       DECTA_CELL_UNSPEC,
>> +       DECTA_CELL_NAME,
>> +       DECTA_CELL_FLAGS,
>> +       DECTA_CELL_TRANSCEIVERS,
>> +       DECTA_CELL_CLUSTER,
>> +       __DECTA_CELL_MAX
>> +};
>> +#define DECTA_CELL_MAX         (__DECTA_CELL_MAX - 1)
>> +
>> +enum dect_mbc_state {
>> +       DECT_MBC_NONE,
>> +       DECT_MBC_INITIATED,
>> +       DECT_MBC_ESTABLISHED,
>> +       DECT_MBC_RELEASED,
>> +};
>> +
>> +enum dect_mbc_tb_attrs {
>> +       DECTA_MBC_TB_UNSPEC,
>> +       DECTA_MBC_TB_LBN,
>> +       DECTA_MBC_TB_ECN,
>> +       DECTA_MBC_TB_CELL,
>> +       DECTA_MBC_TB_RX_SLOT,
>> +       DECTA_MBC_TB_TX_SLOT,
>> +       __DECTA_MBC_TB_MAX,
>> +};
>> +#define DECTA_MBC_TB_MAX       (__DECTA_MBC_TB_MAX - 1)
>> +
>> +enum dect_mbc_stats_attrs {
>> +       DECTA_MBC_STATS_UNSPEC,
>> +       DECTA_MBC_STATS_CS_RX_BYTES,
>> +       DECTA_MBC_STATS_CS_TX_BYTES,
>> +       DECTA_MBC_STATS_I_RX_BYTES,
>> +       DECTA_MBC_STATS_I_TX_BYTES,
>> +       DECTA_MBC_STATS_HANDOVERS,
>> +       __DECTA_MBC_STATS_MAX,
>> +};
>> +#define DECTA_MBC_STATS_MAX    (__DECTA_MBC_STATS_MAX - 1)
>> +
>> +enum dect_mbc_attrs {
>> +       DECTA_MBC_UNSPEC,
>> +       DECTA_MBC_MCEI,
>> +       DECTA_MBC_SERVICE,
>> +       DECTA_MBC_STATE,
>> +       DECTA_MBC_CIPHER_STATE,
>> +       DECTA_MBC_STATS,
>> +       DECTA_MBC_TBS,
>> +       __DECTA_MBC_MAX,
>> +};
>> +#define DECTA_MBC_MAX          (__DECTA_MBC_MAX - 1)
>> +
>> +enum dect_cluster_attrs {
>> +       DECTA_CLUSTER_UNSPEC,
>> +       DECTA_CLUSTER_NAME,
>> +       DECTA_CLUSTER_MODE,
>> +       DECTA_CLUSTER_PARI,
>> +       DECTA_CLUSTER_CELLS,
>> +       DECTA_CLUSTER_MBCS,
>> +       __DECTA_CLUSTER_MAX
>> +};
>> +#define DECTA_CLUSTER_MAX      (__DECTA_CLUSTER_MAX - 1)
>> +
>> +enum dect_cluster_modes {
>> +       DECT_MODE_FP,
>> +       DECT_MODE_PP,
>> +};
>> +
>> +/**
>> + * DECT ARI classes
>> + *
>> + * @DECT_ARC_A:        Residential and private (PBX) single- and 
>> small multiple cell systems
>> + * @DECT_ARC_B:        Private (PABXs) multiple cell
>> + * @DECT_ARC_C: Public single and multiple cell systems
>> + * @DECT_ARC_D: Public DECT access to a GSM network
>> + * @DECT_ARC_E: PP to PP direct communication (private)
>> + */
>> +enum dect_ari_classes {
>> +       DECT_ARC_A,
>> +       DECT_ARC_B,
>> +       DECT_ARC_C,
>> +       DECT_ARC_D,
>> +       DECT_ARC_E,
>> +};
>> +
>> +enum dect_ari_attrs {
>> +       DECTA_ARI_UNSPEC,
>> +       DECTA_ARI_CLASS,
>> +       DECTA_ARI_FPN,
>> +       DECTA_ARI_FPS,
>> +       DECTA_ARI_EMC,
>> +       DECTA_ARI_EIC,
>> +       DECTA_ARI_POC,
>> +       DECTA_ARI_GOP,
>> +       DECTA_ARI_FIL,
>> +       __DECTA_ARI_MAX
>> +};
>> +#define DECTA_ARI_MAX          (__DECTA_ARI_MAX - 1)
>> +
>> +enum decta_sari_attrs {
>> +       DECTA_SARI_UNSPEC,
>> +       DECTA_SARI_ARI,
>> +       DECTA_SARI_BLACK,
>> +       DECTA_SARI_TARI,
>> +       __DECTA_SARI_MAX
>> +};
>> +#define DECTA_SARI_MAX         (__DECTA_SARI_MAX - 1)
>> +
>> +enum dect_fixed_part_capabilities {
>> +       DECT_FPC_EXTENDED_FP_INFO               = 0x80000,
>> +       DECT_FPC_DOUBLE_DUPLEX_BEARER_CONNECTION= 0x40000,
>> +       DECT_FPC_RESERVED                       = 0x20000,
>> +       DECT_FPC_DOUBLE_SLOT                    = 0x10000,
>> +       DECT_FPC_HALF_SLOT                      = 0x08000,
>> +       DECT_FPC_FULL_SLOT                      = 0x04000,
>> +       DECT_FPC_FREQ_CONTROL                   = 0x02000,
>> +       DECT_FPC_PAGE_REPETITION                = 0x01000,
>> +       DECT_FPC_CO_SETUP_ON_DUMMY              = 0x00800,
>> +       DECT_FPC_CL_UPLINK                      = 0x00400,
>> +       DECT_FPC_CL_DOWNLINK                    = 0x00200,
>> +       DECT_FPC_BASIC_A_FIELD_SETUP            = 0x00100,
>> +       DECT_FPC_ADV_A_FIELD_SETUP              = 0x00080,
>> +       DECT_FPC_B_FIELD_SETUP                  = 0x00040,
>> +       DECT_FPC_CF_MESSAGES                    = 0x00020,
>> +       DECT_FPC_IN_MIN_DELAY                   = 0x00010,
>> +       DECT_FPC_IN_NORM_DELAY                  = 0x00008,
>> +       DECT_FPC_IP_ERROR_DETECTION             = 0x00004,
>> +       DECT_FPC_IP_ERROR_CORRECTION            = 0x00002,
>> +       DECT_FPC_MULTIBEARER_CONNECTIONS        = 0x00001,
>> +};
>> +
>> +enum dect_higher_layer_capabilities {
>> +       DECT_HLC_ADPCM_G721_VOICE               = 0x8000,
>> +       DECT_HLC_GAP_PAP_BASIC_SPEECH           = 0x4000,
>> +       DECT_HLC_NON_VOICE_CIRCUIT_SWITCHED     = 0x2000,
>> +       DECT_HLC_NON_VOICE_PACKET_SWITCHED      = 0x1000,
>> +       DECT_HLC_STANDARD_AUTHENTICATION        = 0x0800,
>> +       DECT_HLC_STANDARD_CIPHERING             = 0x0400,
>> +       DECT_HLC_LOCATION_REGISTRATION          = 0x0200,
>> +       DECT_HLC_SIM_SERVICES                   = 0x0100,
>> +       DECT_HLC_NON_STATIC_FIXED_PART          = 0x0080,
>> +       DECT_HLC_CISS_SERVICE                   = 0x0040,
>> +       DECT_HLC_CLMS_SERVICE                   = 0x0020,
>> +       DECT_HLC_COMS_SERVICE                   = 0x0010,
>> +       DECT_HLC_ACCESS_RIGHTS_REQUESTS         = 0x0008,
>> +       DECT_HLC_EXTERNAL_HANDOVER              = 0x0004,
>> +       DECT_HLC_CONNECTION_HANDOVER            = 0x0002,
>> +       DECT_HLC_RESERVED                       = 0x0001,
>> +};
>> +
>> +enum dect_extended_fixed_part_capabilities {
>> +       DECT_EFPC_WRS_MASK                      = 0x1f80,
>> +       DECT_EFPC_WRS_CRFP_HOPS_MASK            = 0x1800,
>> +       DECT_EFPC_WRS_CRFP_HOPS_1               = 0x0000,
>> +       DECT_EFPC_WRS_CRFP_HOPS_2               = 0x0800,
>> +       DECT_EFPC_WRS_CRFP_HOPS_3               = 0x1000,
>> +       DECT_EFPC_WRS_CRFP_HOPS_NONE            = 0x1800,
>> +       DECT_EFPC_WRS_CRFP_ENCRYPTION           = 0x0400,
>> +       DECT_EFPC_WRS_REP_HOPS_MASK             = 0x0300,
>> +       DECT_EFPC_WRS_REP_HOPS_NONE             = 0x0000,
>> +       DECT_EFPC_WRS_REP_HOPS_1                = 0x0100,
>> +       DECT_EFPC_WRS_REP_HOPS_2                = 0x0200,
>> +       DECT_EFPC_WRS_REP_HOPS_3                = 0x0300,
>> +       DECT_EFPC_WRS_REP_INTERLACING           = 0x0080,
>> +       DECT_EFPC_SYNC_MASK                     = 0x0060,
>> +       DECT_EFPC_SYNC_PROLONGED_PREAMBLE       = 0x0020,
>> +       DECT_EFPC_SYNC_RESERVED1                = 0x0010,
>> +       DECT_EFPC_MAC_SUSPEND_RESUME            = 0x0008,
>> +       DECT_EFPC_MAC_IP_Q_SERVICE              = 0x0004,
>> +       DECT_EFPC_EXTENDED_FP_INFO2             = 0x0002,
>> +       DECT_EFPC_RESERVED2                     = 0x0001,
>> +};
>> +
>> +enum dect_extended_higher_layer_capabilities {
>> +       DECT_EHLC_ISDN_DATA_SERVICE             = 0x000001,
>> +       DECT_EHLC_DPRS_FREL                     = 0x000002,
>> +       DECT_EHLC_DPRS_STREAM                   = 0x000004,
>> +       DECT_EHLC_DATA_SERVICE_PROFILE_D        = 0x000008,
>> +       DECT_EHLC_LRMS                          = 0x000010,
>> +       DECT_EHLC_ASYMETRIC_BEARERS             = 0x000040,
>> +       DECT_EHLC_EMERGENCY_CALLS               = 0x000080,
>> +       DECT_EHLC_TPUI_LOCATION_REGISTRATION    = 0x000100,
>> +       DECT_EHLC_GPS_SYNCHRONIZED              = 0x000200,
>> +       DECT_EHLC_ISDN_INTERMEDIATE_SYSTEM      = 0x000400,
>> +       DECT_EHLC_RAP_PART_1_PROFILE            = 0x000800,
>> +       DECT_EHLC_V_24                          = 0x004000,
>> +       DECT_EHLC_PPP                           = 0x008000,
>> +       DECT_EHLC_IP                            = 0x010000,
>> +       DECT_EHLC_TOKEN_RING                    = 0x020000,
>> +       DECT_EHLC_ETHERNET                      = 0x040000,
>> +       DECT_EHLC_IP_ROAMING                    = 0x080000,
>> +       DECT_EHLC_GENERIC_MEDIA_ENCAPSULATION   = 0x100000,
>> +       DECT_EHLC_BASIC_ODAP                    = 0x200000,
>> +       DECT_EHLC_F_MMS_INTERWORKING_PROFILE    = 0x400000,
>> +};
>> +
>> +enum dect_extended_fixed_part_capabilities2 {
>> +       DECT_EFPC2_LONG_SLOT_J640               = 0x800,
>> +       DECT_EFPC2_LONG_SLOT_J672               = 0x400,
>> +       DECT_EFPC2_IP_F                         = 0x200,
>> +       DECT_EFPC2_SI_PF                        = 0x100,
>> +       DECT_EFPC2_GF                           = 0x080,
>> +       DECT_EFPC2_NO_EMISSION_CARRIER          = 0x001,
>> +};
>> +
>> +enum dect_extended_higher_layer_capabilities2 {
>> +       DECT_EHLC2_NG_DECT_PERMANENT_CLIR       = 0x000100,
>> +       DECT_EHLC2_NG_DECT_MULTIPLE_CALLS       = 0x000200,
>> +       DECT_EHLC2_NG_DECT_MULTIPLE_LINES       = 0x000400,
>> +       DECT_EHLC2_EASY_PAIRING                 = 0x000800,
>> +       DECT_EHLC2_LIST_ACCESS_FEATURES         = 0x001000,
>> +       DECT_EHLC2_NO_EMISSION_MODE             = 0x002000,
>> +       DECT_EHLC2_NG_DECT_CALL_DEFLECTION      = 0x004000,
>> +       DECT_EHLC2_NG_DECT_INTRUSION_CALL       = 0x008000,
>> +       DECT_EHLC2_NG_DECT_CONFERENCE_CALL      = 0x010000,
>> +       DECT_EHLC2_NG_DECT_PARALLEL_CALLS       = 0x020000,
>> +       DECT_EHLC2_NG_DECT_CALL_TRANSFER        = 0x040000,
>> +       DECT_EHLC2_NG_DECT_EXTENDED_WIDEBAND    = 0x080000,
>> +       DECT_EHLC2_PACKET_DATA_CATEGORY_MASK    = 0x700000,
>> +       DECT_EHLC2_NG_DECT_WIDEBAND             = 0x800000,
>> +};
>> +
>> +enum dect_mac_info_attrs {
>> +       DECTA_MAC_INFO_UNSPEC,
>> +       DECTA_MAC_INFO_PARI,
>> +       DECTA_MAC_INFO_RPN,
>> +       DECTA_MAC_INFO_RSSI,
>> +       DECTA_MAC_INFO_SARI_LIST,
>> +       DECTA_MAC_INFO_FPC,
>> +       DECTA_MAC_INFO_HLC,
>> +       DECTA_MAC_INFO_EFPC,
>> +       DECTA_MAC_INFO_EHLC,
>> +       DECTA_MAC_INFO_EFPC2,
>> +       DECTA_MAC_INFO_EHLC2,
>> +       DECTA_MAC_INFO_MFN,
>> +       __DECTA_MAC_INFO_MAX
>> +};
>> +#define DECTA_MAC_INFO_MAX     (__DECTA_MAC_INFO_MAX - 1)
>> +
>> +enum dect_llme_ops {
>> +       DECT_LLME_REQUEST,
>> +       DECT_LLME_INDICATE,
>> +       DECT_LLME_RESPONSE,
>> +       DECT_LLME_CONFIRM,
>> +};
>> +
>> +enum dect_llme_msg_types {
>> +       DECT_LLME_SCAN,
>> +       DECT_LLME_MAC_INFO,
>> +       DECT_LLME_MAC_RFP_PRELOAD,
>> +       __DECT_LLME_MAX
>> +};
>> +#define DECT_LLME_MAX          (__DECT_LLME_MAX - 1)
>> +
>> +enum dect_llme_msg_attrs {
>> +       DECTA_LLME_UNSPEC,
>> +       DECTA_LLME_OP,
>> +       DECTA_LLME_TYPE,
>> +       DECTA_LLME_DATA,
>> +       __DECTA_LLME_MAX
>> +};
>> +#define DECTA_LLME_MAX         (__DECTA_LLME_MAX - 1)
>> +
>> +#endif /* _LINUX_DECT_NETLINK_H */
>> diff --git a/target/linux/generic/files/include/net/dect/ccp.h 
>> b/target/linux/generic/files/include/net/dect/ccp.h
>> new file mode 100644
>> index 0000000..5234c7d
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/ccp.h
>> @@ -0,0 +1,110 @@
>> +/*
>> + * DECT MAC Layer - Cell Control Protocol (CCP)
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_CCP
>> +#define _NET_DECT_CCP
>> +
>> +#define DECT_CCP_TIPC_TYPE             TIPC_RESERVED_TYPES
>> +#define DECT_CCP_CELL_PORT             1000
>> +#define DECT_CCP_CLUSTER_PORT_BASE     1000
>> +
>> +enum dect_ccp_primitives {
>> +       /* CCF -> CSF */
>> +       DECT_CCP_SET_MODE,
>> +       DECT_CCP_SCAN,
>> +       DECT_CCP_ENABLE,
>> +       DECT_CCP_PRELOAD,
>> +       DECT_CCP_MAC_INFO_IND,
>> +       DECT_CCP_PAGE_REQ,
>> +       DECT_CCP_TBC_ESTABLISH_REQ,
>> +       DECT_CCP_TBC_ESTABLISH_RES,
>> +       DECT_CCP_TBC_DATA_REQ,
>> +       DECT_CCP_TBC_DIS_REQ,
>> +       DECT_CCP_TBC_ENC_KEY_REQ,
>> +       DECT_CCP_TBC_ENC_EKS_REQ,
>> +       /* CSF -> CCF */
>> +       DECT_CCP_TBC_ESTABLISH_IND,
>> +       DECT_CCP_TBC_ESTABLISH_CFM,
>> +       DECT_CCP_TBC_EVENT_IND,
>> +       DECT_CCP_TBC_DATA_IND,
>> +       DECT_CCP_TBC_DIS_IND,
>> +};
>> +
>> +struct dect_ccp_msg_hdr {
>> +       u8              primitive;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_ari {
>> +       __be64          ari;
>> +};
>> +
>> +struct dect_ccp_mode_msg {
>> +       u8              mode;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_scan_msg {
>> +       __be64          ari;
>> +       __be64          ari_mask;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_sysinfo_msg {
>> +       __be64          pari;
>> +       __be64          sari[DECT_SARI_CYCLE_MAX];
>> +       __be64          fpc;
>> +       __be64          hlc;
>> +       __be64          efpc;
>> +       __be32          mfn;
>> +       u8              num_saris;
>> +       u8              rpn;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_page_msg {
>> +       u8              fast_page;
>> +       u8              long_page;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_tbc_msg {
>> +       __be32          tbei;
>> +       __be32          pmid;
>> +       __be64          ari;
>> +       u8              ecn;
>> +       u8              data;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_enc_key_msg {
>> +       __be64          key;
>> +} __attribute__((packed));
>> +
>> +struct dect_ccp_data_msg {
>> +       u8              channel;
>> +       u8              data[];
>> +} __attribute__((packed));
>> +
>> +#ifdef CONFIG_DECT_CCP
>> +extern int dect_ccp_cluster_init(struct dect_cluster *cl);
>> +extern void dect_ccp_cluster_shutdown(struct dect_cluster *cl);
>> +
>> +extern struct dect_cluster_handle *dect_ccp_cell_init(struct 
>> dect_cell *cell,
>> +                                                     u8 clindex);
>> +#else
>> +static inline int dect_ccp_cluster_init(struct dect_cluster *cl)
>> +{
>> +       return 0;
>> +}
>> +
>> +static inline void dect_ccp_cluster_shutdown(struct dect_cluster *cl)
>> +{
>> +       return;
>> +}
>> +
>> +static inline struct dect_cluster_handle *
>> +dect_ccp_cell_init(struct dect_cell *cell, u8 clindex)
>> +{
>> +       return ERR_PTR(-EOPNOTSUPP);
>> +}
>> +#endif
>> +
>> +#endif /* _NET_DECT_CPP */
>> diff --git a/target/linux/generic/files/include/net/dect/dect.h 
>> b/target/linux/generic/files/include/net/dect/dect.h
>> new file mode 100644
>> index 0000000..e253308
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/dect.h
>> @@ -0,0 +1,319 @@
>> +#ifndef _NET_DECT_DECT_H
>> +#define _NET_DECT_DECT_H
>> +
>> +#define DECT_FRAMES_PER_MULTIFRAME     16
>> +
>> +static inline u8 dect_next_framenum(u8 framenum)
>> +{
>> +       if (++framenum == DECT_FRAMES_PER_MULTIFRAME)
>> +               framenum = 0;
>> +       return framenum;
>> +}
>> +
>> +static inline u8 dect_framenum_add(u8 f1, u8 f2)
>> +{
>> +       return (f1 + f2) % DECT_FRAMES_PER_MULTIFRAME;
>> +}
>> +
>> +#define DECT_MULTIFRAME_MASK           0x00ffffff
>> +
>> +static inline u32 dect_next_mfn(u32 mfn)
>> +{
>> +       if (++mfn == (1 << 24) - 1)
>> +               mfn = 0;
>> +       return mfn;
>> +}
>> +
>> +static inline u32 dect_mfn_add(u32 mfn1, u32 mfn2)
>> +{
>> +       return (mfn1 + mfn2) & DECT_MULTIFRAME_MASK;
>> +}
>> +
>> +/* Compare multiframe numbers, considering overflows */
>> +static inline bool dect_mfn_before(u32 mfn1, u32 mfn2)
>> +{
>> +       return (s32)((mfn2 << 8) - (mfn1 << 8)) > 0;
>> +}
>> +
>> +static inline bool dect_mfn_after(u32 mfn1, u32 mfn2)
>> +{
>> +       return dect_mfn_before(mfn2, mfn1);
>> +}
>> +
>> +#include <linux/list.h>
>> +
>> +/**
>> + * enum dect_timer_bases - timer bases for DECT timers
>> + *
>> + * @DECT_TIMER_RX:     receive time base
>> + * @DECT_TIMER_TX:     send time base
>> + */
>> +enum dect_timer_bases {
>> +       DECT_TIMER_RX,
>> +       DECT_TIMER_TX,
>> +       __DECT_TIMER_BASE_MAX
>> +};
>> +#define DECT_TIMER_BASE_MAX    (__DECT_TIMER_BASE_MAX - 1)
>> +
>> +/**
>> + * struct dect_timer_base - timer base
>> + *
>> + * @timers:            list of active timers
>> + * @slot:              slot position
>> + * @framenum:          frame number
>> + * @mfn:               multiframe number
>> + */
>> +struct dect_timer_base {
>> +       struct list_head        timers;
>> +       u8                      base;
>> +       u8                      slot;
>> +       u8                      framenum;
>> +       u32                     mfn;
>> +};
>> +
>> +static inline void dect_timer_base_init(struct dect_timer_base 
>> base[],
>> +                                       enum dect_timer_bases b)
>> +{
>> +       INIT_LIST_HEAD(&base[b].timers);
>> +       base->base = b;
>> +}
>> +
>> +static inline u8 __dect_slotnum(const struct dect_timer_base *base)
>> +{
>> +       return base->slot;
>> +}
>> +
>> +static inline u8 __dect_framenum(const struct dect_timer_base *base)
>> +{
>> +       return base->framenum;
>> +}
>> +
>> +static inline u32 __dect_mfn(const struct dect_timer_base *base)
>> +{
>> +       return base->mfn;
>> +}
>> +
>> +extern void __dect_run_timers(const char *name, struct 
>> dect_timer_base *base);
>> +
>> +/**
>> + * struct dect_timer - DECT TDMA frame timer
>> + *
>> + * @list:              timer list node
>> + * @base:              timer base
>> + * @mfn:               expiration time: multiframe number
>> + * @frame:             expiration time: frame number
>> + * @slot:              expiration time: slot number
>> + * @func:              timer function
>> + * @data:              timer data
>> + */
>> +struct dect_cell;
>> +struct dect_cluster;
>> +
>> +struct dect_timer {
>> +       struct list_head                list;
>> +
>> +       enum dect_timer_bases           base;
>> +       u32                             mfn;
>> +       u8                              frame;
>> +       u8                              slot;
>> +
>> +       union {
>> +               void                    (*cell)(struct dect_cell *, 
>> void *);
>> +               void                    (*cluster)(struct dect_cluster 
>> *, void *);
>> +               void                    (*cb)(void *, void *);
>> +       } cb;
>> +       union {
>> +               struct dect_cell        *cell;
>> +               struct dect_cluster     *cluster;
>> +               void                    *obj;
>> +       };
>> +       void                            *data;
>> +};
>> +
>> +static inline void dect_timer_init(struct dect_timer *timer)
>> +{
>> +       INIT_LIST_HEAD(&timer->list);
>> +}
>> +
>> +static inline void dect_timer_del(struct dect_timer *timer)
>> +{
>> +       list_del_init(&timer->list);
>> +}
>> +
>> +extern void __dect_timer_add(const char *name, struct dect_timer_base 
>> *base,
>> +                            struct dect_timer *timer, u32 frame, u8 
>> slot);
>> +
>> +#include <linux/dect.h>
>> +#include <net/dect/identities.h>
>> +#include <net/dect/mac_ccf.h>
>> +#include <net/dect/dlc.h>
>> +
>> +extern void __acquires(dect_cfg_mutex) dect_lock(void);
>> +extern void __releases(dect_cfg_mutex) dect_unlock(void);
>> +
>> +/**
>> + * struct dect_cluster - DECT cluster of up to 8/256 cells
>> + *
>> + * @list:              device list node
>> + * @name:              device identifier
>> + * @index:             unique numeric cluster identifier
>> + * @mode:              device mode (FP/PP/monitor)
>> + * @pari:              primary access rights identifier
>> + * @si:                        system information
>> + * @bmc:               Broadcast Message Control
>> + * @cmc:               Connectionless Message Control
>> + * @mbcs:              Multi-Bearer Controllers
>> + * @cells:             DECT cells
>> + */
>> +struct dect_cluster {
>> +       struct list_head                list;
>> +       char                            name[DECTNAMSIZ];
>> +       int                             index;
>> +
>> +       u32                             tipc_id;
>> +       u32                             tipc_portref;
>> +       struct dect_cluster_handle      handle;
>> +
>> +       enum dect_cluster_modes         mode;
>> +
>> +       spinlock_t                      lock;
>> +
>> +       struct dect_ari                 pari;
>> +       struct dect_si                  si;
>> +       u8                              rpn;
>> +
>> +       u32                             pmid;
>> +
>> +       struct list_head                cells;
>> +       struct dect_bmc                 bmc;
>> +       struct dect_cmc                 cmc;
>> +       struct list_head                mbcs;
>> +
>> +       u32                             mcei_rover;
>> +       struct list_head                mac_connections;
>> +
>> +       struct dect_timer_base          timer_base[DECT_TIMER_BASE_MAX 
>> + 1];
>> +};
>> +
>> +extern struct list_head dect_cluster_list;
>> +extern struct dect_cluster *dect_cluster_get_by_index(int index);
>> +
>> +struct dect_netlink_handler {
>> +       int (*doit)(const struct sk_buff *, const struct nlmsghdr *,
>> +                   const struct nlattr *[]);
>> +       int (*dump)(struct sk_buff *, struct netlink_callback *);
>> +       int (*done)(struct netlink_callback *);
>> +       const struct nla_policy *policy;
>> +       unsigned int maxtype;
>> +};
>> +
>> +extern void dect_netlink_register_handlers(const struct 
>> dect_netlink_handler *handler,
>> +                                          unsigned int base, unsigned 
>> int n);
>> +extern void dect_netlink_unregister_handlers(unsigned int base, 
>> unsigned int n);
>> +
>> +extern struct sock *dect_nlsk;
>> +
>> +/**
>> + * struct dect_llme_req - LLME netlink request
>> + *
>> + * @nlh:               netlink header
>> + * @nlpid:             netlink socket PID
>> + */
>> +struct dect_llme_req {
>> +       struct nlmsghdr         nlh;
>> +       u32                     nlpid;
>> +};
>> +
>> +#include <net/sock.h>
>> +
>> +extern const struct proto_ops dect_stream_ops;
>> +extern const struct proto_ops dect_dgram_ops;
>> +
>> +struct dect_proto {
>> +       unsigned int            type;
>> +       unsigned int            protocol;
>> +       int                     capability;
>> +       const struct proto_ops  *ops;
>> +       int                     (*getname)(struct sock *sk,
>> +                                          struct sockaddr *uaddr, int 
>> *len,
>> +                                          int peer);
>> +       struct proto            proto;
>> +};
>> +
>> +#include <net/tcp_states.h>
>> +
>> +enum {
>> +       DECT_SK_ESTABLISHED             = TCP_ESTABLISHED,
>> +       DECT_SK_ESTABLISH_PENDING       = TCP_SYN_SENT,
>> +       DECT_SK_RELEASED                = TCP_CLOSE,
>> +       DECT_SK_RELEASE_PENDING         = TCP_CLOSING,
>> +       DECT_SK_LISTEN                  = TCP_LISTEN,
>> +};
>> +
>> +struct dect_csk {
>> +       struct sock             sk;
>> +       struct hlist_head       accept_queue;
>> +};
>> +
>> +static inline struct dect_csk *dect_csk(const struct sock *sk)
>> +{
>> +       return (struct dect_csk *)sk;
>> +}
>> +
>> +extern int dect_proto_register(struct dect_proto *proto);
>> +extern void dect_proto_unregister(struct dect_proto *proto);
>> +
>> +struct dect_skb_sk_cb {
>> +       //struct dect_skb_trx_cb        cb;
>> +       int                     index;
>> +};
>> +
>> +#define DECT_SK_CB(skb)                ((struct dect_skb_sk_cb 
>> *)(skb)->cb)
>> +
>> +static inline int dect_sock_queue_rcv_skb(struct sock *sk, struct 
>> sk_buff *skb)
>> +{
>> +       /*
>> +        * Release the transceiver reference, it is only valid in IRQ 
>> and
>> +        * softirq context.
>> +        */
>> +       //FIXME
>> +       //DECT_SK_CB(skb)->index = DECT_CB(skb)->trx->dev->index;
>> +       return sock_queue_rcv_skb(sk, skb);
>> +}
>> +
>> +struct dect_notification {
>> +       u32             type;
>> +};
>> +
>> +#define DECT_NOTIFY_CB(skb)    ((struct dect_notification 
>> *)(skb)->cb)
>> +
>> +extern struct sk_buff *dect_alloc_notification(u32 type, const void 
>> *data,
>> +                                              unsigned int size);
>> +
>> +extern void (*dect_raw_rcv_hook)(struct sk_buff *skb);
>> +static inline void dect_raw_rcv(struct sk_buff *skb)
>> +{
>> +       typeof(dect_raw_rcv_hook) dect_raw_rcv;
>> +
>> +       rcu_read_lock();
>> +       dect_raw_rcv = dect_raw_rcv_hook;
>> +       if (dect_raw_rcv != NULL)
>> +               dect_raw_rcv(skb);
>> +       rcu_read_unlock();
>> +}
>> +
>> +extern int dect_af_module_init(void);
>> +extern void dect_af_module_exit(void);
>> +
>> +extern int dect_bsap_module_init(void);
>> +extern void dect_bsap_module_exit(void);
>> +extern int dect_ssap_module_init(void);
>> +extern void dect_ssap_module_exit(void);
>> +
>> +extern int dect_netlink_module_init(void);
>> +extern void dect_netlink_module_exit(void);
>> +
>> +extern struct sk_buff *skb_append_frag(struct sk_buff *head, struct 
>> sk_buff *skb);
>> +extern unsigned int skb_queue_pull(struct sk_buff_head *list, 
>> unsigned int len);
>> +
>> +#endif /* _NET_DECT_DECT_H */
>> diff --git a/target/linux/generic/files/include/net/dect/dlc.h 
>> b/target/linux/generic/files/include/net/dect/dlc.h
>> new file mode 100644
>> index 0000000..f38f4d4
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/dlc.h
>> @@ -0,0 +1,462 @@
>> +/*
>> + * DECT DLC Layer
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_DLC_H
>> +#define _NET_DECT_DLC_H
>> +
>> +#include <linux/timer.h>
>> +
>> +/*
>> + * C-Plane data link service
>> + */
>> +
>> +/*
>> + * FA-Frame
>> + */
>> +
>> +#define DECT_FA_HDR_SIZE       3
>> +
>> +struct dect_fa_hdr {
>> +       u8      addr;
>> +       u8      ctrl;
>> +       u8      li;
>> +};
>> +
>> +/*
>> + * Address field
>> + */
>> +
>> +#define DECT_FA_ADDR_OFF       0
>> +
>> +/* New link flag */
>> +#define DECT_FA_ADDR_NLF_FLAG  0x80
>> +
>> +/* Logical Link Number */
>> +#define DECT_FA_ADDR_LLN_MASK  0x70
>> +#define DECT_FA_ADDR_LLN_SHIFT 4
>> +
>> +/* Service Access Point Identifier */
>> +#define DECT_FA_ADDR_SAPI_MASK 0x0c
>> +#define DECT_FA_ADDR_SAPI_SHIFT        2
>> +
>> +/* Command/Response flag */
>> +#define DECT_FA_ADDR_CR_FLAG   0x02
>> +
>> +/* Reserved bit */
>> +#define DECT_FA_ADDR_RES_BIT   0x01
>> +
>> +/*
>> + * Control field
>> + */
>> +
>> +#define DECT_FA_CTRL_OFF       1
>> +
>> +/*
>> + * I-Format: numbered information
>> + */
>> +
>> +#define DECT_FA_CTRL_I_FMT_MASK        0x01
>> +#define DECT_FA_CTRL_I_FMT_ID  0x00
>> +
>> +/* Receive sequence number */
>> +#define DECT_FA_CTRL_I_NR_MASK 0xe0
>> +#define DECT_FA_CTRL_I_NR_SHIFT        5
>> +
>> +/* Poll bit */
>> +#define DECT_FA_CTRL_I_P_FLAG  0x10
>> +
>> +/* Send sequence number */
>> +#define DECT_FA_CTRL_I_NS_MASK 0x0e
>> +#define DECT_FA_CTRL_I_NS_SHIFT        1
>> +
>> +/* Command */
>> +#define DECT_FA_CTRL_I_CMD_I   (0x0)
>> +
>> +/*
>> + * S-Format: supervisory functions
>> + */
>> +
>> +#define DECT_FA_CTRL_S_FMT_MASK        0x03
>> +#define DECT_FA_CTRL_S_FMT_ID  0x01
>> +
>> +/* Receive sequence number */
>> +#define DECT_FA_CTRL_S_NR_MASK 0xe0
>> +#define DECT_FA_CTRL_S_NR_SHIFT        5
>> +
>> +/* Poll/final bit */
>> +#define DECT_FA_CTRL_S_PF_FLAG 0x10
>> +
>> +/* Command/Response */
>> +#define DECT_FA_CTRL_S_CR_MASK 0x0c
>> +
>> +#define DECT_FA_CTRL_S_CR_RR   0x00
>> +#define DECT_FA_CTRL_S_CR_RNR  0x40
>> +#define DECT_FA_CTRL_S_CR_REJ  0x80
>> +
>> +/*
>> + *  U-Format: unnumbered information
>> + */
>> +
>> +#define DECT_FA_CTRL_U_FMT_MASK        0x03
>> +#define DECT_FA_CTRL_U_FMT_ID  0x03
>> +
>> +/* Unnumbered function bits */
>> +#define DECT_FA_CTRL_U_U1_MASK 0xec
>> +
>> +/* Poll/final bit */
>> +#define DECT_FA_CTRL_U_PF_FLAG 0x10
>> +
>> +/* Command/Response */
>> +#define DECT_FA_CTRL_U_CR_MASK 0xef
>> +
>> +#define DECT_FA_CTRL_U_CR_SABM 0x2c
>> +#define DECT_FA_CTRL_U_CR_DM   0x0c
>> +#define DECT_FA_CTRL_U_CR_UI   0x00
>> +#define DECT_FA_CTRL_U_CR_DISC 0x40
>> +#define DECT_FA_CTRL_U_CR_UA   0x60
>> +
>> +/*
>> + * Length Indicator
>> + */
>> +
>> +#define DECT_FA_LI_OFF         2
>> +
>> +/* Length (octets) */
>> +#define DECT_FA_LI_LENGTH_MASK 0xfc
>> +#define DECT_FA_LI_LENGTH_SHIFT        2
>> +
>> +/* More data flag */
>> +#define DECT_FA_LI_M_FLAG      0x02
>> +
>> +/* Extended length indicator bit */
>> +#define DECT_FA_LI_EXT_FLAG    0x01
>> +
>> +/* maximum length value */
>> +#define DECT_FA_LI_MAX         63
>> +
>> +/*
>> + * Extended Length indicator
>> + */
>> +
>> +#define DECT_FA_ELI_OFF                3
>> +
>> +/* Length (octets) */
>> +#define DECT_FA_ELI_LENGTH_MASK        0xfc
>> +#define DECT_FA_ELI_LENGTH_SHIFT 2
>> +
>> +struct dect_fa_len {
>> +       u8              len;
>> +       bool            more;
>> +};
>> +
>> +/*
>> + * Fill Field
>> + */
>> +
>> +#define DECT_FA_FILL_PATTERN   0xf0
>> +
>> +/*
>> + * Checksum field
>> + */
>> +
>> +#define DECT_FA_CSUM_SIZE      2
>> +
>> +/*
>> + * Information field
>> + */
>> +
>> +#define DECT_FA_I_MAX          (DECT_FA_LI_MAX - DECT_FA_HDR_SIZE - 
>> DECT_FA_CSUM_SIZE)
>> +
>> +
>> +/**
>> + * struct dect_dli - DECT Data Link Identifier (DLI)
>> + *
>> + * @lln:       Logical Link Number
>> + * @mci:       Mac Connection Identifier
>> + */
>> +struct dect_dli {
>> +       enum dect_llns  lln;
>> +       struct dect_mci mci;
>> +};
>> +
>> +/**
>> + * @DECT_LAPC_ULI:     unassigned link identifier state (class U/A)
>> + * @DECT_LAPC_ALI:     assigned link identifier state (class B 
>> established)
>> + * @DECT_LAPC_ASM:     assigned Link Identifier/multiple frame state 
>> (class B suspended)
>> + */
>> +enum dect_lapc_states {
>> +       DECT_LAPC_ULI,
>> +       DECT_LAPC_ALI,
>> +       DECT_LAPC_ASM,
>> +};
>> +
>> +/**
>> + * struct dect_lapc - DECT LAPC entity
>> + *
>> + * @lc:                        Associated Lc entity
>> + * @dli:               Data Link Identifier
>> + * @sapi:              Service Access Point Identifier
>> + * @cmd:               CR bit setting for commands (PT: 1, FT: 0)
>> + * @nlf:               New link flag
>> + * @v_s:               Send state Variable V(S): sequence number of 
>> next I-frame
>> + * @v_a:               Acknowledge state Variable V(A): last I-frame 
>> that has been acknowledged
>> + * @v_r:               Receive state Variable V(R): next expected 
>> sequence number
>> + * busy:               LAPC is in receiver busy condition
>> + * @peer_busy:         Peer is in receiver busy condition
>> + * @window:            maximum number of oustanding unacknowledged 
>> I-frames
>> + * @mod:               modulus for sequence number calculations
>> + * @retransmit_cnt:    Retransmission counter
>> + * @retransmit_queue:  Retransmission queue
>> + * @timer:             Retransmission timer (DL.04)
>> + */
>> +struct dect_lapc {
>> +       struct sock             *sk;
>> +       struct dect_lc          *lc;
>> +       struct dect_dli         dli;
>> +       enum dect_sapis         sapi;
>> +
>> +       bool                    cmd;
>> +
>> +       enum dect_lapc_states   state;
>> +       bool                    nlf;
>> +       u8                      v_s;
>> +       u8                      v_a;
>> +       u8                      v_r;
>> +
>> +       bool                    busy;
>> +       bool                    peer_busy;
>> +
>> +       u8                      window;
>> +       u8                      mod;
>> +
>> +       u8                      retransmit_cnt;
>> +       struct sk_buff_head     retransmit_queue;
>> +       struct timer_list       timer;
>> +
>> +       struct sk_buff          *rcv_head;
>> +};
>> +
>> +/* class A window size and sequence number modulus */
>> +#define DECT_LAPC_CLASS_A_WINDOW               1
>> +#define DECT_LAPC_CLASS_A_MOD                  2
>> +
>> +/* class B window size and sequence number modulus */
>> +#define DECT_LAPC_CLASS_B_INITIAL_WINDOW       1
>> +#define DECT_LAPC_CLASS_B_WINDOW               3
>> +#define DECT_LAPC_CLASS_B_MOD                  8
>> +
>> +/* maximum number of retransmissions */
>> +#define DECT_LAPC_RETRANSMIT_MAX               3
>> +
>> +/* various timer parameters specified in Annex A */
>> +#define DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT    (2 * HZ)
>> +#define DECT_LAPC_CLASS_B_ESTABLISH_TIMEOUT    (2 * HZ)
>> +#define DECT_LAPC_RETRANSMISSION_TIMEOUT       (1 * HZ)
>> +#define DECT_LAPC_LINK_RELEASE_TIMEOUT         (2 * HZ)
>> +#define DECT_LAPC_LINK_SUSPEND_TIMEOUT         (2 * HZ)
>> +#define DECT_LAPC_LINK_RESUME_TIMEOUT          (2 * HZ)
>> +#define DECT_LAPC_CONNECTION_HANDOVER_TIMEOUT  (10 * HZ)
>> +#define DECT_LAPC_CONNECTION_HANDOVER_INTERVAL (4 * HZ)
>> +
>> +extern struct dect_lapc *dect_lapc_init(struct sock *sk, const struct 
>> dect_dli *dli,
>> +                                       enum dect_sapis sapi, struct 
>> dect_lc *lc,
>> +                                       gfp_t gfp);
>> +extern void dect_lapc_destroy(struct dect_lapc *lapc);
>> +
>> +extern int dect_lapc_establish(struct dect_lapc *lapc);
>> +extern void dect_lapc_release(struct dect_lapc *lapc, bool normal);
>> +extern int dect_lapc_transmit(struct dect_lapc *lapc);
>> +
>> +extern struct dect_lapc *dect_ssap_rcv_request(struct dect_lc *lc,
>> +                                              const struct dect_dli 
>> *dli,
>> +                                              enum dect_sapis sapi);
>> +
>> +/**
>> + * struct dect_lc - DECT Lc entity
>> + *
>> + * @mc:                MAC connection
>> + * @lsig:      link signature for checksumming (lower 16 bits of PMID 
>> or 0)
>> + * @rx_head:   reassembly queue head
>> + * @rx_len:    target length of current reassembly buffer
>> + * @txq:       transmit queue
>> + * @tx_head:   current TX LAPC frame
>> + * @tx_len:    TX target fragment length
>> + * @use:       usage count
>> + * @lapcs:     LAPC entities associated with the Lc
>> + * @e_lapc:    LAPC performing establishment procedures
>> + *
>> + * The Lc entity is responsible for framing, logical channel 
>> selection and
>> + * fragmenting of LAPC PDUs. There is one Lc entity per MAC 
>> connection.
>> + */
>> +struct dect_lc {
>> +       struct dect_mac_conn    *mc;
>> +       u16                     lsig;
>> +
>> +       struct sk_buff          *rx_head;
>> +       u8                      rx_len;
>> +
>> +       struct sk_buff_head     txq;
>> +       struct sk_buff          *tx_head;
>> +       u8                      tx_len;
>> +
>> +       u8                      use;
>> +       struct dect_lapc        *lapcs[DECT_LLN_UNASSIGNED + 1];
>> +       struct dect_lapc        *elapc;
>> +};
>> +
>> +#define DECT_LC_LSIG_MASK      0xffff
>> +
>> +extern struct dect_lc *dect_lc_init(struct dect_mac_conn *mc, gfp_t 
>> gfp);
>> +extern void dect_lc_destroy(struct dect_lc *lc);
>> +
>> +extern void dect_lc_bind(struct dect_lc *lc, struct dect_lapc *lapc);
>> +extern void dect_lc_unbind(struct dect_lc *lc, struct dect_lapc 
>> *lapc);
>> +
>> +/**
>> + * struct dect_lb - DECT Lb entity (C-plane broadcast service)
>> + *
>> + *
>> + */
>> +struct dect_lb {
>> +};
>> +
>> +#define DECT_LB_SHORT_FRAME_SIZE       3
>> +#define DECT_LB_LONG_FRAME_SIZE                5
>> +#define DECT_LB_EXTENDED_FRAME_SIZE_MAX        (6 * 
>> DECT_LB_LONG_FRAME_SIZE)
>> +
>> +#include <net/sock.h>
>> +
>> +/**
>> + * struct dect_dlc_fbx_ops - DLC U-plane lower (FBx) entity ops
>> + *
>> + */
>> +struct dect_fbx;
>> +struct dect_fbx_ops {
>> +       struct sk_buff                  *(*dequeue)(struct dect_fbx 
>> *fbx);
>> +       void                            (*enqueue)(struct dect_fbx 
>> *fbx,
>> +                                                  struct sk_buff 
>> *skb);
>> +};
>> +
>> +struct dect_fbx {
>> +       const struct dect_fbx_ops       *ops;
>> +};
>> +
>> +extern const struct dect_fbx_ops dect_fbn_ops;
>> +
>> +struct dect_lux;
>> +struct dect_lux_ops {
>> +       struct sk_buff                  *(*dequeue)(struct dect_lux 
>> *lux);
>> +       void                            (*enqueue)(struct dect_lux 
>> *lux,
>> +                                                  struct sk_buff 
>> *skb);
>> +       void                            (*disconnect)(struct dect_lux 
>> *lux);
>> +};
>> +
>> +/**
>> + * struct dect_lux - DLC U-plane upper (LUx) entity
>> + *
>> + * @fpx:       FBx entity
>> + */
>> +struct dect_lux {
>> +       const struct dect_lux_ops       *ops;
>> +       struct dect_fbx                 fbx;
>> +};
>> +
>> +/**
>> + * dect_mac_connection_states - DECT MAC connection states as viewed 
>> by the DLC
>> + *
>> + * @DECT_MAC_CONN_CLOSED:
>> + * @DECT_MAC_CONN_OPEN_PENDING:
>> + * @DECT_MAC_CONN_OPEN:
>> + */
>> +enum dect_mac_conn_states {
>> +       DECT_MAC_CONN_CLOSED,
>> +       DECT_MAC_CONN_OPEN_PENDING,
>> +       DECT_MAC_CONN_OPEN,
>> +};
>> +
>> +/**
>> + * struct dect_mac_conn - DECT MAC connection as viewed by the DLC
>> + *
>> + * @list:      Cluster connection list node
>> + * @cl:                Cluster
>> + * @mcei:      MAC Connection Endpoint Identification
>> + * @mci:       MAC Connection Identifier (BMCI or AMCI)
>> + * @state:     Connection state
>> + * @service:   Service offered by the connection
>> + * @ck:                cipher key
>> + */
>> +struct dect_mac_conn {
>> +       struct list_head                list;
>> +       struct dect_cluster             *cl;
>> +
>> +       u32                             mcei;
>> +       struct dect_mci                 mci;
>> +       enum dect_mac_conn_states       state;
>> +       enum dect_mac_service_types     service;
>> +       u64                             ck;
>> +
>> +       u8                              use;
>> +       struct dect_lc                  *lc;
>> +       struct dect_fbx                 *fbx;
>> +};
>> +
>> +extern struct dect_mac_conn *dect_mac_conn_init(struct dect_cluster 
>> *cl,
>> +                                               const struct dect_mci 
>> *mci,
>> +                                               const struct 
>> dect_mbc_id *id);
>> +extern void dect_dlc_mac_conn_destroy(struct dect_mac_conn *mc);
>> +extern struct dect_mac_conn *dect_mac_conn_get_by_mci(const struct 
>> dect_cluster *cl,
>> +                                                     const struct 
>> dect_mci *mci);
>> +
>> +extern void dect_dlc_mac_conn_bind(struct dect_mac_conn *mc);
>> +extern void dect_dlc_mac_conn_unbind(struct dect_mac_conn *mc);
>> +extern int dect_dlc_mac_conn_establish(struct dect_mac_conn *mc);
>> +
>> +extern int dect_mac_con_cfm(struct dect_cluster *cl, u32 mcei,
>> +                           enum dect_mac_service_types service);
>> +extern int dect_mac_con_ind(struct dect_cluster *cl,
>> +                           const struct dect_mbc_id *id,
>> +                           enum dect_mac_service_types service);
>> +
>> +extern int dect_dlc_mac_conn_enc_key_req(struct dect_mac_conn *mc, 
>> u64 key);
>> +extern int dect_dlc_mac_conn_enc_eks_req(struct dect_mac_conn *mc,
>> +                                        enum dect_cipher_states 
>> status);
>> +extern void dect_mac_enc_eks_cfm(struct dect_cluster *cl, u32 mcei,
>> +                                enum dect_cipher_states status);
>> +extern void dect_mac_enc_eks_ind(struct dect_cluster *cl, u32 mcei,
>> +                                enum dect_cipher_states status);
>> +
>> +extern void dect_dlc_mac_dis_req(struct dect_mac_conn *mc);
>> +extern int dect_mac_dis_ind(struct dect_cluster *cl, u32 mcei,
>> +                           enum dect_release_reasons reason);
>> +
>> +extern void dect_cplane_notify_state_change(struct dect_mac_conn 
>> *mc);
>> +extern void dect_cplane_mac_dis_ind(const struct dect_mac_conn *mc,
>> +                                   enum dect_release_reasons reason);
>> +extern void dect_cplane_mac_enc_eks_ind(const struct dect_mac_conn 
>> *mc,
>> +                                       enum dect_cipher_states 
>> status);
>> +
>> +extern void dect_cplane_rcv(struct dect_mac_conn *mc,
>> +                           enum dect_data_channels chan,
>> +                           struct sk_buff *skb);
>> +extern struct sk_buff *dect_cplane_dtr(struct dect_mac_conn *mc,
>> +                                      enum dect_data_channels chan);
>> +
>> +extern void dect_uplane_rcv(struct dect_mac_conn *mc,
>> +                           enum dect_data_channels chan,
>> +                           struct sk_buff *skb);
>> +extern struct sk_buff *dect_uplane_dtr(struct dect_mac_conn *mc,
>> +                                      enum dect_data_channels chan);
>> +
>> +extern void dect_mac_co_data_ind(struct dect_cluster *cl, u32 mcei,
>> +                                enum dect_data_channels chan,
>> +                                struct sk_buff *skb);
>> +extern struct sk_buff *dect_mac_co_dtr_ind(struct dect_cluster *cl, 
>> u32 mcei,
>> +                                          enum dect_data_channels 
>> chan);
>> +
>> +extern void dect_bsap_rcv(const struct dect_cluster *cl, struct 
>> sk_buff *skb);
>> +extern void dect_mac_page_ind(struct dect_cluster *cl, struct sk_buff 
>> *skb);
>> +
>> +#endif /* _NET_DECT_DLC_H */
>> diff --git a/target/linux/generic/files/include/net/dect/dsc.h 
>> b/target/linux/generic/files/include/net/dect/dsc.h
>> new file mode 100644
>> index 0000000..423a646
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/dsc.h
>> @@ -0,0 +1,12 @@
>> +#ifndef _NET_DECT_DSC_H
>> +#define _NET_DECT_DSC_H
>> +
>> +static inline __le64 dect_dsc_iv(u32 mfn, u8 framenum)
>> +{
>> +       return cpu_to_le64((mfn << 4) + framenum);
>> +}
>> +
>> +extern void dect_dsc_keystream(uint64_t iv, const uint8_t *key,
>> +                              uint8_t *output, unsigned int len);
>> +
>> +#endif /* _NET_DECT_DSC_H */
>> diff --git a/target/linux/generic/files/include/net/dect/identities.h 
>> b/target/linux/generic/files/include/net/dect/identities.h
>> new file mode 100644
>> index 0000000..a924d35
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/identities.h
>> @@ -0,0 +1,194 @@
>> +#ifndef _NET_DECT_IDENTITIES_H
>> +#define _NET_DECT_IDENTITIES_H
>> +
>> +/*
>> + * Acess Rights Identity (ARI)
>> + */
>> +
>> +#define DECT_ARI_ARC_MASK      0xe000000000000000ULL
>> +#define DECT_ARI_ARC_SHIFT     61
>> +
>> +/* Class A */
>> +#define DECT_ARI_A_EMC_MASK    0x1fffe00000000000ULL
>> +#define DECT_ARI_A_EMC_SHIFT   45
>> +
>> +#define DECT_ARI_A_FPN_MASK    0x00001ffff0000000ULL
>> +#define DECT_ARI_A_FPN_SHIFT   28
>> +
>> +/* Class B */
>> +#define DECT_ARI_B_EIC_MASK    0x1fffe00000000000ULL
>> +#define DECT_ARI_B_EIC_SHIFT   45
>> +
>> +#define DECT_ARI_B_FPN_MASK    0x00001fe000000000ULL
>> +#define DECT_ARI_B_FPN_SHIFT   37
>> +
>> +#define DECT_ARI_B_FPS_MASK    0x0000001e00000000ULL
>> +#define DECT_ARI_B_FPS_SHIFT   33
>> +
>> +/* Class C */
>> +#define DECT_ARI_C_POC_MASK    0x1fffe00000000000ULL
>> +#define DECT_ARI_C_POC_SHIFT   45
>> +
>> +#define DECT_ARI_C_FPN_MASK    0x00001fe000000000ULL
>> +#define DECT_ARI_C_FPN_SHIFT   37
>> +
>> +#define DECT_ARI_C_FPS_MASK    0x0000001e00000000ULL
>> +#define DECT_ARI_C_FPS_SHIFT   33
>> +
>> +/* Class D */
>> +#define DECT_ARI_D_GOP_MASK    0x1ffffe0000000000ULL
>> +#define DECT_ARI_D_GOP_SHIFT   41
>> +
>> +#define DECT_ARI_D_FPN_MASK    0x000001fe00000000ULL
>> +#define DECT_ARI_D_FPN_SHIFT   33
>> +
>> +/* Class E */
>> +#define DECT_ARI_E_FIL_MASK    0x1fffe00000000000ULL
>> +#define DECT_ARI_E_FIL_SHIFT   45
>> +
>> +#define DECT_ARI_E_FPN_MASK    0x00001ffe00000000ULL
>> +#define DECT_ARI_E_FPN_SHIFT   33
>> +
>> +#include <linux/dect_netlink.h>
>> +
>> +struct dect_ari {
>> +       enum dect_ari_classes   arc;
>> +       u32                     fpn;
>> +       u32                     fps;
>> +       union {
>> +               u16             emc;
>> +               u16             eic;
>> +               u16             poc;
>> +               u32             gop;
>> +               u16             fil;
>> +       };
>> +};
>> +
>> +enum dect_ari_lengths {
>> +       DECT_ARC_A_LEN          = 36,
>> +       DECT_ARC_B_LEN          = 31,
>> +       DECT_ARC_C_LEN          = 31,
>> +       DECT_ARC_D_LEN          = 31,
>> +       DECT_ARC_E_LEN          = 31,
>> +};
>> +
>> +extern bool dect_ari_masked_cmp(const struct dect_ari *a1,
>> +                               const struct dect_ari *a2,
>> +                               const struct dect_ari *m);
>> +extern bool dect_ari_cmp(const struct dect_ari *a1, const struct 
>> dect_ari *a2);
>> +extern u8 dect_parse_ari(struct dect_ari *ari, u64 a);
>> +extern u64 dect_build_ari(const struct dect_ari *ari);
>> +
>> +/*
>> + * RFPI
>> + */
>> +
>> +#define DECT_RFPI_E_FLAG       0x0080000000000000ULL
>> +#define DECT_RFPI_ARI_SHIFT    9
>> +#define DECT_RFPI_RPN_SHIFT    16
>> +
>> +struct dect_idi;
>> +extern bool dect_rfpi_cmp(const struct dect_idi *i1, const struct 
>> dect_idi *i2);
>> +extern u64 dect_build_rfpi(const struct dect_idi *idi);
>> +
>> +/*
>> + * FMID (Fixed MAC Identifier)
>> + */
>> +
>> +#define DECT_FMID_MASK         0x0fff
>> +#define DECT_FMID_SIZE         12
>> +
>> +extern u16 dect_build_fmid(const struct dect_idi *idi);
>> +
>> +/*
>> + * PMID (Portable MAC Identifier)
>> + */
>> +
>> +#define DECT_PMID_MASK                 0x000fffff
>> +#define DECT_PMID_SIZE                 20
>> +
>> +#define DECT_PMID_DEFAULT_ID_MASK      0x000f0000
>> +#define DECT_PMID_DEFAULT_ID           0x000e0000
>> +#define DECT_PMID_DEFAULT_NUM_MASK     0x0000ffff
>> +
>> +#define DECT_PMID_EMERGENCY_ID_MASK    0x000ff000
>> +#define DECT_PMID_EMERGENCY_ID         0x000f1000
>> +#define DECT_PMID_EMERGENCY_TPUI_MASK  0x00000fff
>> +
>> +#define DECT_PMID_ASSIGNED_TPUI_MASK   0x000fffff
>> +
>> +/**
>> + * @DECT_PMID_DEFAULT:         1110 + arbitrary number (16 bits)
>> + * @DECT_PMID_ASSIGNED:                Assigned individual TPUI
>> + * @DECT_PMID_EMERGENCY:       1111 0001 + 12 bits of emergency TPUI
>> + */
>> +enum dect_pmid_types {
>> +       DECT_PMID_DEFAULT,
>> +       DECT_PMID_ASSIGNED,
>> +       DECT_PMID_EMERGENCY,
>> +};
>> +
>> +struct dect_pmid {
>> +       enum dect_pmid_types    type;
>> +       union {
>> +               u32             tpui;
>> +               u32             num;
>> +       };
>> +};
>> +
>> +extern void dect_parse_pmid(struct dect_pmid *pmid, u32 p);
>> +extern u32 dect_build_pmid(const struct dect_pmid *pmid);
>> +extern bool dect_pmid_cmp(const struct dect_pmid *p1, const struct 
>> dect_pmid *p2);
>> +
>> +/*
>> + * ECN (Exchanged Connection Number)
>> + */
>> +
>> +#define DECT_ECN_MASK          0xf
>> +#define DECT_ECN_SIZE          4
>> +
>> +/*
>> + * LCN (Logical Connection Number)
>> + */
>> +
>> +#define DECT_LCN_MASK          0x7
>> +#define DECT_LCN_SIZE          3
>> +
>> +/**
>> + * struct dect_mci - MAC connection identifier
>> + *
>> + * @ari:       DECT ARI
>> + * @pmid:      Portable MAC Identity
>> + * @lcn:       Logical Connection Number
>> + */
>> +struct dect_mci {
>> +       struct dect_ari         ari;
>> +       struct dect_pmid        pmid;
>> +       u8                      lcn;
>> +};
>> +
>> +extern int dect_parse_mci(struct dect_mci *mci, u64 m);
>> +extern u64 dect_build_mci(const struct dect_mci *mci);
>> +
>> +/*
>> + * Data Link Identifier
>> + */
>> +
>> +/**
>> + * struct dect_dlei - DECT Data Link Endpoint Identifier (DLEI)
>> + *
>> + */
>> +struct dect_dlei {
>> +       struct dect_mci mci;
>> +       enum dect_sapis sapi;
>> +       enum dect_llns  lln;
>> +};
>> +
>> +/**
>> + * struct dect_ulei - DECT U-Plane Link Endpoint Identifier
>> + */
>> +struct dect_ulei {
>> +       struct dect_mci mci;
>> +};
>> +
>> +#endif /* _NET_DECT_IDENTITIES_H */
>> diff --git a/target/linux/generic/files/include/net/dect/mac.h 
>> b/target/linux/generic/files/include/net/dect/mac.h
>> new file mode 100644
>> index 0000000..1f5c6e1
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/mac.h
>> @@ -0,0 +1,861 @@
>> +/*
>> + * DECT MAC Layer - Header and global definitions
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_MAC_H
>> +#define _NET_DECT_MAC_H
>> +
>> +#include <net/dect/identities.h>
>> +
>> +/*
>> + * A-Field
>> + */
>> +
>> +#define DECT_A_FIELD_SIZE      8
>> +
>> +#define DECT_RA_FIELD_SIZE     2
>> +#define DECT_RA_FIELD_OFF      6
>> +
>> +/*
>> + * Header field
>> + */
>> +
>> +#define DECT_HDR_FIELD_SIZE    1
>> +#define DECT_HDR_FIELD_OFF     0
>> +
>> +#define DECT_HDR_TA_OFF                0
>> +#define DECT_HDR_TA_MASK       0xe0
>> +#define DECT_HDR_TA_SHIFT      5
>> +
>> +#define DECT_HDR_Q1_OFF                0
>> +#define DECT_HDR_Q1_FLAG       0x10
>> +
>> +#define DECT_HDR_BA_OFF                0
>> +#define DECT_HDR_BA_MASK       0x0e
>> +#define DECT_HDR_BA_SHIFT      1
>> +
>> +#define DECT_HDR_Q2_OFF                0
>> +#define DECT_HDR_Q2_FLAG       0x01
>> +
>> +/*
>> + * T-Field
>> + */
>> +
>> +#define DECT_T_FIELD_OFF       1
>> +#define DECT_T_FIELD_SIZE      5
>> +
>> +/**
>> + * dect_tail_identification - MAC layer T-Field identification
>> + *
>> + * @DECT_TI_CT_PKT_0:          C_T data packet number 0
>> + * @DECT_TI_CT_PKT_1:          C_T data packet number 1
>> + * @DECT_TI_NT_CL:             Identities information on 
>> connectionless bearer
>> + * @DECT_TI_NT:                        Identities information
>> + * @DECT_TI_QT:                        Multiframe synchronisation und 
>> system information
>> + * @DECT_TI_RESERVED:          Reserved
>> + * @DECT_TI_MT:                        MAC layer control
>> + * @DECT_TI_PT:                        Paging tail (RFP only)
>> + * @DECT_TI_MT_PKT_0:          MAC layer control (first PP 
>> transmission, PP only)
>> + */
>> +enum dect_tail_identifications {
>> +       DECT_TI_CT_PKT_0        = 0x0 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_CT_PKT_1        = 0x1 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_NT_CL           = 0x2 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_NT              = 0x3 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_QT              = 0x4 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_RESERVED        = 0x5 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_MT              = 0x6 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_PT              = 0x7 << DECT_HDR_TA_SHIFT,
>> +       DECT_TI_MT_PKT_0        = 0x7 << DECT_HDR_TA_SHIFT,
>> +};
>> +
>> +struct dect_skb_a_cb {
>> +       enum dect_tail_identifications  id;
>> +};
>> +
>> +#define DECT_A_CB(skb)         ((struct dect_skb_a_cb *)(skb)->cb)
>> +
>> +/*
>> + * Identities channel (N-channel)
>> + */
>> +
>> +/* Identities information */
>> +#define DECT_NT_ID_RFPI_LEN    5
>> +
>> +/**
>> + * @e:         indicates whether SARIs are available
>> + * @pari:      primary access rights identifier
>> + * @rpn:       radio part number
>> + */
>> +struct dect_idi {
>> +       bool            e;
>> +       struct dect_ari pari;
>> +       u8              rpn;
>> +};
>> +
>> +/*
>> + * System information and multiframe marker (Q-channel)
>> + */
>> +
>> +/* RFP Q-channel T-MUX rules: only frame 8 */
>> +#define DECT_Q_CHANNEL_FRAME   8
>> +
>> +/* System information header */
>> +#define DECT_QT_H_MASK         0x00f0000000000000ULL
>> +#define DECT_QT_H_SHIFT                52
>> +
>> +/**
>> + * dect_system_information_types - codes for system information 
>> messages
>> + *
>> + * @DECT_QT_SI_SSI:            static system information
>> + * @DECT_QT_SI_ERFC:           extended RF carriers
>> + * @DECT_QT_SI_FPC:            fixed part capabilities
>> + * @DECT_QT_SI_EFPC:           extended fixed part capabilities
>> + * @DECT_QT_SI_SARI:           SARI list contents
>> + * @DECT_QT_SI_MFN:            multi-frame number
>> + * @DECT_QT_SI_ESC:            escape
>> + * @DECT_QT_SI_ERFC2:          extended RF carriers part 2
>> + * @DECT_QT_SI_TXI             transmit information
>> + * @DECT_QT_SI_EFPC2:          extended fixed part capabilities part 
>> 2
>> + */
>> +enum dect_mac_system_information_types {
>> +       DECT_QT_SI_SSI          = 0x0ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_SSI2         = 0x1ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_ERFC         = 0x2ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_FPC          = 0x3ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_EFPC         = 0x4ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_SARI         = 0x5ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_MFN          = 0x6ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_ESC          = 0x7ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_ERFC2        = 0x9ULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_TXI          = 0xbULL << DECT_QT_H_SHIFT,
>> +       DECT_QT_SI_EFPC2        = 0xcULL << DECT_QT_H_SHIFT,
>> +};
>> +
>> +/*
>> + * Static system information - repeated every 8 multiframes
>> + */
>> +
>> +#define DECT_QT_SSI_FREQ       8
>> +
>> +/* normal reverse */
>> +#define DECT_QT_SSI_NR_FLAG    0x0010000000000000ULL
>> +
>> +/* slot number */
>> +#define DECT_QT_SSI_SN_MASK    0x000f000000000000ULL
>> +#define DECT_QT_SSI_SN_SHIFT   48
>> +
>> +/* start position */
>> +#define DECT_QT_SSI_SP_MASK    0x0000c00000000000ULL
>> +#define DECT_QT_SSI_SP_SHIFT   46
>> +
>> +/* escape bit */
>> +#define DECT_QT_SSI_ESC_FLAG   0x0000200000000000ULL
>> +
>> +/* number of transceivers */
>> +#define DECT_QT_SSI_TXS_MASK   0x0000180000000000ULL
>> +#define DECT_QT_SSI_TXS_SHIFT  43
>> +
>> +/* extended RF carrier information available */
>> +#define DECT_QT_SSI_MC_FLAG    0x0000040000000000ULL
>> +
>> +/* RF carriers available */
>> +#define DECT_QT_SSI_RFCARS_MASK        0x000003ff00000000ULL
>> +#define DECT_QT_SSI_RFCARS_SHIFT 32
>> +
>> +/* carrier number */
>> +#define DECT_QT_SSI_CN_MASK    0x000000003f000000ULL
>> +#define DECT_QT_SSI_CN_SHIFT   24
>> +
>> +/* primary scan carrier number */
>> +#define DECT_QT_SSI_PSCN_MASK  0x00000000003f0000ULL
>> +#define DECT_QT_SSI_PSCN_SHIFT 16
>> +
>> +struct dect_ssi {
>> +       bool    nr;
>> +       bool    mc;
>> +       u16     rfcars;
>> +       u8      sn;
>> +       u8      sp;
>> +       u8      txs;
>> +       u8      cn;
>> +       u8      pscn;
>> +};
>> +
>> +/*
>> + * Extended RF carrier information
>> + */
>> +
>> +#define DECT_QT_ERFC_FREQ              8
>> +
>> +#define DECT_QT_ERFC_RFCARS_MASK       0x000fffffe0000000ULL
>> +#define DECT_QT_ERFC_RFCARS_SHIFT      1
>> +
>> +#define DECT_QT_ERFC_RFBAND_MASK       0x000000001f000000ULL
>> +#define DECT_QT_ERFC_RFBAND_SHIFT      24
>> +
>> +#define DECT_QT_ERFC_ERFC2_FLAG                0x0000000000800000ULL
>> +
>> +#define DECT_QT_ERFC_NUM_RFCARS_MASK   0x00000000003f0000ULL
>> +#define DECT_QT_ERFC_NUM_RFCARS_SHIFT  16
>> +
>> +struct dect_erfc {
>> +       u32     rfcars;
>> +       u8      band;
>> +       u8      num_rfcars;
>> +       bool    erfc2;
>> +};
>> +
>> +/*
>> + * Fixed Part capabilities
>> + */
>> +
>> +#define DECT_QT_FPC_FREQ               8
>> +
>> +#define DECT_QT_FPC_CAPABILITY_MASK    0x000fffff00000000ULL
>> +#define DECT_QT_FPC_CAPABILITY_SHIFT   32
>> +
>> +#define DECT_QT_FPC_HLC_MASK           0x00000000ffff0000ULL
>> +#define DECT_QT_FPC_HLC_SHIFT          16
>> +
>> +struct dect_fpc {
>> +       u32     fpc;
>> +       u16     hlc;
>> +};
>> +
>> +/*
>> + * Extended Fixed Part capabilities
>> + */
>> +
>> +#define DECT_QT_EFPC_EFPC_MASK         0x000fff8000000000ULL
>> +#define DECT_QT_EFPC_EFPC_SHIFT                39
>> +
>> +#define DECT_QT_EFPC_EHLC_MASK         0x0000007fffff0000ULL
>> +#define DECT_QT_EFPC_EHLC_SHIFT                16
>> +
>> +struct dect_efpc {
>> +       u16     fpc;
>> +       u32     hlc;
>> +};
>> +
>> +#define DECT_QT_EFPC2_FPC_MASK         0x000fff0000000000ULL
>> +#define DECT_QT_EFPC2_FPC_SHIFT                40
>> +
>> +#define DECT_QT_EFPC2_HLC_MASK         0x000000ffffff0000ULL
>> +#define DECT_QT_EFPC2_HLC_SHIFT                16
>> +
>> +struct dect_efpc2 {
>> +       u16     fpc;
>> +       u32     hlc;
>> +};
>> +
>> +/*
>> + * SARI message
>> + */
>> +
>> +#define DECT_QT_SARI_FREQ              4
>> +
>> +#define DECT_QT_SARI_LIST_CYCLE_MASK   0x00000e0000000000ULL
>> +#define DECT_QT_SARI_LIST_CYCLE_SHIFT  41
>> +
>> +#define DECT_QT_SARI_TARI_FLAG         0x0000010000000000ULL
>> +
>> +#define DECT_QT_SARI_BLACK_FLAG                0x0000008000000000ULL
>> +
>> +#define DECT_QT_SARI_ARI_MASK          0x0000007fffffff00ULL
>> +#define DECT_QT_SARI_ARI_SHIFT         25
>> +
>> +struct dect_sari {
>> +       u8              list_cycle;
>> +       bool            tari;
>> +       bool            black;
>> +       struct dect_ari ari;
>> +};
>> +
>> +#define DECT_SARI_CYCLE_MAX            16
>> +
>> +/*
>> + * Multiframe number - repeated every 8 multiframes if supported
>> + */
>> +
>> +#define DECT_QT_MFN_FREQ               8
>> +
>> +#define DECT_QT_MFN_MASK               0x000000ffffff0000ULL
>> +#define DECT_QT_MFN_SHIFT              16
>> +
>> +struct dect_mfn {
>> +       u32     num;
>> +};
>> +
>> +/*
>> + * Extended RF carrier information part 2
>> + */
>> +
>> +#define DECT_QT_TXI_ERFC2_FREQ         8
>> +
>> +#define DECT_QT_ERFC2_RFCARS_MASK      0x000fffffffe00000ULL
>> +#define DECT_QT_ERFC2_RFCARS_SHIFT     21
>> +
>> +struct dect_erfc2 {
>> +       u32     rfcars;
>> +};
>> +
>> +/*
>> + * Transmit Information
>> + */
>> +
>> +#define DECT_QT_TXI_FREQ               8
>> +
>> +#define DECT_QT_TXI_TYPE_MASK          0x000f000000000000ULL
>> +#define DECT_QT_TXI_TYPE_SHIFT         48
>> +
>> +#define DECT_QT_TXI_PWL_MASK           0x0000ff0000000000ULL
>> +#define DECT_QT_TXI_PWL_SHIFT          40
>> +
>> +/*
>> + * Extended fixed part capabilitiees part 2
>> + */
>> +
>> +/*
>> + * Paging Tail (P-channel)
>> + */
>> +
>> +#define DECT_PT_HDR_EXTEND_FLAG                0x0080000000000000ULL
>> +
>> +#define DECT_PT_HDR_LENGTH_MASK                0x0070000000000000ULL
>> +#define DECT_PT_HDR_LENGTH_SHIFT       52
>> +
>> +/**
>> + * @DECT_PT_ZERO_PAGE:         zero length page
>> + * @DECT_PT_SHORT_PAGE:                short page
>> + * @DECT_PT_FULL_PAGE:         full page
>> + * @DECT_PT_MAX_RESUME_PAGE:   MAC resume and control page
>> + * @DECT_PT_LONG_PAGE:         not the last 36 bits of a long page
>> + * @DECT_PT_LONG_PAGE_FIRST:   the first 36 bits of a long page
>> + * @DECT_PT_LONG_PAGE_LAST:    the last 36 bits of a long page
>> + * @DECT_PT_LONG_PAGE_ALL:     all of a long page (first and last)
>> + *
>> + */
>> +enum dect_page_lengths {
>> +       DECT_PT_ZERO_PAGE               = 0x0ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_SHORT_PAGE              = 0x1ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_FULL_PAGE               = 0x2ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_RESUME_PAGE             = 0x3ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_LONG_PAGE               = 0x4ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_LONG_PAGE_FIRST         = 0x5ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_LONG_PAGE_LAST          = 0x6ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +       DECT_PT_LONG_PAGE_ALL           = 0x7ULL << 
>> DECT_PT_HDR_LENGTH_SHIFT,
>> +};
>> +
>> +/* zero length pages */
>> +#define DECT_PT_ZP_RFPI_MASK           0x000fffff00000000ULL
>> +#define DECT_PT_ZP_RFPI_SHIFT          32
>> +
>> +/* short page B_S channel data */
>> +#define DECT_PT_SP_BS_DATA_MASK                0x000fffff00000000ULL
>> +#define DECT_PT_SP_BS_DATA_SHIFT       32
>> +#define DECT_PT_SP_BS_DATA_SIZE                3
>> +
>> +/* long and full page B_S channel data */
>> +#define DECT_PT_LFP_BS_DATA_MASK       0x000fffffffff0000ULL
>> +#define DECT_PT_LFP_BS_DATA_SHIFT      16
>> +#define DECT_PT_LFP_BS_DATA_SIZE       5
>> +
>> +struct dect_page {
>> +       bool                    extend;
>> +       enum dect_page_lengths  length;
>> +       u32                     rfpi;
>> +};
>> +
>> +/* MAC layer information */
>> +#define DECT_PT_INFO_TYPE_MASK         0x00000000f0000000ULL
>> +#define DECT_PT_INFO_TYPE_SHIFT                28
>> +#define DECT_PT_INFO_TYPE_SIZE         2
>> +
>> +/**
>> + * @DECT_PT_IT_FILL_BITS_OR_BLIND_LONG_SLOTS:  fill bits/blind long 
>> slots if bit 47 set
>> + * @DECT_PT_IT_BLIND_FULL_SLOT:                        blind full 
>> slot information
>> + * @DECT_PT_IT_OTHER_BEARER:
>> + * @DECT_PT_IT_RECOMMENDED_OTHER_BEARER:
>> + * @DECT_PT_IT_GOOD_RFP_BEARER:
>> + * @DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION:
>> + * @DECT_PT_IT_RFP_IDENTITY:
>> + * @DECT_PT_IT_ESCAPE:
>> + * @DECT_PT_IT_DUMMY_OR_CL_BEARER_MARKER:
>> + * @DECT_PT_IT_BEARER_HANDOVER_INFO:
>> + * @DECT_PT_IT_RFP_STATUS:
>> + * @DECT_PT_IT_ACTIVE_CARRIERS:
>> + * @DECT_PT_IT_CL_BEARER_POSITION:
>> + * @DECT_PT_IT_RECOMMENDED_POWER_LEVEL:
>> + * @DECT_PT_IT_BLIND_DOUBLE_SLOT:
>> + * @DECT_PT_IT_BLIND_FULL_SLOT_PACKET_MODE:
>> + *
>> + */
>> +enum dect_pt_info_types {
>> +       DECT_PT_IT_FILL_BITS_OR_BLIND_LONG_SLOTS= 0x0ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_BLIND_FULL_SLOT              = 0x1ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_OTHER_BEARER                 = 0x2ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_RECOMMENDED_OTHER_BEARER     = 0x3ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_GOOD_RFP_BEARER              = 0x4ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION  = 0x5ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_RFP_IDENTITY                 = 0x6ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_ESCAPE                       = 0x7ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_DUMMY_OR_CL_BEARER_MARKER    = 0x8ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_BEARER_HANDOVER_INFO         = 0x9ULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_RFP_STATUS                   = 0xaULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_ACTIVE_CARRIERS              = 0xbULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_CL_BEARER_POSITION           = 0xcULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_RECOMMENDED_POWER_LEVEL      = 0xdULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_BLIND_DOUBLE_SLOT            = 0xeULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +       DECT_PT_IT_BLIND_FULL_SLOT_PACKET_MODE  = 0xfULL << 
>> DECT_PT_INFO_TYPE_SHIFT,
>> +};
>> +
>> +/* blind full slot information */
>> +#define DECT_PT_BFS_MASK               0x000000000fff0000ULL
>> +#define DECT_PT_BFS_SHIFT              16
>> +
>> +struct dect_bfs {
>> +       struct dect_page        page;
>> +       u16                     mask;
>> +};
>> +
>> +/* Bearer description */
>> +#define DECT_PT_BEARER_SN_MASK         0x000000000f000000ULL
>> +#define DECT_PT_BEARER_SN_SHIFT                24
>> +
>> +#define DECT_PT_BEARER_SP_MASK         0x0000000000c00000ULL
>> +#define DECT_PT_BEARER_SP_SHIFT                22
>> +
>> +#define DECT_PT_BEARER_CN_MASK         0x00000000003f0000ULL
>> +#define DECT_PT_BEARER_CN_SHIFT                16
>> +
>> +struct dect_bearer_desc {
>> +       struct dect_page        page;
>> +       enum dect_pt_info_types bt;
>> +       u8                      sn;
>> +       u8                      sp;
>> +       u8                      cn;
>> +};
>> +
>> +/* RFP identity */
>> +#define DECT_PT_RFP_ID_MASK            0x000000000fff0000ULL
>> +#define DECT_PT_RFP_ID_SHIFT           16
>> +
>> +struct dect_rfp_id {
>> +       struct dect_page        page;
>> +       u16                     id;
>> +};
>> +
>> +/* RFP status */
>> +#define DECT_PT_RFPS_RFP_BUSY_FLAG     0x0000000001000000ULL
>> +#define DECT_PT_RFPS_SYS_BUSY_FLAG     0x0000000002000000ULL
>> +
>> +struct dect_rfp_status {
>> +       struct dect_page        page;
>> +       bool                    rfp_busy;
>> +       bool                    sys_busy;
>> +};
>> +
>> +/* Active carriers */
>> +#define DECT_PT_ACTIVE_CARRIERS_MASK   0x000000000ffc0000ULL
>> +#define DECT_PT_ACTIVE_CARRIERS_SHIFT  18
>> +
>> +struct dect_active_carriers {
>> +       struct dect_page        page;
>> +       u16                     active;
>> +};
>> +
>> +/*
>> + * MAC control (M-channel)
>> + */
>> +
>> +#define DECT_MT_FRAME_RATE             2
>> +
>> +#define DECT_MT_HDR_MASK               0x00f0000000000000ULL
>> +#define DECT_MT_HDR_SHIFT              52
>> +
>> +#define DECT_MT_CMD_MASK               0x000f000000000000ULL
>> +#define DECT_MT_CMD_SHIFT              48
>> +
>> +/**
>> + * enum dect_mt_hdr_type - MAC tail header types
>> + */
>> +enum dect_mt_hdr_type {
>> +       DECT_MT_BASIC_CCTRL                     = 0x0ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_ADV_CCTRL                       = 0x1ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_MAC_TEST                        = 0x2ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_QUALITY_CTRL                    = 0x3ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_BRD_CL_SERVICE                  = 0x4ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_ENC_CTRL                        = 0x5ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_XYZ                             = 0x6ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_ESC                             = 0x7ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_TARI                            = 0x8ULL << 
>> DECT_MT_HDR_SHIFT,
>> +       DECT_MT_REP_CCTRL                       = 0x9ULL << 
>> DECT_MT_HDR_SHIFT,
>> +};
>> +
>> +/* advanced connection control */
>> +enum dect_cctrl_cmds {
>> +       DECT_CCTRL_ACCESS_REQ                   = 0x0ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_BEARER_HANDOVER_REQ          = 0x1ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_CONNECTION_HANDOVER_REQ      = 0x2ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_UNCONFIRMED_ACCESS_REQ       = 0x3ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_BEARER_CONFIRM               = 0x4ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_WAIT                         = 0x5ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_ATTRIBUTES_T_REQUEST         = 0x6ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_ATTRIBUTES_T_CONFIRM         = 0x7ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_BANDWIDTH_T_REQUEST          = 0x8ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_BANDWIDTH_T_CONFIRM          = 0x9ULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_CHANNEL_LIST                 = 0xaULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_UNCONFIRMED_DUMMY            = 0xbULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_UNCONFIRMED_HANDOVER         = 0xcULL << 
>> DECT_MT_CMD_SHIFT,
>> +       DECT_CCTRL_RELEASE                      = 0xfULL << 
>> DECT_MT_CMD_SHIFT,
>> +};
>> +
>> +/* Most messages */
>> +#define DECT_CCTRL_FMID_MASK                   0x0000fff000000000ULL
>> +#define DECT_CCTRL_FMID_SHIFT                  36
>> +
>> +#define DECT_CCTRL_PMID_MASK                   0x0000000fffff0000ULL
>> +#define DECT_CCTRL_PMID_SHIFT                  16
>> +
>> +/* Attributes-T request/confirm */
>> +#define DECT_CCTRL_ATTR_ECN_MASK               0x0000f00000000000ULL
>> +#define DECT_CCTRL_ATTR_ECN_SHIFT              44
>> +
>> +#define DECT_CCTRL_ATTR_LBN_MASK               0x00000f0000000000ULL
>> +#define DECT_CCTRL_ATTR_LBN_SHIFT              40
>> +
>> +#define DECT_CCTRL_ATTR_TYPE_MASK              0x000000c000000000ULL
>> +#define DECT_CCTRL_ATTR_TYPE_SHIFT             38
>> +
>> +enum dect_cctrl_connection_types {
>> +       DECT_CCTRL_TYPE_ASYMETRIC_UPLINK        = 0x0,
>> +       DECT_CCTRL_TYPE_ASYMETRIC_DOWNLINK      = 0x1,
>> +       DECT_CCTRL_TYPE_SYMETRIC_MULTIBEARER    = 0x2,
>> +       DECT_CCTRL_TYPE_SYMETRIC_BEARER         = 0x3,
>> +};
>> +
>> +#define DECT_CCTRL_ATTR_SERVICE_MASK           0x0000003f00000000ULL
>> +#define DECT_CCTRL_ATTR_SERVICE_SHIFT          32
>> +
>> +#define DECT_CCTRL_ATTR_SLOT_MASK              0x00000000f0000000ULL
>> +#define DECT_CCTRL_ATTR_SLOT_SHIFT             28
>> +
>> +#define DECT_CCTRL_ATTR_CF_FLAG                        
>> 0x0000000008000000ULL
>> +
>> +#define DECT_CCTRL_ATTR_BZ_EXT_MOD_MASK                
>> 0x0000000007000000ULL
>> +#define DECT_CCTRL_ATTR_BZ_EXT_MOD_SHIFT       24
>> +
>> +#define DECT_CCTRL_ATTR_ACR_MASK               0x0000000000f00000ULL
>> +#define DECT_CCTRL_ATTR_ACR_SHIFT              20
>> +
>> +enum dect_adaptive_code_rates {
>> +       DECT_ACR_NONE                           = 0x0,
>> +};
>> +
>> +#define DECT_CCTRL_ATTR_A_MOD_MASK             0x00000000000c0000ULL
>> +#define DECT_CCTRL_ATTR_A_MOD_SHIFT            18
>> +
>> +#define DECT_CCTRL_ATTR_BZ_MOD_MASK            0x0000000000030000ULL
>> +#define DECT_CCTRL_ATTR_BZ_MOD_SHIFT           16
>> +
>> +enum dect_modulation_type {
>> +       DECT_MODULATION_2_LEVEL                 = 0x3,
>> +       DECT_MODULATION_4_LEVEL                 = 0x2,
>> +       DECT_MODULATION_8_LEVEL                 = 0x1,
>> +};
>> +
>> +/* Release */
>> +
>> +#define DECT_CCTRL_RELEASE_INFO1_MASK          0x0000f00000000000ULL
>> +#define DECT_CCTRL_RELEASE_INFO1_SHIFT         44
>> +
>> +#define DECT_CCTRL_RELEASE_LBN_MASK            0x00000f0000000000ULL
>> +#define DECT_CCTRL_RELEASE_LBN_SHIFT           40
>> +
>> +#define DECT_CCTRL_RELEASE_REASON_MASK         0x000000f000000000ULL
>> +#define DECT_CCTRL_RELEASE_REASON_SHIFT                36
>> +
>> +enum dect_release_reasons {
>> +       DECT_REASON_UNKNOWN                             = 0x0,
>> +       DECT_REASON_BEARER_RELEASE                      = 0x1,
>> +       DECT_REASON_CONNECTION_RELEASE                  = 0x2,
>> +       DECT_REASON_BEARER_SETUP_OR_HANDOVER_FAILED     = 0x3,
>> +       DECT_REASON_BEARER_HANDOVER_COMPLETED           = 0x4,
>> +       DECT_REASON_BEARER_HANDOVER_CLUSTER             = 0x5,
>> +       DECT_REASON_TIMEOUT_LOST_SIGNAL                 = 0x6,
>> +       DECT_REASON_TIMEOUT_LOST_HANDSHAKE              = 0x7,
>> +       DECT_REASON_REQUESTED_UNACCEPTABLE_SLOT_TYPE    = 0x8,
>> +       DECT_REASON_REQUESTED_UNACCEPTABLE_MAC_SERVICE  = 0x9,
>> +       DECT_REASON_BASE_STATION_BUSY                   = 0xa,
>> +       DECT_REASON_REVERSE_DIRECTION                   = 0xb,
>> +       DECT_REASON_DUPLICATE_PMID                      = 0xc,
>> +       DECT_REASON_UNACCEPTABLE_PMID                   = 0xd,
>> +       DECT_REASON_STAY_ON_LISTEN                      = 0xe,
>> +};
>> +
>> +#define DECT_CCTRL_RELEASE_PMID_MASK           0x0000000fffff0000ULL
>> +#define DECT_CCTRL_RELEASE_PMID_SHIFT          16
>> +
>> +struct dect_cctrl {
>> +       enum dect_cctrl_cmds            cmd;
>> +       union {
>> +               struct {
>> +                       union {
>> +                               struct {
>> +                                       u16             fmid;
>> +                               };
>> +                               struct {
>> +                                       u8              lbn;
>> +                                       union {
>> +                                               u8              ecn;
>> +                                               u8              
>> reason;
>> +                                       };
>> +                               };
>> +                       };
>> +                       union {
>> +                               u32             pmid;
>> +                               struct {
>> +                                       u8              type;
>> +                                       u8              service;
>> +                                       u8              slot;
>> +                                       u8              cf;
>> +                                       u8              a_mod;
>> +                                       u8              bz_mod;
>> +                                       u8              bz_ext_mod;
>> +                                       u8              acr;
>> +                               };
>> +                       };
>> +               };
>> +       };
>> +};
>> +
>> +/* Encryption Control */
>> +
>> +#define DECT_ENCCTRL_FILL_MASK                 0x0050000000000000ULL
>> +
>> +#define DECT_ENCCTRL_CMD_MASK                  0x000f000000000000ULL
>> +#define DECT_ENCCTRL_CMD_SHIFT                 48
>> +
>> +enum dect_encctrl_cmds {
>> +       DECT_ENCCTRL_START_REQUEST              = 0x0,
>> +       DECT_ENCCTRL_START_CONFIRM              = 0x1,
>> +       DECT_ENCCTRL_START_GRANT                = 0x2,
>> +       DECT_ENCCTRL_STOP_REQUEST               = 0x4,
>> +       DECT_ENCCTRL_STOP_CONFIRM               = 0x5,
>> +       DECT_ENCCTRL_STOP_GRANT                 = 0x6,
>> +};
>> +
>> +#define DECT_ENCCTRL_FMID_MASK                 0x0000fff000000000ULL
>> +#define DECT_ENCCTRL_FMID_SHIFT                        36
>> +
>> +#define DECT_ENCCTRL_PMID_MASK                 0x0000000fffff0000ULL
>> +#define DECT_ENCCTRL_PMID_SHIFT                        16
>> +
>> +struct dect_encctrl {
>> +       enum dect_encctrl_cmds  cmd;
>> +       u32                     pmid;
>> +       u16                     fmid;
>> +};
>> +
>> +/* marker for T-MUX exceptions */
>> +#define DECT_MT_HIGH_PRIORITY          0x1
>> +
>> +/*
>> + * C_T data
>> + */
>> +
>> +#define DECT_C_S_SDU_SIZE              5
>> +
>> +struct dect_ct_data {
>> +       u8                              seq;
>> +};
>> +
>> +/*
>> + * Flat representation of tail message contents
>> + */
>> +enum dect_tail_msg_types {
>> +       DECT_TM_TYPE_INVALID,
>> +       DECT_TM_TYPE_ID,
>> +       DECT_TM_TYPE_SSI,
>> +       DECT_TM_TYPE_ERFC,
>> +       DECT_TM_TYPE_FPC,
>> +       DECT_TM_TYPE_EFPC,
>> +       DECT_TM_TYPE_EFPC2,
>> +       DECT_TM_TYPE_SARI,
>> +       DECT_TM_TYPE_MFN,
>> +       DECT_TM_TYPE_PAGE,
>> +       DECT_TM_TYPE_BFS,
>> +       DECT_TM_TYPE_BD,
>> +       DECT_TM_TYPE_RFP_ID,
>> +       DECT_TM_TYPE_RFP_STATUS,
>> +       DECT_TM_TYPE_ACTIVE_CARRIERS,
>> +       DECT_TM_TYPE_BCCTRL,
>> +       DECT_TM_TYPE_ACCTRL,
>> +       DECT_TM_TYPE_ENCCTRL,
>> +       DECT_TM_TYPE_CT,
>> +};
>> +
>> +struct dect_tail_msg {
>> +       enum dect_tail_identifications          ti;
>> +       enum dect_tail_msg_types                type;
>> +       union {
>> +               struct dect_idi                 idi;
>> +               struct dect_ssi                 ssi;
>> +               struct dect_erfc                erfc;
>> +               struct dect_fpc                 fpc;
>> +               struct dect_efpc                efpc;
>> +               struct dect_efpc2               efpc2;
>> +               struct dect_sari                sari;
>> +               struct dect_mfn                 mfn;
>> +               struct dect_page                page;
>> +               struct dect_bfs                 bfs;
>> +               struct dect_bearer_desc         bd;
>> +               struct dect_rfp_id              rfp_id;
>> +               struct dect_rfp_status          rfp_status;
>> +               struct dect_active_carriers     active_carriers;
>> +               struct dect_cctrl               cctl;
>> +               struct dect_encctrl             encctl;
>> +               struct dect_ct_data             ctd;
>> +       };
>> +};
>> +
>> +struct dect_si {
>> +       u32                             mask;
>> +       struct dect_ssi                 ssi;
>> +       struct dect_erfc                erfc;
>> +       struct dect_fpc                 fpc;
>> +       struct dect_efpc                efpc;
>> +       struct dect_efpc2               efpc2;
>> +       struct dect_sari                sari[DECT_SARI_CYCLE_MAX];
>> +       struct dect_mfn                 mfn;
>> +       u8                              num_saris;
>> +};
>> +
>> +/*
>> + * B-Field
>> + */
>> +
>> +/**
>> + * dect_b_identitifications - MAC layer B-Field Identification
>> + *
>> + * @DECT_BI_UTYPE_0:           U-Type, I_N, SI_N, SI_P or I_P packet 
>> number 0
>> + * @DECT_BI_UTYPE_1:           U-Type, I_P error detect or I_P packet 
>> number 1
>> + * @DECT_BI_ETYPE_CF_0:                E-Type, all C_F or CL_F, 
>> packet number 0
>> + * @DECT_BI_ETYPE_CF_1:                E-Type, all C_F, packet number 
>> 1
>> + * @DECT_BI_ETYPE_MAC:         E-Type, all MAC control (unnumbered)
>> + * @DECT_BI_NONE:              no B-Field
>> + */
>> +enum dect_b_identifications {
>> +       DECT_BI_UTYPE_0                 = 0x0 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_UTYPE_1                 = 0x1 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_ETYPE_CF_0              = 0x2 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_DOUBLE_SLOT_REQUIRED    = DECT_BI_ETYPE_CF_0,
>> +       DECT_BI_ETYPE_CF_1              = 0x3 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_ETYPE_NOT_ALL_CF_0      = 0x4 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_HALF_SLOT_REQUIRED      = DECT_BI_ETYPE_NOT_ALL_CF_0,
>> +       DECT_BI_ETYPE_NOT_ALL_CF_1      = 0x5 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_LONG_SLOT_640_REQUIRED  = DECT_BI_ETYPE_NOT_ALL_CF_1,
>> +       DECT_BI_ETYPE_MAC               = 0x6 << DECT_HDR_BA_SHIFT,
>> +       DECT_BI_LONG_SLOT_672_REQUIRED  = DECT_BI_ETYPE_MAC,
>> +       DECT_BI_NONE                    = 0x7 << DECT_HDR_BA_SHIFT,
>> +};
>> +
>> +struct dect_skb_b_cb {
>> +       enum dect_b_identifications     id;
>> +};
>> +
>> +#define DECT_B_CB(skb)         ((struct dect_skb_b_cb *)(skb)->cb)
>> +
>> +#define DECT_C_F_SDU_SIZE      8
>> +#define DECT_G_F_SDU_SIZE      8
>> +
>> +/**
>> + * enum dect_mac_channels - internal MAC control channels
>> + *
>> + * @DECT_MC_Q:         System information and multiframe marker
>> + * @DECT_MC_N:         Identities information
>> + * @DECT_MC_M:         MAC control channel
>> + * @DECT_MC_P:         MAC Paging channel
>> + */
>> +enum dect_mac_channels {
>> +       DECT_MC_Q,
>> +       DECT_MC_N,
>> +       DECT_MC_M,
>> +       DECT_MC_P,
>> +};
>> +
>> +/**
>> + * enum dect_data_channels - logical MAC data channels
>> + *
>> + * @DECT_MC_G_F:
>> + * @DECT_MC_C_S:       Higher layer C-Plane channel (slow)
>> + * @DECT_MC_C_F:       Higher layer C-Plane channel (fast)
>> + * @DECT_MC_I_N:       Higher layer U-Plane channel (numbered)
>> + * @DECT_MC_I_P:       Higher layer U-Plane channel (protected)
>> + * @DECT_MC_SI_N:      Higher layer connectionless U-Plane channel 
>> (numbered)
>> + * @DECT_MC_SI_P:      Higher layer connectionless U-Plane channel 
>> (protected)
>> + */
>> +enum dect_data_channels {
>> +       DECT_MC_G_F,
>> +       DECT_MC_C_S,
>> +       DECT_MC_C_F,
>> +       DECT_MC_I_N,
>> +       DECT_MC_I_P,
>> +       DECT_MC_SI_N,
>> +       DECT_MC_SI_P,
>> +       __DECT_MC_MAX
>> +};
>> +#define DECT_MC_MAX            (__DECT_MC_MAX - 1)
>> +
>> +/**
>> + * enum dect_mac_connection_types - MAC Connection types
>> + *
>> + * @DECT_MAC_CONN_BASIC:       Basic connection, always I_N_min_delay 
>> service
>> + * @DECT_MAC_CONN_ADVANCED:    Advanced connection
>> + * @DECT_MAC_CONN_COMPLEMENT:  Complementary connection
>> + */
>> +enum dect_mac_connection_types {
>> +       DECT_MAC_CONN_BASIC,
>> +       DECT_MAC_CONN_ADVANCED,
>> +       DECT_MAC_CONN_COMPLEMENT,
>> +};
>> +
>> +/**
>> + * struct dect_tbc_id
>> + *
>> + * @ari:               FT identifier
>> + * @pmid:              Portable MAC identity
>> + * @lbn:               Logical Bearer Number
>> + * @enc:               Exchanged connection number
>> + * @tbei:              Traffic Bearer Endpoint Identifier
>> + */
>> +struct dect_tbc_id {
>> +       struct dect_ari                 ari;
>> +       struct dect_pmid                pmid;
>> +       u8                              lbn;
>> +       u8                              ecn;
>> +       u32                             tbei;
>> +};
>> +
>> +/**
>> + * struct dect_mbc_id
>> + *
>> + * @mcei:              MAC Connection Endpoint Identifier
>> + * @type:              Connection Type (Basic/Advanced)
>> + * @ari:               FT identifier
>> + * @pmid:              Portable MAC Identity
>> + * @ecn:               Exchanged Connection Number
>> + * @service:           Service type
>> + */
>> +struct dect_mbc_id {
>> +       u32                             mcei;
>> +       enum dect_mac_connection_types  type;
>> +       struct dect_ari                 ari;
>> +       struct dect_pmid                pmid;
>> +       u8                              ecn;
>> +};
>> +
>> +#endif /* _NET_DECT_MAC_H */
>> diff --git a/target/linux/generic/files/include/net/dect/mac_ccf.h 
>> b/target/linux/generic/files/include/net/dect/mac_ccf.h
>> new file mode 100644
>> index 0000000..e3cb1ba
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/mac_ccf.h
>> @@ -0,0 +1,250 @@
>> +/*
>> + * DECT MAC Layer - Cluster Control Functions (CCF)
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_MAC_CCF_H
>> +#define _NET_DECT_MAC_CCF_H
>> +
>> +#include <linux/skbuff.h>
>> +#include <linux/timer.h>
>> +#include <net/dect/mac.h>
>> +
>> +/**
>> + * struct dect_bmc_skb_cb
>> + *
>> + * @fast_page:         page message is a fast page
>> + * @long_page:         page message is a long page
>> + * @stamp:             multiframe number at time of TX request
>> + * @repetitions:       number of page repetitions
>> + */
>> +struct dect_bmc_skb_cb {
>> +       bool                            fast_page;
>> +       bool                            long_page;
>> +       u32                             stamp;
>> +       u8                              repetitions;
>> +};
>> +#define DECT_BMC_CB(skb)               ((struct dect_bmc_skb_cb 
>> *)(skb)->cb)
>> +
>> +#define DECT_PAGE_LIFETIME             6       /* multiframes */
>> +
>> +/**
>> + * struct dect_bmc - broadcast message control
>> + *
>> + * @bcs:               broadcast controller list
>> + * @index:             system information round robin index
>> + */
>> +struct dect_bmc {
>> +       struct list_head                bcs;
>> +       unsigned int                    index;
>> +};
>> +
>> +struct dect_cmc {
>> +
>> +};
>> +
>> +struct dect_cs_skb_cb {
>> +       u8                              seq;
>> +};
>> +#define DECT_CS_CB(skb)                        ((struct 
>> dect_cs_skb_cb *)(skb)->cb)
>> +
>> +/**
>> + * struct dect_tb - DECT Traffic Bearer
>> + *
>> + * @list:              MBC traffic bearer list node
>> + * @mbc:               MBC controlling the traffic bearer
>> + * @ch:                        Cell handling the traffic bearer
>> + * @id:                        Traffic Bearer Controller ID
>> + * @handover:          Handover yes/no
>> + * @handover_timer:    Handover timer
>> + * @rx_slot:           Receive slot
>> + * @tx_slot:           Transmit slot
>> + * @slot_rx_timer:     Receive slot timer
>> + * @slot_tx_timer:     Transmit slot timer
>> + * @b_rx_skb:          B-Field receive skb
>> + */
>> +struct dect_tb {
>> +       struct list_head                list;
>> +       struct dect_mbc                 *mbc;
>> +       const struct dect_cell_handle   *ch;
>> +       struct dect_tbc_id              id;
>> +       bool                            handover;
>> +
>> +       /* FP: handover release timer */
>> +       struct dect_timer               handover_timer;
>> +
>> +       /* Slot transmit/receive timers */
>> +       u8                              rx_slot;
>> +       u8                              tx_slot;
>> +       struct dect_timer               slot_rx_timer;
>> +       struct dect_timer               slot_tx_timer;
>> +
>> +       /* I channel data */
>> +       struct sk_buff                  *b_rx_skb;
>> +};
>> +
>> +struct dect_mbc_stats {
>> +       unsigned int                    cs_rx_bytes;
>> +       unsigned int                    cs_tx_bytes;
>> +       unsigned int                    i_rx_bytes;
>> +       unsigned int                    i_tx_bytes;
>> +       unsigned int                    handovers;
>> +};
>> +
>> +/**
>> + * struct dect_mbc - DECT Multi-Bearer Control
>> + *
>> + * @list:              Cluster connection list node
>> + * @cl:                        Cluster the MBC is contained in
>> + * @refcnt:            Reference count
>> + * @type:              connection type
>> + * @id:                        MBC identity
>> + * @state:             MBC state
>> + * @timer:             Connection setup timer (T200)
>> + * @setup_cnt:         number of setup attempts (N200)
>> + * @tbs:               List of traffic bearers
>> + * @ho_stamp:          Handover token bucket refill timestamp
>> + * @ho_tokens:         Handover token bucket tokens
>> + * @normal_rx_timer:   Normal receive half frame timer
>> + * @onrmal_tx_timer:   Normal transmit half frame timer
>> + * @ck:                        Cipher key
>> + * @cipher_state:      Ciphering state
>> + * @cs_rx_seq:         C_S receive sequence number
>> + * @cs_tx_seq:         C_S transmit sequence number
>> + * @cs_tx_ok:          C_S segment transmit OK
>> + * @cs_rx_ok:          C_S segment reception OK
>> + * @cs_tx_skb:         C_S segment queued for transmission
>> + * @cs_tx_skb:         C_S segment queued for delivery to DLC
>> + */
>> +struct dect_mbc {
>> +       struct list_head                list;
>> +       struct dect_cluster             *cl;
>> +       unsigned int                    refcnt;
>> +
>> +       enum dect_mac_connection_types  type;
>> +       struct dect_mbc_id              id;
>> +       enum dect_mbc_state             state;
>> +       enum dect_mac_service_types     service;
>> +
>> +       struct timer_list               timer;
>> +       u8                              setup_cnt;
>> +
>> +       struct list_head                tbs;
>> +
>> +       /* Handover rate limiting */
>> +       unsigned long                   ho_stamp;
>> +       u8                              ho_tokens;
>> +
>> +       /* Normal transmit/receive timers */
>> +       struct dect_timer               normal_rx_timer;
>> +       struct dect_timer               normal_tx_timer;
>> +
>> +       /* Encryption */
>> +       u64                             ck;
>> +       enum dect_cipher_states         cipher_state;
>> +
>> +       /* C_S channel */
>> +       u8                              cs_rx_seq;
>> +       u8                              cs_tx_seq;
>> +       bool                            cs_tx_ok;
>> +       bool                            cs_rx_ok;
>> +       struct sk_buff                  *cs_rx_skb;
>> +       struct sk_buff                  *cs_tx_skb;
>> +
>> +       struct dect_mbc_stats           stats;
>> +};
>> +
>> +#define DECT_MBC_SETUP_TIMEOUT         (5 * HZ)        /* T200: 5 
>> seconds */
>> +#define DECT_MBC_SETUP_MAX_ATTEMPTS    10              /* N200: 10 
>> attempts */
>> +#define DECT_MBC_HANDOVER_TIMER                (3 * HZ)        /* 
>> T202: 3 seconds */
>> +#define DECT_MBC_TB_HANDOVER_TIMEOUT   16              /* T203: 16 
>> frames */
>> +
>> +#define DECT_MBC_HANDOVER_LIMIT                2               /* per 
>> N202 seconds */
>> +#define DECT_MBC_HANDOVER_REATTEMPTS   15              /* N201: 15 */
>> +
>> +extern u32 dect_mbc_alloc_mcei(struct dect_cluster *cl);
>> +extern int dect_mac_con_req(struct dect_cluster *cl,
>> +                           const struct dect_mbc_id *id);
>> +extern void dect_mac_dis_req(struct dect_cluster *cl, u32 mcei);
>> +
>> +extern int dect_mac_enc_key_req(const struct dect_cluster *cl, u32 
>> mcei, u64 ck);
>> +extern int dect_mac_enc_eks_req(const struct dect_cluster *cl, u32 
>> mcei,
>> +                               enum dect_cipher_states status);
>> +
>> +extern void dect_bmc_mac_page_req(struct dect_cluster *cl, struct 
>> sk_buff *skb);
>> +
>> +struct dect_llme_req;
>> +
>> +/**
>> + * struct dect_ccf_ops - Cluster Control Ops
>> + *
>> + * @bind:                      bind cell to cluster
>> + * @unbind:                    unbind cell from cluster
>> + * @mac_info_indicate:         indicate FP mac layer information (PP 
>> only)
>> + * @mbc_conn_indicate:         indicate a new TBC connection
>> + * @mbc_conn_notify:           notify MBC of TBC events
>> + * @mbc_data_indicate:         indicate new data to MBC
>> + * @bmc_page_indicate:         indicate reception of a page message 
>> to the BMC
>> + */
>> +struct dect_cluster_handle;
>> +struct dect_scan_result;
>> +enum dect_tbc_event;
>> +struct dect_ccf_ops {
>> +       int     (*bind)(struct dect_cluster_handle *,
>> +                       struct dect_cell_handle *);
>> +       void    (*unbind)(struct dect_cluster_handle *,
>> +                         struct dect_cell_handle *);
>> +
>> +       void    (*time_ind)(struct dect_cluster_handle *,
>> +                           enum dect_timer_bases, u32, u8, u8);
>> +
>> +       void    (*scan_report)(const struct dect_cluster_handle *,
>> +                              const struct dect_scan_result *);
>> +
>> +       void    (*mac_info_ind)(const struct dect_cluster_handle *,
>> +                               const struct dect_idi *,
>> +                               const struct dect_si *);
>> +
>> +       int     (*tbc_establish_ind)(const struct dect_cluster_handle 
>> *,
>> +                                    const struct dect_cell_handle *,
>> +                                    const struct dect_tbc_id *,
>> +                                    enum dect_mac_service_types, 
>> bool);
>> +       int     (*tbc_establish_cfm)(const struct dect_cluster_handle 
>> *,
>> +                                    const struct dect_tbc_id *, bool, 
>> u8);
>> +       void    (*tbc_dis_ind)(const struct dect_cluster_handle *,
>> +                              const struct dect_tbc_id *,
>> +                              enum dect_release_reasons);
>> +       int     (*tbc_event_ind)(const struct dect_cluster_handle *,
>> +                                const struct dect_tbc_id *,
>> +                                enum dect_tbc_event);
>> +       void    (*tbc_data_ind)(const struct dect_cluster_handle *,
>> +                               const struct dect_tbc_id *,
>> +                               enum dect_data_channels chan,
>> +                               struct sk_buff *);
>> +       int     (*tbc_handover_req)(const struct dect_cluster_handle 
>> *,
>> +                                   const struct dect_tbc_id *);
>> +
>> +       void    (*bmc_page_ind)(const struct dect_cluster_handle *,
>> +                               struct sk_buff *);
>> +};
>> +
>> +/**
>> + * struct dect_cluster_handle - Cell's view of a cluster
>> + *
>> + * @ops:               Cluster Control Function ops
>> + * @index:             Cluster index
>> + * @tipc_id:           Cluster TIPC user ID
>> + * @tportref:          Topology Service port reference (remote 
>> cluster only)
>> + * @portref:           Cell Control Protocol port reference (remote 
>> cluster only)
>> + */
>> +struct dect_cluster_handle {
>> +       const struct dect_ccf_ops       *ops;
>> +       u8                              index;
>> +
>> +       u32                             tipc_id;
>> +       u32                             tportref;
>> +       u32                             portref;
>> +};
>> +
>> +#endif /* _NET_DECT_MAC_CCF_H */
>> diff --git a/target/linux/generic/files/include/net/dect/mac_csf.h 
>> b/target/linux/generic/files/include/net/dect/mac_csf.h
>> new file mode 100644
>> index 0000000..4a182f3
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/mac_csf.h
>> @@ -0,0 +1,596 @@
>> +/*
>> + * DECT MAC Layer - Cell Site Functions (CSF)
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_MAC_CSF_H
>> +#define _NET_DECT_MAC_CSF_H
>> +
>> +#include <net/dect/mac.h>
>> +#include <net/dect/transceiver.h>
>> +#define DECT_CHANNEL_LIST_DBM_RES      6
>> +#define DECT_CHANNEL_LIST_BINS         (DECT_RSSI_DBM_RANGE / 
>> DECT_CHANNEL_LIST_DBM_RES)
>> +
>> +/**
>> + * struct dect_channel_list_entry
>> + *
>> + * @list:              channel list bin node
>> + * @slot:              slot number
>> + * @carrier:           RF-carrier
>> + * @rssi:              measured RSSI value
>> + */
>> +struct dect_channel_list_entry {
>> +       struct list_head        list;
>> +       u8                      slot;
>> +       u8                      carrier;
>> +       u8                      rssi;
>> +};
>> +
>> +/**
>> + * struct dect_channel_list - Basic channel list
>> + *
>> + * @list:              cell's channel lists list node
>> + * @pkt:               packet type used for RSSI measurement
>> + * @status:            bitmask of completed carriers
>> + * @timer:             update timer
>> + * @available:         number of available entries
>> + * @bins:              channels ordered by RSSI value
>> + * @entries:           channel list entries
>> + *
>> + * A channel list contains channel descriptions of all physical 
>> channels
>> + * able to carry the packet type, sorted into multiple bins based on 
>> the
>> + * maximum RSSI value of the TDD slot pair.
>> + */
>> +struct dect_channel_list {
>> +       struct list_head                list;
>> +       enum dect_packet_types          pkt;
>> +       u64                             status;
>> +
>> +       struct dect_timer               timer;
>> +       u16                             available;
>> +       struct list_head                bins[DECT_CHANNEL_LIST_BINS];
>> +       struct dect_channel_list_entry  entries[];
>> +};
>> +
>> +#define DECT_CHANNEL_LIST_MAX_AGE      30      /* T209: 30 seconds */
>> +#define DECT_CHANNEL_LIST_MAX_DBM      -50     /* dBm */
>> +#define DECT_CHANNEL_LIST_LOW_WATERMARK        20      /* channels */
>> +
>> +#define DECT_CHANNEL_MIN_DELAY         2       /* frames */
>> +
>> +enum dect_bearer_states {
>> +       DECT_DUMMY_BEARER,
>> +       DECT_TRAFFIC_BEARER,
>> +       DECT_CL_BEARER,
>> +       DECT_MONITOR_BEARER,
>> +};
>> +
>> +enum dect_bearer_modes {
>> +       DECT_BEARER_RX,
>> +       DECT_BEARER_TX,
>> +};
>> +
>> +/**
>> + * enum dect_bearer_state - DECT MAC bearer states
>> + *
>> + * @DECT_BEARER_INACTIVE:      bearer inactive
>> + * @DECT_BEARER_SCHEDULED:     bearer is scheduled for activation
>> + * @DECT_BEARER_RSSI_CONFIRM:  bearer is scheduled for RSSI 
>> confirmation
>> + * @DECT_BEARER_RSSI_CONFIRMED:        RSSI is confirmed, bearer is 
>> scheduled for e
>> + * @DECT_BEARER_ENABLED:       bearer is enabled
>> + */
>> +enum dect_bearer_state {
>> +       DECT_BEARER_INACTIVE,
>> +       DECT_BEARER_SCHEDULED,
>> +       DECT_BEARER_RSSI_CONFIRM,
>> +       DECT_BEARER_RSSI_CONFIRMED,
>> +       DECT_BEARER_ENABLED,
>> +};
>> +
>> +struct dect_bearer;
>> +struct dect_bearer_ops {
>> +       enum dect_bearer_states state;
>> +       void                    (*enable)(struct dect_cell *, struct 
>> dect_bearer *);
>> +       void                    (*report_rssi)(struct dect_cell *, 
>> struct dect_bearer *,
>> +                                              u8 slot, u8 rssi);
>> +       void                    (*rcv)(struct dect_cell *cell, struct 
>> dect_bearer *,
>> +                                      struct sk_buff *);
>> +};
>> +
>> +/**
>> + * struct dect_bearer - DECT MAC Bearer
>> + *
>> + * @type:              bearer type
>> + * @state:             operational state
>> + * @trx:               DECT transceiver
>> + * @chd:               channel description
>> + * @mode:              bearer mode (RX/TX)
>> + * @tx_timer:          TX enable timer
>> + * @rssi:              last measured RSSI of selected channel
>> + * @m_tx_queue:                M-channel TX queue
>> + * @q:                 Hdr-field MUX for Q1/Q2 bit settings
>> + * @union:             bearer type specific data
>> + */
>> +struct dect_bearer {
>> +       const struct dect_bearer_ops    *ops;
>> +       struct dect_transceiver         *trx;
>> +       struct dect_channel_desc        chd;
>> +       enum dect_bearer_modes          mode;
>> +       enum dect_bearer_state          state;
>> +       struct dect_timer               tx_timer;
>> +       u8                              rssi;
>> +
>> +       struct sk_buff_head             m_tx_queue;
>> +       u8                              q;
>> +
>> +       union {
>> +               struct dect_dbc         *dbc;
>> +               struct dect_cbc         *cbc;
>> +               struct dect_tbc         *tbc;
>> +               struct dect_dmb         *dmb;
>> +               struct dect_irc         *irc;
>> +               void                    *data;
>> +       };
>> +};
>> +
>> +/**
>> + * struct dect_bc - broadcast controller
>> + *
>> + * @list:              broadcast message control BC list node
>> + * @p_rx_skb:          current RX P-channel message
>> + * @p_tx_mask:         bitmask of scheduled mac layer pages
>> + */
>> +struct dect_bc {
>> +       struct list_head                list;
>> +       struct sk_buff                  *p_rx_skb;
>> +       u32                             p_tx_mask;
>> +};
>> +
>> +/*
>> + * enum dect_bearer_qctrl_state - DECT bearer quality control state
>> + *
>> + * @DECT_BEARER_QCTRL_WAIT:    waiting for next quality control event
>> + * @DECT_BEARER_QCTRL_CONFIRM: performing quality control
>> + */
>> +enum dect_bearer_qctrl_state {
>> +       DECT_BEARER_QCTRL_WAIT,
>> +       DECT_BEARER_QCTRL_CONFIRM,
>> +};
>> +
>> +#define DECT_BEARER_QCTRL_FRAMENUM     15      /* must not affect 
>> paging */
>> +#define DECT_BEARER_QCTRL_PERIOD       256     /* frames */
>> +
>> +/**
>> + * struct dect_dbc - dummy bearer control
>> + *
>> + * @list:              cell dbc list node
>> + * @cell:              DECT cell
>> + * @bearer:            dummy bearer
>> + * @qctrl_timer:       quality control timer
>> + * @qctrl_state:       qaulity control state
>> + * @bc:                        broadcast controller
>> + */
>> +struct dect_dbc {
>> +       struct list_head                list;
>> +       struct dect_cell                *cell;
>> +       struct dect_bearer              bearer;
>> +       struct dect_timer               qctrl_timer;
>> +       enum dect_bearer_qctrl_state    qctrl;
>> +       struct dect_bc                  bc;
>> +};
>> +
>> +/*
>> + * struct dect_cbc - connectionless bearer control
>> + *
>> + * @cell:              DECT cell
>> + * @dl_bearer:         connectionless downlink bearer
>> + * @ul_bearer:         connectionless uplink bearer, if present
>> + * @bc:                        broadcast controller
>> + */
>> +struct dect_cbc {
>> +       struct dect_cell                *cell;
>> +       struct dect_bearer              dl_bearer;
>> +       struct dect_bearer              ul_bearer;
>> +       struct dect_bc                  bc;
>> +};
>> +
>> +/**
>> + * enum dect_tbc_state - DECT Traffic Bearer Controller state
>> + *
>> + * @DECT_TBC_NONE:             Initial state
>> + * @DECT_TBC_REQ_SENT:         Initiator: bearer request sent
>> + * @DECT_TBC_WAIT_RCVD:                Initiator: intermediate state
>> + * @DECT_TBC_REQ_RCVD:         Responder: request received
>> + * @DECT_TBC_RESPONSE_SENT:    Responder: immediate response to 
>> request sent
>> + * @DECT_TBC_OTHER_WAIT:       Waiting for "other" message
>> + * @DECT_TBC_ESTABLISHED       Established
>> + * @DECT_TBC_RELEASING         First RELEASE message sent
>> + * @DECT_TBC_RELEASED:         Second RELEASE message sent
>> + */
>> +enum dect_tbc_state {
>> +       DECT_TBC_NONE,
>> +       DECT_TBC_REQ_SENT,
>> +       DECT_TBC_WAIT_RCVD,
>> +       DECT_TBC_REQ_RCVD,
>> +       DECT_TBC_RESPONSE_SENT,
>> +       DECT_TBC_OTHER_WAIT,
>> +       DECT_TBC_ESTABLISHED,
>> +       DECT_TBC_RELEASING,
>> +       DECT_TBC_RELEASED,
>> +};
>> +
>> +/**
>> + * enum dect_tbc_enc_state - DECT Traffic Bearer encryption state
>> + *
>> + * @DECT_TBC_ENC_DISABLED:      Encryption is disabled
>> + * @DECT_TBC_ENC_START_REQ_RCVD: Start request received (FP)
>> + * @DECT_TBC_ENC_START_REQ_SENT: Start request sent (PP)
>> + * @DECT_TBC_ENC_START_CFM_RCVD: Start confirm received (PP)
>> + * @DECT_TBC_ENC_START_CFM_SENT: Start confirm sent (FP)
>> + * @DECT_TBC_ENC_ENABLED:       Encryption is enabled
>> + */
>> +enum dect_tbc_enc_state {
>> +       DECT_TBC_ENC_DISABLED,
>> +       DECT_TBC_ENC_START_REQ_RCVD,
>> +       DECT_TBC_ENC_START_REQ_SENT,
>> +       DECT_TBC_ENC_START_CFM_RCVD,
>> +       DECT_TBC_ENC_START_CFM_SENT,
>> +       DECT_TBC_ENC_ENABLED,
>> +};
>> +
>> +/**
>> + * enum dect_tbc_event - DECT Traffic Bearer events
>> + *
>> + * @DECT_TBC_ACK_RECEIVED:     Acknowledgement for C_S data received
>> + * @DECT_TBC_CIPHER_ENABLED:   Ciphering enabled
>> + * @DECT_TBC_CIPHER_DISABLED:  Ciphering disabled
>> + */
>> +enum dect_tbc_event {
>> +       DECT_TBC_ACK_RECEIVED,
>> +       DECT_TBC_CIPHER_ENABLED,
>> +       DECT_TBC_CIPHER_DISABLED,
>> +};
>> +
>> +/**
>> + * struct dect_tbc - DECT Traffic Bearer Control
>> + *
>> + * @list:              Cell TBC list node
>> + * @cell:              DECT cell
>> + * @id:                        Traffic Bearer ID
>> + * @txb:               TX bearer
>> + * @rxb:               RX bearer
>> + * @state:             Bearer establishment state
>> + * @tx_timer:          Transmit activation timer
>> + * @wd_timer:          Receive watchdog timer
>> + * @release_timer:     Release timer for unacknowledged release 
>> procedure
>> + * @release_reason:    release reason
>> + * @normal_tx_timer:   Normal transmit timer for C-channel/I_N normal 
>> delay transmission
>> + * @normal_rx_timer:   Normal receive timer for C-channel/I_N normal 
>> delay delivery
>> + * @rx_timer:          Mimimum delay receive timer
>> + * @tx_timer:          Minimum delay transmit timer
>> + * @ck:                        Cipher key
>> + * @enc_timer:         Encryption TX timer
>> + * @enc_state:         Encryption state
>> + * @enc_msg_cnt:       Encryption message retransmit counter
>> + * @c_rx_skb:          C_S segment for delivery to DLC
>> + * @c_tx_skb:          C_S segment for transmission in next TDMA 
>> frame
>> + * @c_tx_ok:           C_S segment was successfully transmitted
>> + * @b_rx_skb:          B-field data segment for delivery to DLC
>> + * @b_tx_skb:          B-field data segment for transmission in next 
>> TDMA frame
>> + * @bc:                        Broadcast Control
>> + */
>> +struct dect_tbc {
>> +       struct list_head                list;
>> +       struct dect_cell                *cell;
>> +       struct dect_tbc_id              id;
>> +       enum dect_mac_connection_types  type;
>> +       enum dect_mac_service_types     service;
>> +       bool                            handover;
>> +
>> +       struct dect_bearer              txb;
>> +       struct dect_bearer              rxb;
>> +
>> +       enum dect_tbc_state             state;
>> +       struct dect_timer               wait_timer;
>> +       struct dect_timer               wd_timer;
>> +
>> +       struct dect_timer               release_timer;
>> +       enum dect_release_reasons       release_reason;
>> +
>> +       /* PP handover trigger */
>> +       s8                              handover_tokens;
>> +
>> +       /* Encryption */
>> +       u64                             ck;
>> +       struct dect_timer               enc_timer;
>> +       enum dect_tbc_enc_state         enc_state:8;
>> +       u8                              enc_msg_cnt;
>> +
>> +       /* C_S channel */
>> +       struct sk_buff                  *cs_tx_skb;
>> +       bool                            cs_tx_ok;
>> +
>> +       /* I channel */
>> +       struct sk_buff                  *b_tx_skb;
>> +
>> +       struct dect_bc                  bc;
>> +};
>> +
>> +#define DECT_TBC_RFPI_TIMEOUT          (5 * DECT_FRAMES_PER_SECOND)
>> +
>> +#define DECT_TBC_HO_TOKENS_INITIAL     16
>> +#define DECT_TBC_HO_TOKENS_OK          1 /* Correct slot adds one 
>> token */
>> +#define DECT_TBC_HO_TOKENS_ERROR       8 /* Error slot subtracts 
>> eight tokens */
>> +#define DECT_TBC_HO_TOKENS_MAX         32
>> +
>> +enum dect_scan_status {
>> +       DECT_SCAN_FAIL,
>> +       DECT_SCAN_TIMEOUT,
>> +       DECT_SCAN_COMPLETE,
>> +};
>> +
>> +/**
>> + * struct dect_dmb - Monitor Bearer
>> + *
>> + * @list:      cell dmbs list node
>> + * @cell:      DECT cell
>> + * @rxb1:      receive bearer 1
>> + * @rxb2:      receive bearer 2
>> + */
>> +struct dect_dmb {
>> +       struct list_head                list;
>> +       struct dect_cell                *cell;
>> +
>> +       struct dect_timer               wd_timer;
>> +       struct dect_bearer              rxb1;
>> +       struct dect_bearer              rxb2;
>> +       struct dect_bc                  bc;
>> +};
>> +
>> +/**
>> + * struct dect_irc - Idle receiver control
>> + *
>> + * @cell:              DECT cell
>> + * @trx:               DECT transceiver
>> + * @ari:               ARI filter
>> + * @ari_mask:          ARI filter mask
>> + * @idi:               identities information
>> + * @si:                        system information
>> + * @notify:            notification callback
>> + * @rx_scn:            Scan carrier number (RX time base)
>> + * @tx_scn:            Scan carrier number (TX time base)
>> + * @rx_frame_timer:    rx_scn update timer
>> + * @tx_frame_timer:    tx_scn update timer
>> + */
>> +struct dect_irc {
>> +       struct dect_cell        *cell;
>> +       struct dect_transceiver *trx;
>> +
>> +       struct dect_llme_req    lreq;
>> +
>> +       struct dect_ari         ari;
>> +       struct dect_ari         ari_mask;
>> +
>> +       u16                     timeout;
>> +       u16                     rssi;
>> +       struct dect_idi         idi;
>> +       struct dect_si          si;
>> +
>> +       void                    (*notify)(struct dect_cell *,
>> +                                         struct dect_transceiver *,
>> +                                         enum dect_scan_status);
>> +
>> +       u8                      rx_scn;
>> +       u8                      tx_scn;
>> +       struct dect_timer       rx_frame_timer;
>> +       struct dect_timer       tx_frame_timer;
>> +       struct dect_bearer      scan_bearer;
>> +};
>> +
>> +#define DECT_IRC_SCN_OFF       3
>> +
>> +struct dect_scan_result {
>> +       struct dect_llme_req    lreq;
>> +       struct dect_idi         idi;
>> +       struct dect_si          si;
>> +       u16                     rssi;
>> +};
>> +
>> +/**
>> + * struct dect_csf_ops - Cell Site Function ops
>> + *
>> + * @set_mode:                  set cell to PP/FP mode
>> + * @scan:                      initiate scan for pari/pari_mask
>> + * @preload:                   preload system information
>> + * @enable:                    enable cell
>> + * @page_request:              deliver paging message
>> + * @tbc_initiate:              initiate a new connection
>> + * @tbc_confirm:               confirm an incoming connection
>> + * @tbc_release:               release a TBC
>> + * @tbc_enc_key_request:       set encryption key
>> + * @tbc_enc_eks_request:       enable/disable encryption
>> + *
>> + * The CSF ops define the interface in the direction CCF -> CSF.
>> + */
>> +struct dect_cell_handle;
>> +struct dect_csf_ops {
>> +       int     (*set_mode)(const struct dect_cell_handle *,
>> +                           enum dect_cluster_modes);
>> +       int     (*scan)(const struct dect_cell_handle *,
>> +                       const struct dect_llme_req *lreq,
>> +                       const struct dect_ari *, const struct dect_ari 
>> *);
>> +       int     (*preload)(const struct dect_cell_handle *,
>> +                          const struct dect_ari *, u8,
>> +                          const struct dect_si *);
>> +       int     (*enable)(const struct dect_cell_handle *);
>> +
>> +       void    (*page_req)(const struct dect_cell_handle *, struct 
>> sk_buff *);
>> +
>> +       int     (*tbc_establish_req)(const struct dect_cell_handle *,
>> +                                    const struct dect_tbc_id *,
>> +                                    const struct dect_channel_desc *,
>> +                                    enum dect_mac_service_types, 
>> bool);
>> +       int     (*tbc_establish_res)(const struct dect_cell_handle *,
>> +                                    const struct dect_tbc_id *);
>> +       void    (*tbc_dis_req)(const struct dect_cell_handle *,
>> +                              const struct dect_tbc_id *,
>> +                              enum dect_release_reasons);
>> +       int     (*tbc_enc_key_req)(const struct dect_cell_handle *,
>> +                                  const struct dect_tbc_id *, u64 
>> ck);
>> +       int     (*tbc_enc_eks_req)(const struct dect_cell_handle *,
>> +                                  const struct dect_tbc_id *,
>> +                                  enum dect_cipher_states status);
>> +       int     (*tbc_enc_req)(const struct dect_cell_handle *,
>> +                              const struct dect_tbc_id *, u64 ck);
>> +       void    (*tbc_data_req)(const struct dect_cell_handle *,
>> +                               const struct dect_tbc_id *,
>> +                               enum dect_data_channels chan,
>> +                               struct sk_buff *);
>> +
>> +};
>> +
>> +/**
>> + * struct dect_cell_handle - DECT cluster view of a cell
>> + *
>> + * @list:              cluster cell list node
>> + * @clh:               bound cluster handle
>> + * @ops:               cell site function ops
>> + * @rpn:               assigned radio part number
>> + * @portref:           cell control protocol port reference (remote 
>> cells)
>> + */
>> +struct dect_cell_handle {
>> +       struct list_head                list;
>> +       struct dect_cluster_handle      *clh;
>> +       const struct dect_csf_ops       *ops;
>> +       u8                              rpn;
>> +
>> +       u32                             portref;
>> +};
>> +
>> +enum dect_cell_states {
>> +       DECT_CELL_ENABLED               = 1 << 0,
>> +};
>> +
>> +/**
>> + * struct dect_cell - DECT cell: one radio system
>> + *
>> + * @list:              cell list node
>> + * @name:              cells' name
>> + * @index:             unique numeric cell identifier
>> + * @flags:             operational and status flags
>> + * @handle:            cell handle
>> + * @lock:              lock
>> + * @mode:              operational mode (FP/PP)
>> + * @state:             bitmask of enum dect_cell_states
>> + * @idi:               FP System Identity
>> + * @fmid:              FMID (Fixed MAC IDentity)
>> + * @si:                        FP System Information
>> + * @timer_sync_stamp:  Time (multiframe number) of last multiframe 
>> number sync
>> + * @a_rcv_stamp:       Time (jiffies) of last received A-Field with 
>> correct CRC
>> + * @nt_rcv_stamp:      Time (jiffies) of last received Nt-Tail 
>> containing the PARI
>> + * @bcs:               Broadcast Controllers
>> + * @cbc:               Connectionless Bearer Controller
>> + * @dbcs:              Dummy Bearer Controllers
>> + * @tbcs:              list of Traffic Bearer Controllers
>> + * @tbc_num_est:       Number of TBCs in ESTABLISHED state
>> + * @tbc_last_chd:      Channel description of last TBC leaving 
>> ESTABLISHED state
>> + * @dmbs:              list of Monitor Bearers
>> + * @chanlists:         list of channel lists for different channel 
>> types
>> + * @timer_base:                RX/TX timer bases
>> + * @trg:               DECT transceiver group
>> + */
>> +struct dect_cell {
>> +       struct list_head                list;
>> +       char                            name[DECTNAMSIZ];
>> +       u32                             index;
>> +       u32                             flags;
>> +
>> +       struct dect_cell_handle         handle;
>> +
>> +       spinlock_t                      lock;
>> +       enum dect_cluster_modes         mode;
>> +       u32                             state;
>> +
>> +       /* identities */
>> +       struct dect_idi                 idi;
>> +       u16                             fmid;
>> +
>> +       /* system information */
>> +       struct dect_si                  si;
>> +       u32                             blind_full_slots;
>> +
>> +       /* PP state maintenance */
>> +       u32                             timer_sync_stamp;
>> +       unsigned long                   a_rcv_stamp;
>> +       unsigned long                   nt_rcv_stamp;
>> +
>> +       /* Broadcast controllers and related data */
>> +       struct dect_timer               page_timer;
>> +       struct sk_buff_head             page_queue;
>> +       struct sk_buff_head             page_fast_queue;
>> +
>> +       struct sk_buff                  *page_sdu;
>> +       struct sk_buff_head             page_tx_queue;
>> +
>> +       struct list_head                bcs;
>> +       unsigned int                    si_idx;
>> +       unsigned long                   bfs_xmit_stamp;
>> +
>> +       struct dect_cbc                 cbc;
>> +       struct list_head                dbcs;
>> +
>> +       u32                             tbei_rover;
>> +       struct list_head                tbcs;
>> +       unsigned int                    tbc_num_est;
>> +       struct dect_channel_desc        tbc_last_chd;
>> +
>> +       struct list_head                dmbs;
>> +
>> +       /* channel lists */
>> +       struct list_head                chl_pending;
>> +       struct list_head                chanlists;
>> +       struct dect_channel_list        *chl_next;
>> +       struct dect_channel_list        *chl;
>> +
>> +       /* raw transmission queue */
>> +       struct sk_buff_head             raw_tx_queue;
>> +
>> +       struct dect_timer_base          timer_base[DECT_TIMER_BASE_MAX 
>> + 1];
>> +       struct dect_transceiver_group   trg;
>> +       u32                             trg_blind_full_slots;
>> +};
>> +
>> +#define DECT_CELL_TIMER_RESYNC_TIMEOUT 8               /* T216: 8 
>> multiframes */
>> +#define DECT_CELL_A_RCV_TIMEOUT                (5 * HZ)        /* 
>> T207: 5 seconds */
>> +#define DECT_CELL_NT_RCV_TIMEOUT       (20 * HZ)       /* T208: 20 
>> seconds */
>> +
>> +#define dect_foreach_transmit_slot(slot, end, cell) \
>> +       for ((slot) = dect_normal_transmit_base((cell)->mode), \
>> +            (end) = (slot) + DECT_HALF_FRAME_SIZE; \
>> +            (slot) < (end); (slot)++)
>> +
>> +#define dect_foreach_receive_slot(slot, end, cell) \
>> +       for ((slot) = dect_normal_receive_base((cell)->mode), \
>> +            (end) = (slot) + DECT_HALF_FRAME_SIZE; \
>> +            (slot) < (end); (slot)++)
>> +
>> +extern struct dect_cell *dect_cell_get_by_index(u32 index);
>> +
>> +extern int dect_cell_attach_transceiver(struct dect_cell *cell,
>> +                                       struct dect_transceiver *trx);
>> +extern void dect_cell_detach_transceiver(struct dect_cell *cell,
>> +                                        struct dect_transceiver 
>> *trx);
>> +
>> +extern void dect_mac_rcv(struct dect_transceiver *trx,
>> +                        struct dect_transceiver_slot *ts,
>> +                        struct sk_buff *skb);
>> +extern void dect_mac_report_rssi(struct dect_transceiver *trx,
>> +                                struct dect_transceiver_slot *ts, u8 
>> rssi);
>> +extern void dect_mac_rx_tick(struct dect_transceiver_group *grp, u8 
>> slot);
>> +extern void dect_mac_tx_tick(struct dect_transceiver_group *grp, u8 
>> slot);
>> +
>> +extern void dect_mac_irc_rcv(struct dect_transceiver *trx, struct 
>> sk_buff *skb);
>> +extern void dect_mac_irc_tick(struct dect_transceiver *trx);
>> +
>> +#endif /* _NET_DECT_MAC_CSF_H */
>> diff --git a/target/linux/generic/files/include/net/dect/transceiver.h 
>> b/target/linux/generic/files/include/net/dect/transceiver.h
>> new file mode 100644
>> index 0000000..f5d95d1
>> --- /dev/null
>> +++ b/target/linux/generic/files/include/net/dect/transceiver.h
>> @@ -0,0 +1,726 @@
>> +/*
>> + * DECT Transceiver Layer
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + */
>> +
>> +#ifndef _NET_DECT_TRANSCEIVER_H
>> +#define _NET_DECT_TRANSCEIVER_H
>> +
>> +#include <linux/interrupt.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/dect.h>
>> +#include <linux/dect_netlink.h>
>> +
>> +#define DECT_RSSI_RANGE                        255
>> +#define DECT_RSSI_DBM_LOW              -93
>> +#define DECT_RSSI_DBM_RANGE            60
>> +
>> +static inline u8 dect_dbm_to_rssi_rel(s8 dbm)
>> +{
>> +       return dbm * DECT_RSSI_RANGE / DECT_RSSI_DBM_RANGE;
>> +}
>> +
>> +static inline u8 dect_dbm_to_rssi(s8 dbm)
>> +{
>> +       return dect_dbm_to_rssi_rel(dbm - DECT_RSSI_DBM_LOW);
>> +}
>> +
>> +#define DECT_RSSI_AVG_SCALE            3
>> +
>> +static inline u16 dect_average_rssi(u16 cur, u16 sample)
>> +{
>> +       if (cur == 0)
>> +               cur = sample << DECT_RSSI_AVG_SCALE;
>> +       else {
>> +               cur -= cur >> DECT_RSSI_AVG_SCALE;
>> +               cur += sample;
>> +       }
>> +       return cur;
>> +}
>> +
>> +#define DECT_CARRIER_NUM               64
>> +
>> +static inline u8 dect_next_carrier(u64 rfcars, u8 carrier)
>> +{
>> +       u64 tmp;
>> +
>> +       if (WARN_ON(rfcars == 0))
>> +               return 0;
>> +       tmp = rfcars & ~((1ULL << (carrier + 1)) - 1);
>> +       if (tmp == 0)
>> +               tmp = rfcars;
>> +       return ffs(tmp) - 1;
>> +}
>> +
>> +static inline u8 dect_prev_carrier(u64 rfcars, u8 carrier)
>> +{
>> +       u64 tmp;
>> +
>> +       if (WARN_ON(rfcars == 0))
>> +               return 0;
>> +       tmp = rfcars & ((1ULL << carrier) - 1);
>> +       if (tmp == 0)
>> +               tmp = rfcars;
>> +       return fls(tmp) - 1;
>> +}
>> +
>> +static inline u8 dect_carrier_sub(u64 rfcars, u8 carrier, u8 n)
>> +{
>> +       while (n != 0) {
>> +               carrier = dect_prev_carrier(rfcars, carrier);
>> +               n--;
>> +       }
>> +       return carrier;
>> +}
>> +
>> +static inline u8 dect_carrier_distance(u64 rfcars, u8 from, u8 to)
>> +{
>> +       if (from >= to) {
>> +               /* clear bits between to and from */
>> +               rfcars &= ~(((1ULL << (from - to)) - 1) << to);
>> +       } else {
>> +               /* clear bits not between from and to */
>> +               rfcars &= ((1ULL << (to - from)) - 1) << from;
>> +       }
>> +       return hweight64(rfcars);
>> +}
>> +
>> +#define DECT_PHASE_OFFSET_EWMA_LOG     (DECT_PHASE_OFFSET_SCALE / 4)
>> +
>> +static inline s32 dect_average_phase_offset(s32 cur, s32 phaseoff)
>> +{
>> +       cur -= cur / DECT_PHASE_OFFSET_EWMA_LOG;
>> +       cur += phaseoff / DECT_PHASE_OFFSET_EWMA_LOG;
>> +       return cur;
>> +}
>> +
>> +#define DECT_BAND_NUM                  32
>> +#define DECT_DEFAULT_BAND              0
>> +
>> +#define DECT_FREQUENCY_F0              1897344 /* kHz */
>> +#define DECT_CARRIER_WIDTH             1728    /* kHz */
>> +
>> +/**
>> + * struct dect_band - DECT RF-band
>> + *
>> + * @band:              RF-band number
>> + * @carriers:          number of defined carriers
>> + * @frequency:         frequency of each carrier in kHz
>> + */
>> +struct dect_band {
>> +       u8      band;
>> +       u8      carriers;
>> +       u32     frequency[];
>> +};
>> +
>> +#define DECT_FRAME_SIZE                        24
>> +#define DECT_HALF_FRAME_SIZE           (DECT_FRAME_SIZE / 2)
>> +#define DECT_FRAMES_PER_SECOND         100
>> +
>> +#define DECT_SCAN_SLOT                 0
>> +#define DECT_SLOT_MASK                 0x00ffffff
>> +
>> +static inline u8 dect_next_slotnum(u8 slot)
>> +{
>> +       if (++slot == DECT_FRAME_SIZE)
>> +               slot = 0;
>> +       return slot;
>> +}
>> +
>> +static inline u8 dect_prev_slotnum(u8 slot)
>> +{
>> +       if (slot == 0)
>> +               slot = DECT_FRAME_SIZE;
>> +       return slot - 1;
>> +}
>> +
>> +static inline u8 dect_slot_add(u8 s1, u8 s2)
>> +{
>> +       return (s1 + s2) % DECT_FRAME_SIZE;
>> +}
>> +
>> +static inline u8 dect_slot_sub(u8 s1, u8 s2)
>> +{
>> +       return s1 >= s2 ? s1 - s2 : DECT_FRAME_SIZE + s1 - s2;
>> +}
>> +
>> +static inline u8 dect_slot_distance(u8 s1, u8 s2)
>> +{
>> +       return s2 >= s1 ? s2 - s1 : DECT_FRAME_SIZE + s2 - s1;
>> +}
>> +
>> +#define dect_foreach_slot(slot) \
>> +       for ((slot) = 0; (slot) < DECT_FRAME_SIZE; (slot)++)
>> +
>> +static inline u8 dect_normal_transmit_base(enum dect_cluster_modes 
>> mode)
>> +{
>> +       return mode == DECT_MODE_FP ? 0 : DECT_HALF_FRAME_SIZE;
>> +}
>> +
>> +static inline u8 dect_normal_receive_base(enum dect_cluster_modes 
>> mode)
>> +{
>> +       return mode == DECT_MODE_FP ? DECT_HALF_FRAME_SIZE : 0;
>> +}
>> +
>> +static inline u8 dect_normal_receive_end(enum dect_cluster_modes 
>> mode)
>> +{
>> +       return mode == DECT_MODE_FP ? DECT_FRAME_SIZE - 1 :
>> +                                     DECT_HALF_FRAME_SIZE - 1;
>> +}
>> +
>> +static inline u8 dect_tdd_slot(u8 slot)
>> +{
>> +       return slot < DECT_HALF_FRAME_SIZE ? slot + 
>> DECT_HALF_FRAME_SIZE :
>> +                                            slot - 
>> DECT_HALF_FRAME_SIZE;
>> +}
>> +
>> +/**
>> + * enum dect_slot_types - DECT slot types
>> + *
>> + * @DECT_FULL_SLOT:            Full-slot format (480 bits)
>> + * @DECT_HALF_SLOT:            Half-slot format (240 bits)
>> + * @DECT_DOUBLE_SLOT:          Double-slot format (960 bits)
>> + * @DECT_LONG_SLOT_j640:       Long slot format j=640 (800 bits)
>> + * @DECT_LONG_SLOT_j672:       Long slot format j=672 (832 bits)
>> + *
>> + * The numeric values must match the MAC-layer attributes-T coding.
>> + */
>> +enum dect_slot_types {
>> +       DECT_FULL_SLOT          = 0x0,
>> +       DECT_HALF_SLOT          = 0x1,
>> +       DECT_DOUBLE_SLOT        = 0x2,
>> +       DECT_LONG_SLOT_640      = 0x3,
>> +       DECT_LONG_SLOT_672      = 0x4,
>> +};
>> +
>> +enum dect_packet_sizes {
>> +       DECT_P00_SIZE           = 12,
>> +       DECT_P08_SIZE           = 23,
>> +       DECT_P32_SIZE           = 53,
>> +       DECT_P640j_SIZE         = 89,
>> +       DECT_P672j_SIZE         = 93,
>> +       DECT_P80_SIZE           = 113,
>> +};
>> +
>> +#define DECT_PREAMBLE_SIZE     4
>> +
>> +/**
>> + * enum dect_checksum - DECT hardware checksum results
>> + *
>> + * @DECT_CHECKSUM_A_CRC_OK:    A-field R-CRC OK
>> + * @DECT_CHECKSUM_X_CRC_OK:    Unprotected B-field X-CRC OK
>> + * @DECT_CHECKSUM_Z_CRC_OK:    Z-field OK
>> + */
>> +enum dect_checksum {
>> +       DECT_CHECKSUM_A_CRC_OK  = 0x1,
>> +       DECT_CHECKSUM_X_CRC_OK  = 0x2,
>> +       DECT_CHECKSUM_Z_CRC_OK  = 0x4,
>> +};
>> +
>> +/**
>> + * enum dect_b_formats - DECT B-Field formats
>> + *
>> + * @DECT_B_NONE:       No B-field
>> + * @DECT_B_UNPROTECTED:        Unprotected B-field format
>> + * @DECT_B_PROTECTED:  Protected B-field format
>> + *
>> + * The B-Field format can be used by a transceiver for offloading 
>> X-CRC
>> + * calculation.
>> + */
>> +enum dect_b_formats {
>> +       DECT_B_NONE,
>> +       DECT_B_UNPROTECTED,
>> +       DECT_B_PROTECTED,
>> +       __DECT_B_MAX
>> +};
>> +#define DECT_B_MAX             (__DECT_B_MAX - 1)
>> +
>> +/**
>> + * struct dect_channel_desc - DECT physical channel description
>> + *
>> + * @pkt:       Packet type in use
>> + * @b_fmt:     B-Field format for checksum offloading
>> + * @slot:      Slot number
>> + * @carrier:   RF-carrier number
>> + */
>> +struct dect_channel_desc {
>> +       enum dect_packet_types          pkt:8;
>> +       enum dect_b_formats             b_fmt:8;
>> +       u8                              slot;
>> +       u8                              carrier;
>> +};
>> +
>> +enum dect_channel_priv_flags {
>> +       DECT_SLOT_RAW_TX                = 0x1,
>> +};
>> +
>> +/**
>> + * struct dect_transceiver_slot - Transceiver TDMA slot
>> + *
>> + * @flags:             slot flags
>> + * @priv_flags:                internally used flags
>> + * @state:             current state
>> + * @desc:              channel description
>> + * @bearer:            associated bearer
>> + * @ck:                        cipher key
>> + * @phaseoff:          measured phase offset
>> + * @rssi:              averaged RSSI
>> + * @rx_bytes:          RX byte count
>> + * @rx_packets:                RX packet count
>> + * @rx_a_crc_errors:   RX A-field CRC errors
>> + * @tx_bytes:          TX byte count
>> + * @tx_packets:                TX packet count
>> + */
>> +struct dect_transceiver_slot {
>> +       u8                              flags;
>> +       u8                              priv_flags;
>> +       u8                              blinded;
>> +       enum dect_slot_states           state:8;
>> +       struct dect_channel_desc        chd;
>> +       struct dect_bearer              *bearer;
>> +       u64                             ck;
>> +
>> +       s32                             phaseoff;
>> +       u16                             rssi;
>> +       u32                             rx_bytes;
>> +       u32                             rx_packets;
>> +       u32                             rx_a_crc_errors;
>> +       u32                             rx_x_crc_errors;
>> +       u32                             rx_z_crc_errors;
>> +       u32                             tx_bytes;
>> +       u32                             tx_packets;
>> +};
>> +
>> +/**
>> + * struct dect_transceiver_event - one atomic unit of work for the 
>> MAC layer
>> + *
>> + * @trx:               transceiver
>> + * @busy:              synchronizer
>> + * @list:              transceiver group events list node
>> + * @rx_queue:          received packets
>> + * @rssi:              RSSI measurement in scanning slots
>> + * @rssi_mask:         RSSI measurement positions
>> + * @slotpos:           transceiver slot position in TDMA frame
>> + *
>> + * A transceiver operates asynchronously to the MAC layer, but the 
>> MAC layer's
>> + * timing needs to be strictly synchronized to the receiver.
>> + *
>> + * This structure contains the packets from multiple consequitive 
>> slots received
>> + * by the receiver in one unit (up to ops->eventrate frames). Slotpos 
>> specifies
>> + * the transceivers current position in the TDMA frame (== the 
>> minimum current
>> + * time) and is used for timing purposes and slot maintenance 
>> operations of the
>> + * upcoming slots. A transceiver uses a fixed amount of these 
>> structure and
>> + * synchronizes with BH processing through the busy marker. When BH 
>> processing
>> + * is too slow, frames are dropped.
>> + */
>> +struct dect_transceiver_event {
>> +       struct dect_transceiver *trx;
>> +       atomic_t                busy;
>> +       struct list_head        list;
>> +       struct sk_buff_head     rx_queue;
>> +       u8                      rssi[DECT_HALF_FRAME_SIZE / 2];
>> +       u8                      rssi_mask;
>> +       u8                      slotpos;
>> +};
>> +
>> +/**
>> + * struct dect_skb_trx_cb - DECT Transceiver skb control block
>> + *
>> + * @trx:               transceiver
>> + * @mfn:               multiframe number
>> + * @frame:             frame number
>> + * @slot:              slot number
>> + * @lbn:               logical bearer number
>> + * @csum:              checksum results
>> + * @rssi:              RSSI measurement
>> + */
>> +struct dect_skb_trx_cb {
>> +       struct dect_transceiver *trx;
>> +       u32                     mfn;
>> +       u8                      frame;
>> +       u8                      slot;
>> +       u8                      lbn;
>> +       u8                      csum;
>> +       u8                      rssi;
>> +};
>> +
>> +static inline struct dect_skb_trx_cb *DECT_TRX_CB(const struct 
>> sk_buff *skb)
>> +{
>> +       BUILD_BUG_ON(sizeof(struct dect_skb_trx_cb) > 
>> sizeof(skb->cb));
>> +       return (struct dect_skb_trx_cb *)skb->cb;
>> +}
>> +
>> +/**
>> + * struct dect_transceiver_ops - DECT transceiver operations
>> + *
>> + * @disable:           shut the transceiver down
>> + * @enable:            bring the transceiver to operational state
>> + * @confirm:           confirm a received signal in slave mode
>> + * @unlock:            release a confirmed signal again
>> + * @lock:              lock to a signal
>> + * @set_mode:          set the mode (RX/TX/SCANNING) for a slot
>> + * @set_carrier:       set the RF-carrier for a slot
>> + * @set_band:          set the RF-band
>> + * @destructor:                destructor
>> + * @name               transceiver driver name
>> + * @features:          transceiver features
>> + * @eventrate:         rate at which slot events are generated, must 
>> be integral
>> + *                     divisor of the number of slots per TDMA half 
>> frame
>> + * @latency:           latency in slots until updates for a slot take 
>> effect
>> + *
>> + * A transceiver provides frame reception and transmission, signal 
>> strength
>> + * measurement as well as a reference clock for the MAC layer. It can 
>> exist
>> + * in two basic states:
>> + *
>> + * - master: doesn't need initial synchronization to a radio signal
>> + * - slave: needs to synchronize timing with a signal
>> + *
>> + * Only the first transceiver of a FP is a master, PPs are always 
>> slaves to
>> + * a FPs timing. Secondary and further transceivers of a FP also 
>> start as
>> + * slaves until they have synchronized to one of the already running
>> + * transceivers.
>> + *
>> + * Locking to a new signal works in multiple phases:
>> + *
>> + * 1) The ->enable() callback is invoked. The driver is expected to 
>> initiate a
>> + *    scan for a signal, during which it will pass on any received 
>> frame to the
>> + *    transceiver layer. As no framing has been established, all 
>> packets should
>> + *    indicate a slot number of zero.
>> + *
>> + * 2) While scanning for a signal, the ->set_carrier() callback may 
>> be invoked
>> + *    with a slot number of zero. The driver is expected to adjust 
>> the carrier
>> + *    on which it is scanning for a signal.
>> + *
>> + * 3) When the MAC layer determines interest in a received signal, 
>> the ->confirm()
>> + *    callback is invoked. The driver is expected to continue to pass 
>> frames from
>> + *    this signal to the MAC layer to establish framing.
>> + *
>> + * 3a) When the MAC layer is only collecting information for a scan, 
>> it may call
>> + *     the ->unlock callback to release a previously confirmed 
>> signal.
>> + *
>> + * 4) Once the MAC layer has determined framing relative to the slot 
>> timing, the
>> + *    ->lock() callback is invoked. At this point, only a single 
>> physical channel
>> + *    is received. The driver should synchronize the hardware to the 
>> framing to
>> + *    make it interrupt at the appropriate times.
>> + *
>> + */
>> +struct dect_transceiver;
>> +struct dect_transceiver_ops {
>> +       void            (*disable)(const struct dect_transceiver 
>> *trx);
>> +       void            (*enable)(const struct dect_transceiver *trx);
>> +
>> +       void            (*confirm)(const struct dect_transceiver 
>> *trx);
>> +       void            (*unlock)(const struct dect_transceiver *trx);
>> +       void            (*lock)(const struct dect_transceiver *trx, u8 
>> slot);
>> +
>> +       void            (*set_mode)(const struct dect_transceiver 
>> *trx,
>> +                                   const struct dect_channel_desc 
>> *chd,
>> +                                   enum dect_slot_states mode);
>> +       void            (*set_carrier)(const struct dect_transceiver 
>> *trx,
>> +                                      u8 slot, u8 carrier);
>> +       void            (*tx)(const struct dect_transceiver *trx,
>> +                             struct sk_buff *skb);
>> +
>> +       u64             (*set_band)(const struct dect_transceiver 
>> *trx,
>> +                                   const struct dect_band *band);
>> +       void            (*destructor)(struct dect_transceiver *trx);
>> +       const char      *name;
>> +
>> +       u32             features;
>> +       u8              eventrate;
>> +       u8              latency;
>> +};
>> +
>> +/**
>> + * enum dect_transceiver_modes - Transceiver synchronization modes
>> + *
>> + * @DECT_TRANSCEIVER_MASTER:   Transceiver determines reference time 
>> (FP)
>> + * @DECT_TRANSCEIVER_SLAVE:    Transceiver is slave to foreign 
>> reference timing
>> + */
>> +enum dect_transceiver_modes {
>> +       DECT_TRANSCEIVER_MASTER,
>> +       DECT_TRANSCEIVER_SLAVE,
>> +};
>> +
>> +/**
>> + * enum dect_transceiver_states - transceiver synchronization states
>> + *
>> + * @DECT_TRANSCEIVER_STOPPED:          transceiver is inactive
>> + * @DECT_TRANSCEIVER_UNLOCKED:         transceiver is not 
>> synchronized to any RFP
>> + * @DECT_TRANSCEIVER_LOCK_PENDING:     transceiver is receiving RFP 
>> transmissions,
>> + *                                     but has not obtained frame 
>> synchonization
>> + * @DECT_TRANSCEIVER_LOCKED:           the transceiver has achieved 
>> frame and
>> + *                                     multiframe lock to an RFP
>> + *
>> + * These correspond to the ETS 300 175-3 Annex D PT MAC layer states, 
>> but are
>> + * per transceiver as we also need to synchronize secondary 
>> transceivers.
>> + */
>> +enum dect_transceiver_states {
>> +       DECT_TRANSCEIVER_STOPPED,
>> +       DECT_TRANSCEIVER_UNLOCKED,
>> +       DECT_TRANSCEIVER_LOCK_PENDING,
>> +       DECT_TRANSCEIVER_LOCKED,
>> +};
>> +
>> +/**
>> + * struct dect_transceiver_stats - transceiver statistics
>> + *
>> + * @event_busy:                events lost due to MAC layer busy
>> + * @event_late:                events lost due to transceiver late
>> + */
>> +struct dect_transceiver_stats {
>> +       u32                                     event_busy;
>> +       u32                                     event_late;
>> +};
>> +
>> +/**
>> + * struct dect_transceiver - DECT transceiver
>> + *
>> + * @list:              transceiver list node
>> + * @ops:               transceiver ops
>> + * @name:              transceiver identity
>> + * @stats:             transceiver statistics
>> + * @mode:              synchronization mode
>> + * @state:             synchronization state
>> + * @band:              current RF-band
>> + * @carriers:          bitmask of supported carriers in the current 
>> band
>> + * @slots:             transceiver slot state
>> + * @index:             cell transceiver index
>> + * @segno:             transceiver receive sequence number
>> + * @cell:              cell the transceiver is assigned to
>> + * @irc:               idle receiver control
>> + * @event:             dynamic amount of transceiver event structures
>> + *
>> + * Following the event structures is the private driver data.
>> + */
>> +struct dect_transceiver {
>> +       struct list_head                        list;
>> +       const struct dect_transceiver_ops       *ops;
>> +       char                                    name[DECTNAMSIZ];
>> +
>> +       struct dect_transceiver_stats           stats;
>> +       enum dect_transceiver_modes             mode;
>> +       enum dect_transceiver_states            state;
>> +
>> +       const struct dect_band                  *band;
>> +       u64                                     carriers;
>> +
>> +       struct dect_transceiver_slot            
>> slots[DECT_FRAME_SIZE];
>> +       u32                                     blind_full_slots;
>> +
>> +       u8                                      index;
>> +       u32                                     seqno;
>> +       struct dect_cell                        *cell;
>> +       struct dect_irc                         *irc;
>> +       struct dect_transceiver_event           event[];
>> +};
>> +
>> +static inline void *dect_transceiver_priv(const struct 
>> dect_transceiver *trx)
>> +{
>> +       return (void *)&trx->event[DECT_HALF_FRAME_SIZE / 
>> trx->ops->eventrate];
>> +}
>> +
>> +extern struct dect_transceiver *dect_transceiver_alloc(const struct 
>> dect_transceiver_ops *ops,
>> +                                                      unsigned int 
>> priv);
>> +extern void dect_transceiver_free(struct dect_transceiver *trx);
>> +extern int dect_register_transceiver(struct dect_transceiver *trx);
>> +extern void dect_unregister_transceiver(struct dect_transceiver 
>> *trx);
>> +
>> +extern void dect_transceiver_enable(struct dect_transceiver *trx);
>> +extern void dect_transceiver_disable(struct dect_transceiver *trx);
>> +
>> +extern void dect_transceiver_confirm(struct dect_transceiver *trx);
>> +extern void dect_transceiver_unlock(struct dect_transceiver *trx);
>> +extern void dect_transceiver_lock(struct dect_transceiver *trx, u8 
>> slot);
>> +
>> +extern int dect_transceiver_set_band(struct dect_transceiver *trx, u8 
>> bandnum);
>> +
>> +static inline void dect_set_channel_mode(struct dect_transceiver 
>> *trx,
>> +                                        const struct 
>> dect_channel_desc *chd,
>> +                                        enum dect_slot_states mode)
>> +{
>> +       trx->ops->set_mode(trx, chd, mode);
>> +       trx->slots[chd->slot].state = mode;
>> +       trx->slots[chd->slot].chd.pkt = chd->pkt;
>> +       trx->slots[chd->slot].chd.b_fmt = chd->b_fmt;
>> +}
>> +
>> +static inline void dect_set_carrier(struct dect_transceiver *trx,
>> +                                   u8 slot, u8 carrier)
>> +{
>> +       trx->slots[slot].chd.carrier = carrier;
>> +       trx->slots[slot].rssi     = 0;
>> +       trx->slots[slot].phaseoff = 0;
>> +       trx->ops->set_carrier(trx, slot, carrier);
>> +}
>> +
>> +static inline void dect_set_flags(struct dect_transceiver *trx, u8 
>> slot, u32 flags)
>> +{
>> +       trx->slots[slot].flags |= flags;
>> +       trx->ops->set_mode(trx, &trx->slots[slot].chd, 
>> trx->slots[slot].state);
>> +}
>> +
>> +static inline void dect_clear_flags(struct dect_transceiver *trx, u8 
>> slot, u32 flags)
>> +{
>> +       trx->slots[slot].flags &= ~flags;
>> +       trx->ops->set_mode(trx, &trx->slots[slot].chd, 
>> trx->slots[slot].state);
>> +}
>> +
>> +static inline void dect_enable_cipher(struct dect_transceiver *trx,
>> +                                     u8 slot, u64 ck)
>> +{
>> +       trx->slots[slot].ck = ck;
>> +       dect_set_flags(trx, slot, DECT_SLOT_CIPHER);
>> +}
>> +
>> +static inline void dect_disable_cipher(struct dect_transceiver *trx, 
>> u8 slot)
>> +{
>> +       dect_clear_flags(trx, slot, DECT_SLOT_CIPHER);
>> +       trx->slots[slot].ck = 0;
>> +}
>> +
>> +static inline void dect_transceiver_tx(struct dect_transceiver *trx,
>> +                                      struct sk_buff *skb)
>> +{
>> +       u8 slot = DECT_TRX_CB(skb)->slot;
>> +
>> +       trx->slots[slot].tx_bytes += skb->len;
>> +       trx->slots[slot].tx_packets++;
>> +       trx->ops->tx(trx, skb);
>> +}
>> +
>> +extern struct sk_buff *dect_transceiver_alloc_skb(struct 
>> dect_transceiver *trx, u8 slot);
>> +
>> +static inline struct dect_transceiver_event *
>> +dect_transceiver_event(struct dect_transceiver *trx, u8 n, u8 
>> slotpos)
>> +{
>> +       struct dect_transceiver_event *event;
>> +
>> +       event = &trx->event[n];
>> +       if (unlikely(!atomic_add_unless(&event->busy, 1, 1))) {
>> +               trx->stats.event_busy++;
>> +               return NULL;
>> +       }
>> +       event->slotpos = slotpos;
>> +       return event;
>> +}
>> +
>> +static inline void dect_transceiver_record_rssi(struct 
>> dect_transceiver_event *event,
>> +                                               u8 slot, u8 rssi)
>> +{
>> +       u8 idx;
>> +
>> +       idx = slot % event->trx->ops->eventrate;
>> +       event->rssi[idx] = rssi;
>> +       event->rssi_mask |= 1 << idx;
>> +}
>> +
>> +static inline void dect_release_transceiver_event(struct 
>> dect_transceiver_event *event)
>> +{
>> +       event->rssi_mask = 0;
>> +       smp_mb__before_atomic_dec();
>> +       atomic_dec(&event->busy);
>> +}
>> +
>> +enum dect_transceiver_events {
>> +       DECT_TRANSCEIVER_REGISTER,
>> +       DECT_TRANSCEIVER_UNREGISTER,
>> +};
>> +
>> +#define DECT_TRX_GROUP_MAX     16
>> +
>> +/**
>> + * struct dect_transceiver_group
>> + *
>> + * @trx:               Transceiver array
>> + * @trxmask:           Mask of present transceivers
>> + * @latency:           Maximum latency of all transceivers
>> + * @blind_full_slots:  combined blind full slots state of all 
>> transceivers
>> + * @tasklet:           Event processing tasklet
>> + * @lock:              Event list lock
>> + * @events:            List of queued events
>> + * @seqno:             Transceiver event loss detection
>> + * @slot_low:          First unhandled slot
>> + * @slot_high:         First slot after slot window
>> + * @slots:             merged events for window slot_low - slot_high
>> + */
>> +struct dect_transceiver_group {
>> +       struct dect_transceiver                 
>> *trx[DECT_TRX_GROUP_MAX];
>> +       u16                                     trxmask;
>> +       u8                                      latency;
>> +       u32                                     blind_full_slots;
>> +
>> +       struct tasklet_struct                   tasklet;
>> +       spinlock_t                              lock;
>> +       struct list_head                        events;
>> +
>> +       u32                                     seqno;
>> +       u8                                      slot_low;
>> +       u8                                      slot_high;
>> +       struct {
>> +               struct sk_buff_head             queue;
>> +               u16                             mask;
>> +               u8                              
>> rssi[DECT_TRX_GROUP_MAX];
>> +       } slots[DECT_HALF_FRAME_SIZE];
>> +};
>> +
>> +extern void dect_transceiver_group_init(struct dect_transceiver_group 
>> *trg);
>> +extern int dect_transceiver_group_add(struct dect_transceiver_group 
>> *trg,
>> +                                     struct dect_transceiver *trx);
>> +extern void dect_transceiver_group_remove(struct 
>> dect_transceiver_group *trg,
>> +                                         struct dect_transceiver 
>> *trx);
>> +
>> +extern bool dect_transceiver_channel_available(const struct 
>> dect_transceiver *trx,
>> +                                              const struct 
>> dect_channel_desc *chd);
>> +extern bool dect_transceiver_reserve(struct dect_transceiver_group 
>> *trg,
>> +                                    struct dect_transceiver *trx,
>> +                                    const struct dect_channel_desc 
>> *chd);
>> +extern bool dect_transceiver_release(struct dect_transceiver_group 
>> *trg,
>> +                                    struct dect_transceiver *trx,
>> +                                    const struct dect_channel_desc 
>> *chd);
>> +
>> +extern void dect_transceiver_queue_event(struct dect_transceiver 
>> *trx,
>> +                                        struct dect_transceiver_event 
>> *ev);
>> +
>> +#define dect_first_transceiver(trg)                                   
>>  \
>> +({                                                                    
>>  \
>> +       struct dect_transceiver_group *_trg = (void *)(trg);           
>>  \
>> +       u32 mask = _trg->trxmask;                                      
>>  \
>> +       mask ? (_trg)->trx[ffs(mask) - 1] : NULL; })
>> +
>> +#define dect_next_transceiver(trx, trg)                               
>>          \
>> +({                                                                    
>>  \
>> +       struct dect_transceiver_group *_trg = (void *)(trg);           
>>  \
>> +       u32 mask = _trg->trxmask;                                      
>>  \
>> +       mask &= ~((1 << ((trx)->index + 1)) - 1);                      
>>  \
>> +       mask ? (_trg)->trx[ffs(mask) - 1] : NULL; })
>> +
>> +#define dect_foreach_transceiver(trx, trg)                            
>>  \
>> +       for ((trx) = dect_first_transceiver(trg);                      
>>  \
>> +            (trx) != NULL;                                            
>>  \
>> +            (trx) = dect_next_transceiver(trx, trg))
>> +
>> +#define dect_last_transceiver(trg)                                    
>>  \
>> +({                                                                    
>>  \
>> +       struct dect_transceiver_group *_trg = (void *)(trg);           
>>  \
>> +       u32 mask = _trg->trxmask;                                      
>>  \
>> +       mask ? (_trg)->trx[fls(mask) - 1] : NULL; })
>> +
>> +#define dect_prev_transceiver(trx, trg)                               
>>          \
>> +({                                                                    
>>  \
>> +       struct dect_transceiver_group *_trg = (void *)(trg);           
>>  \
>> +       u32 mask = _trg->trxmask;                                      
>>  \
>> +       mask &= (1 << (trx)->index) - 1;                               
>>  \
>> +       mask ? (_trg)->trx[fls(mask) - 1] : NULL; })
>> +
>> +#define dect_foreach_transceiver_reverse(trx, trg)                    
>>  \
>> +       for ((trx) = dect_last_transceiver(trg);                       
>>  \
>> +            (trx) != NULL;                                            
>>  \
>> +            (trx) = dect_prev_transceiver(trx, trg))
>> +
>> +extern int dect_transceiver_module_init(void);
>> +extern void dect_transceiver_module_exit(void);
>> +
>> +#endif /* _NET_DECT_TRANSCEIVER_H */
>> diff --git a/target/linux/generic/files/net/dect/Kconfig 
>> b/target/linux/generic/files/net/dect/Kconfig
>> new file mode 100644
>> index 0000000..7e836a9
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/Kconfig
>> @@ -0,0 +1,66 @@
>> +menuconfig DECT
>> +       tristate "DECT protocol support"
>> +       help
>> +         This option enables support for the DECT protocol.
>> +
>> +         If unsure, say N.
>> +
>> +if DECT
>> +
>> +config DECT_DEBUG
>> +       bool "DECT debugging"
>> +       help
>> +         This option enables support for debugging in the DECT 
>> modules.
>> +
>> +         If unsure, say N.
>> +
>> +config DECT_CSF
>> +       tristate "DECT Cell Site Functions (CSF) support"
>> +       help
>> +         This option enables support for DECT Cell Site Functions. A 
>> DECT
>> +         cell is a radio endpoint containing one or more 
>> transceivers.
>> +
>> +         If unsure, say N.
>> +
>> +config DECT_RAW
>> +       tristate "DECT raw sockets"
>> +       depends on DECT_CSF
>> +       help
>> +         This option enables support for PF_DECT raw sockets. DECT 
>> raw
>> +         sockets are used to receive raw frames from DECT devices.
>> +
>> +         If unsure, say N.
>> +
>> +config DECT_CCF
>> +       tristate "DECT Cluster Control Functions (CCF) support"
>> +       help
>> +         This option enables support for the DECT Cluster Control 
>> Functions.
>> +
>> +         A DECT cluster is a Portable radio Termination (PT), 
>> containing a
>> +         single cell, or a Fixed radio Termination (FT), containing 
>> up to
>> +         8 cells.
>> +
>> +         If unsure, say N.
>> +
>> +config DECT_LU1_SAP
>> +       tristate "DECT DLC LU1 SAP sockets"
>> +       select DECT_CCF
>> +       help
>> +         This option enables support for PF_DECT DLC LU1 SAP sockets. 
>> DECT
>> +         DLC LU1 SAP sockets are used for the TRUP (TRansparent 
>> UnProtected)
>> +         service, most commonly used for audio.
>> +
>> +         If unsure, say N.
>> +
>> +config DECT_CCP
>> +       bool "DECT Cell Control Protocol support"
>> +       depends on ( DECT_CSF || DECT_CCF ) && BROKEN
>> +       select TIPC
>> +       help
>> +         This option enables support for the DECT Cell Control 
>> Protocol.
>> +         This can be used to remotely control one or multiple DECT 
>> cells
>> +         by the DECT cluster control functions.
>> +
>> +         If unsure, say N.
>> +
>> +endif
>> diff --git a/target/linux/generic/files/net/dect/Makefile 
>> b/target/linux/generic/files/net/dect/Makefile
>> new file mode 100644
>> index 0000000..7d7bb14
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/Makefile
>> @@ -0,0 +1,17 @@
>> +dect-y                         += core.o identities.o dect_netlink.o 
>> af_dect.o
>> +
>> +dect_csf-y                     += mac_csf.o transceiver.o
>> +
>> +dect_ccf-y                     += mac_ccf.o dsc.o
>> +dect_ccf-y                     += dlc.o
>> +dect_ccf-y                     += dlc_cplane.o dlc_b_sap.o 
>> dlc_s_sap.o
>> +dect_ccf-y                     += dlc_uplane.o
>> +dect_ccf-$(CONFIG_DECT_CCP)    += ccp.o
>> +
>> +dect_raw-y                     += raw.o
>> +
>> +obj-$(CONFIG_DECT)             += dect.o
>> +obj-$(CONFIG_DECT_CSF)         += dect_csf.o
>> +obj-$(CONFIG_DECT_RAW)         += dect_raw.o
>> +obj-$(CONFIG_DECT_CCF)         += dect_ccf.o
>> +obj-$(CONFIG_DECT_LU1_SAP)     += dlc_lu1_sap.o
>> diff --git a/target/linux/generic/files/net/dect/af_dect.c 
>> b/target/linux/generic/files/net/dect/af_dect.c
>> new file mode 100644
>> index 0000000..452df7f
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/af_dect.c
>> @@ -0,0 +1,456 @@
>> +/*
>> + * DECT sockets
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/socket.h>
>> +#include <linux/net.h>
>> +#include <linux/poll.h>
>> +#include <linux/dect.h>
>> +#include <net/sock.h>
>> +#include <net/dect/dect.h>
>> +
>> +static struct dect_proto *dect_protos[DECT_PROTO_NUM];
>> +static DEFINE_SPINLOCK(dect_proto_lock);
>> +
>> +void (*dect_raw_rcv_hook)(struct sk_buff *skb);
>> +EXPORT_SYMBOL_GPL(dect_raw_rcv_hook);
>> +
>> +int dect_proto_register(struct dect_proto *proto)
>> +{
>> +       int err;
>> +
>> +       err = proto_register(&proto->proto, true);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       spin_lock(&dect_proto_lock);
>> +       dect_protos[proto->protocol] = proto;
>> +       spin_unlock(&dect_proto_lock);
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_proto_register);
>> +
>> +void dect_proto_unregister(struct dect_proto *proto)
>> +{
>> +       spin_lock(&dect_proto_lock);
>> +       dect_protos[proto->protocol] = NULL;
>> +       spin_unlock(&dect_proto_lock);
>> +       proto_unregister(&proto->proto);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_proto_unregister);
>> +
>> +struct sk_buff *dect_alloc_notification(u32 type, const void *data,
>> +                                       unsigned int size)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = alloc_skb(size, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return NULL;
>> +       DECT_NOTIFY_CB(skb)->type = type;
>> +       memcpy(skb_put(skb, size), data, size);
>> +       return skb;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_alloc_notification);
>> +
>> +static void dect_destruct(struct sock *sk)
>> +{
>> +       __skb_queue_purge(&sk->sk_receive_queue);
>> +       __skb_queue_purge(&sk->sk_error_queue);
>> +       __skb_queue_purge(&sk->sk_write_queue);
>> +}
>> +
>> +static int dect_release(struct socket *sock)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       long timeout;
>> +
>> +       if (sk == NULL)
>> +               return 0;
>> +
>> +       timeout = 0;
>> +       if (sock_flag(sk, SOCK_LINGER) && !(current->flags & 
>> PF_EXITING))
>> +               timeout = sk->sk_lingertime;
>> +       sock->sk = NULL;
>> +       sk->sk_prot->close(sk, timeout);
>> +       return 0;
>> +}
>> +
>> +static int dect_bind(struct socket *sock, struct sockaddr *uaddr, int 
>> len)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       int err;
>> +
>> +       err = 0;
>> +       if (sk->sk_prot->bind != NULL)
>> +               err = sk->sk_prot->bind(sk, uaddr, len);
>> +
>> +       return err;
>> +}
>> +
>> +static int dect_listen(struct socket *sock, int backlog)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       int err;
>> +
>> +       lock_sock(sk);
>> +       err = -EINVAL;
>> +       if (sock->state != SS_UNCONNECTED ||
>> +           (sock->type != SOCK_STREAM && sock->type != 
>> SOCK_SEQPACKET))
>> +               goto out;
>> +
>> +       if (sk->sk_state != DECT_SK_RELEASED && sk->sk_state != 
>> DECT_SK_LISTEN)
>> +               goto out;
>> +
>> +       if (sk->sk_state != DECT_SK_LISTEN)
>> +               sk->sk_prot->hash(sk);
>> +       sk->sk_max_ack_backlog = backlog;
>> +       err = 0;
>> +out:
>> +       release_sock(sk);
>> +       return err;
>> +}
>> +
>> +static int dect_accept(struct socket *sock, struct socket *newsock, 
>> int flags)
>> +{
>> +       struct sock *sk = sock->sk, *newsk;
>> +       int err;
>> +
>> +       newsk = sk->sk_prot->accept(sk, flags, &err);
>> +       if (newsk == NULL)
>> +               return err;
>> +
>> +       lock_sock(newsk);
>> +       sock_graft(newsk, newsock);
>> +       newsock->state = SS_CONNECTED;
>> +       release_sock(newsk);
>> +       return 0;
>> +}
>> +
>> +static unsigned int dect_poll(struct file *file, struct socket *sock,
>> +                             struct poll_table_struct *wait)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       unsigned int mask;
>> +
>> +       poll_wait(file, sk_sleep(sk), wait);
>> +       mask = 0;
>> +
>> +       if (sk->sk_state == DECT_SK_LISTEN) {
>> +               if (!hlist_empty(&dect_csk(sk)->accept_queue))
>> +                       return POLLIN | POLLRDNORM;
>> +               return 0;
>> +       }
>> +
>> +       /* exceptional events? */
>> +       if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
>> +               mask |= POLLERR;
>> +       if (sk->sk_shutdown & RCV_SHUTDOWN)
>> +               mask |= POLLRDHUP;
>> +       if (sk->sk_shutdown == SHUTDOWN_MASK)
>> +               mask |= POLLHUP;
>> +
>> +       /* readable? */
>> +       if (!skb_queue_empty(&sk->sk_receive_queue) ||
>> +           (sk->sk_shutdown & RCV_SHUTDOWN))
>> +               mask |= POLLIN | POLLRDNORM;
>> +
>> +       /* Connection-based need to check for termination and startup 
>> */
>> +       if (sk->sk_state == DECT_SK_RELEASED)
>> +               mask |= POLLHUP;
>> +       /* connection hasn't started yet? */
>> +       if (sk->sk_state == DECT_SK_ESTABLISH_PENDING)
>> +               return mask;
>> +
>> +       /* writable? */
>> +       if (sock_writeable(sk))
>> +               mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
>> +       else
>> +               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
>> +
>> +       return mask;
>> +}
>> +
>> +static int dect_shutdown(struct socket *sock, int how)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       int err = 0;
>> +
>> +       how++;
>> +       if ((how & ~SHUTDOWN_MASK) || !how)
>> +               return -EINVAL;
>> +
>> +       lock_sock(sk);
>> +
>> +       if (sock->state == SS_CONNECTING &&
>> +           sk->sk_state == DECT_SK_ESTABLISH_PENDING)
>> +               sock->state = SS_DISCONNECTING;
>> +
>> +       switch (sk->sk_state) {
>> +       case DECT_SK_RELEASED:
>> +               err = -ENOTCONN;
>> +               break;
>> +       case DECT_SK_LISTEN:
>> +               if (!(how & RCV_SHUTDOWN))
>> +                       break;
>> +       default:
>> +               sk->sk_shutdown |= how;
>> +               if (sk->sk_prot->shutdown != NULL)
>> +                       sk->sk_prot->shutdown(sk, how);
>> +       }
>> +
>> +       /* wake up processes sleeping in poll() */
>> +       sk->sk_state_change(sk);
>> +       release_sock(sk);
>> +       return err;
>> +}
>> +
>> +static int dect_connect(struct socket *sock, struct sockaddr *uaddr, 
>> int len,
>> +                       int flags)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       long timeo;
>> +       int err;
>> +
>> +       lock_sock(sk);
>> +       switch (sock->state) {
>> +       case SS_CONNECTED:
>> +               err = -EISCONN;
>> +               goto out;
>> +       case SS_CONNECTING:
>> +               err = -EALREADY;
>> +               goto out;
>> +       case SS_UNCONNECTED:
>> +               err = -EISCONN;
>> +               if (sk->sk_state != DECT_SK_RELEASED)
>> +                       goto out;
>> +               err = sk->sk_prot->connect(sk, uaddr, len);
>> +               if (err < 0)
>> +                       goto out;
>> +               sock->state = SS_CONNECTING;
>> +               err = -EINPROGRESS;
>> +               break;
>> +       default:
>> +               err = -EINVAL;
>> +               goto out;
>> +       }
>> +
>> +       if (sk->sk_state == DECT_SK_ESTABLISH_PENDING) {
>> +               timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
>> +               err = sk_stream_wait_connect(sk, &timeo);
>> +               if (err < 0)
>> +                       goto out;
>> +
>> +               err = sock_intr_errno(timeo);
>> +               if (signal_pending(current))
>> +                       goto out;
>> +       }
>> +
>> +       /* Connection establishment was aborted or failed */
>> +       if (sk->sk_state == DECT_SK_RELEASED)
>> +               goto sock_error;
>> +
>> +       sock->state = SS_CONNECTED;
>> +       err = 0;
>> +out:
>> +       release_sock(sk);
>> +       return err;
>> +
>> +sock_error:
>> +       err = sock_error(sk) ? : -ECONNABORTED;
>> +       sock->state = SS_UNCONNECTED;
>> +       goto out;
>> +}
>> +
>> +static int dect_getname(struct socket *sock, struct sockaddr *uaddr, 
>> int *len,
>> +                       int peer)
>> +{
>> +       const struct dect_proto *p;
>> +
>> +       /* AF_DECT uses different address formats for the different 
>> SAPs */
>> +       p = container_of(sock->sk->sk_prot, struct dect_proto, proto);
>> +       if (p->getname != NULL)
>> +               return p->getname(sock->sk, uaddr, len, peer);
>> +       *len = 0;
>> +       return 0;
>> +}
>> +
>> +static int dect_sendmsg(struct kiocb *iocb, struct socket *sock,
>> +                       struct msghdr *msg, size_t size)
>> +{
>> +       struct sock *sk = sock->sk;
>> +
>> +       return sk->sk_prot->sendmsg(iocb, sk, msg, size);
>> +}
>> +
>> +static int dect_setsockopt(struct socket *sock, int level, int 
>> optname,
>> +                          char __user *optval, unsigned int optlen)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       int err;
>> +
>> +       if (level != SOL_DECT)
>> +               return -ENOPROTOOPT;
>> +
>> +       switch (optname) {
>> +       default:
>> +               if (sk->sk_prot->setsockopt)
>> +                       err = sk->sk_prot->setsockopt(sk, level, 
>> optname,
>> +                                                     optval, optlen);
>> +               else
>> +                       err = -ENOPROTOOPT;
>> +       }
>> +       return err;
>> +}
>> +
>> +static int dect_getsockopt(struct socket *sock, int level, int 
>> optname,
>> +                          char __user *optval, int __user *optlen)
>> +{
>> +       struct sock *sk = sock->sk;
>> +       int err;
>> +
>> +       if (level != SOL_DECT)
>> +               return -ENOPROTOOPT;
>> +
>> +       switch (optname) {
>> +       default:
>> +               if (sk->sk_prot->getsockopt)
>> +                       err = sk->sk_prot->getsockopt(sk, level, 
>> optname,
>> +                                                     optval, optlen);
>> +               else
>> +                       err = -ENOPROTOOPT;
>> +       }
>> +       return err;
>> +}
>> +
>> +static int dect_create(struct net *net, struct socket *sock, int 
>> protocol,
>> +                      int kern)
>> +{
>> +       struct dect_proto *p;
>> +       struct sock *sk;
>> +       int err = 0;
>> +
>> +       if (protocol < 0 || protocol >= DECT_PROTO_NUM)
>> +               return -EPROTONOSUPPORT;
>> +#ifdef CONFIG_MODULES
>> +       if (dect_protos[protocol] == NULL) {
>> +               err = request_module("net-pf-%d-proto-%d", PF_DECT, 
>> protocol);
>> +               if (err < 0)
>> +                       return err;
>> +       }
>> +#endif
>> +       spin_lock(&dect_proto_lock);
>> +       p = dect_protos[protocol];
>> +       if (p != NULL && !try_module_get(p->proto.owner))
>> +               p = NULL;
>> +       spin_unlock(&dect_proto_lock);
>> +
>> +       if (p == NULL)
>> +               return -EPROTONOSUPPORT;
>> +
>> +       if (p->type != sock->type) {
>> +               err = -EPROTONOSUPPORT;
>> +               goto err;
>> +       }
>> +
>> +       if (cap_valid(p->capability) && !capable(p->capability)) {
>> +               err = -EACCES;
>> +               goto err;
>> +       }
>> +
>> +       sock->state = SS_UNCONNECTED;
>> +       sock->ops = p->ops;
>> +
>> +       sk = sk_alloc(net, PF_DECT, GFP_KERNEL, &p->proto);
>> +       if (sk == NULL) {
>> +               err = -ENOMEM;
>> +               goto err;
>> +       }
>> +
>> +       sock_init_data(sock, sk);
>> +       sk->sk_protocol = protocol;
>> +       sk->sk_destruct = dect_destruct;
>> +
>> +       if (sk->sk_prot->init != NULL) {
>> +               err = sk->sk_prot->init(sk);
>> +               if (err < 0) {
>> +                       sock_orphan(sk);
>> +                       sock_put(sk);
>> +               }
>> +       }
>> +err:
>> +       module_put(p->proto.owner);
>> +       return err;
>> +}
>> +
>> +const struct proto_ops dect_stream_ops = {
>> +       .family         = PF_DECT,
>> +       .owner          = THIS_MODULE,
>> +       .release        = dect_release,
>> +       .bind           = dect_bind,
>> +       .connect        = dect_connect,
>> +       .socketpair     = sock_no_socketpair,
>> +       .getname        = dect_getname,
>> +       .poll           = dect_poll,
>> +       .ioctl          = sock_no_ioctl,
>> +       .listen         = dect_listen,
>> +       .accept         = dect_accept,
>> +       .shutdown       = dect_shutdown,
>> +       .setsockopt     = dect_setsockopt,
>> +       .getsockopt     = dect_getsockopt,
>> +       .sendmsg        = dect_sendmsg,
>> +       .recvmsg        = sock_common_recvmsg,
>> +       .mmap           = sock_no_mmap,
>> +       .sendpage       = sock_no_sendpage,
>> +};
>> +EXPORT_SYMBOL_GPL(dect_stream_ops);
>> +
>> +const struct proto_ops dect_dgram_ops = {
>> +       .family         = PF_DECT,
>> +       .owner          = THIS_MODULE,
>> +       .release        = dect_release,
>> +       .bind           = dect_bind,
>> +       .connect        = sock_no_connect,
>> +       .socketpair     = sock_no_socketpair,
>> +       .getname        = dect_getname,
>> +       .poll           = datagram_poll,
>> +       .ioctl          = sock_no_ioctl,
>> +       .listen         = sock_no_listen,
>> +       .accept         = sock_no_accept,
>> +       .shutdown       = sock_no_shutdown,
>> +       .setsockopt     = sock_no_setsockopt,
>> +       .getsockopt     = sock_no_getsockopt,
>> +       .sendmsg        = dect_sendmsg,
>> +       .recvmsg        = sock_common_recvmsg,
>> +       .mmap           = sock_no_mmap,
>> +       .sendpage       = sock_no_sendpage,
>> +};
>> +EXPORT_SYMBOL_GPL(dect_dgram_ops);
>> +
>> +static struct net_proto_family dect_family_ops = {
>> +       .family         = PF_DECT,
>> +       .create         = dect_create,
>> +       .owner          = THIS_MODULE,
>> +};
>> +
>> +int __init dect_af_module_init(void)
>> +{
>> +       return sock_register(&dect_family_ops);
>> +}
>> +
>> +void dect_af_module_exit(void)
>> +{
>> +       sock_unregister(PF_DECT);
>> +}
>> +
>> +MODULE_ALIAS_NETPROTO(PF_DECT);
>> diff --git a/target/linux/generic/files/net/dect/ccp.c 
>> b/target/linux/generic/files/net/dect/ccp.c
>> new file mode 100644
>> index 0000000..d423a96
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/ccp.c
>> @@ -0,0 +1,906 @@
>> +/*
>> + * DECT Cell Control Protocol
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_csf.h>
>> +#include <net/dect/mac_ccf.h>
>> +#include <net/dect/ccp.h>
>> +#include <net/tipc/tipc.h>
>> +
>> +static struct sk_buff *dect_ccp_msg_alloc(size_t size)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       size += sizeof(struct dect_ccp_msg_hdr) + 2 * LL_MAX_HEADER;
>> +       skb = alloc_skb(size, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return NULL;
>> +       skb_reserve(skb, size);
>> +       return skb;
>> +}
>> +
>> +static void dect_ccp_build_msg(struct sk_buff *skb,
>> +                              enum dect_ccp_primitives prim)
>> +{
>> +       struct dect_ccp_msg_hdr *h;
>> +
>> +       h = (struct dect_ccp_msg_hdr *)skb_push(skb, sizeof(*h));
>> +       h->primitive = prim;
>> +}
>> +
>> +static int dect_ccp_send_to_cell(const struct dect_cell_handle *ch,
>> +                                struct sk_buff *skb,
>> +                                enum dect_ccp_primitives prim)
>> +{
>> +       int err;
>> +
>> +       dect_ccp_build_msg(skb, prim);
>> +       err = tipc_send_buf(ch->portref, skb, skb->len);
>> +       if (err < 0 && net_ratelimit())
>> +               printk("Failed to send DECT CCP message\n");
>> +       return err;
>> +}
>> +
>> +static int dect_ccp_send_to_cluster(const struct dect_cluster_handle 
>> *clh,
>> +                                   struct sk_buff *skb,
>> +                                   enum dect_ccp_primitives prim)
>> +{
>> +       int err;
>> +
>> +       dect_ccp_build_msg(skb, prim);
>> +       err = tipc_send_buf(clh->portref, skb, skb->len);
>> +       if (err < 0 && net_ratelimit())
>> +               printk("Failed to send DECT CCP message\n");
>> +       return err;
>> +}
>> +
>> +static void dect_ccp_build_tbc_msg(struct sk_buff *skb, const struct 
>> dect_tbc_id *id,
>> +                                  u8 data)
>> +{
>> +       struct dect_ccp_tbc_msg *msg;
>> +
>> +       msg = (struct dect_ccp_tbc_msg *)__skb_push(skb, 
>> sizeof(*msg));
>> +       msg->tbei = cpu_to_be32(id->tbei);
>> +       msg->pmid = cpu_to_be32(dect_build_pmid(&id->pmid));
>> +       msg->ari  = cpu_to_be64(dect_build_ari(&id->ari));
>> +       msg->ecn  = id->ecn;
>> +       msg->data = data;
>> +}
>> +
>> +static bool dect_ccp_parse_tbc_msg(struct dect_tbc_id *id, u8 *data,
>> +                                  struct sk_buff *skb)
>> +{
>> +       struct dect_ccp_tbc_msg *msg;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return false;
>> +       msg = (struct dect_ccp_tbc_msg *)skb->data;
>> +       __skb_pull(skb, sizeof(*msg));
>> +
>> +       id->tbei = be32_to_cpu(msg->tbei);
>> +       dect_parse_pmid(&id->pmid, be32_to_cpu(msg->pmid));
>> +       if (!dect_parse_ari(&id->ari, be64_to_cpu(msg->ari)))
>> +               return false;
>> +       id->ecn = msg->ecn;
>> +       if (data != NULL)
>> +               *data = msg->data;
>> +       return true;
>> +}
>> +
>> +static void dect_ccp_build_sysinfo(struct sk_buff *skb,
>> +                                  const struct dect_ari *pari, u8 
>> rpn,
>> +                                  const struct dect_si *si)
>> +{
>> +       struct dect_ccp_sysinfo_msg *msg;
>> +       unsigned int i;
>> +
>> +       msg = (struct dect_ccp_sysinfo_msg *)__skb_push(skb, 
>> sizeof(*msg));
>> +       msg->pari = cpu_to_be64(dect_build_ari(pari));
>> +       for (i = 0; i < si->num_saris; i++)
>> +               msg->sari[i] = 
>> cpu_to_be64(dect_build_ari(&si->sari[i].ari));
>> +       msg->num_saris = i;
>> +       msg->fpc = cpu_to_be64(si->fpc.fpc);
>> +       msg->hlc = cpu_to_be64(si->fpc.hlc);
>> +       msg->mfn = cpu_to_be32(si->mfn.num);
>> +       msg->rpn = rpn;
>> +}
>> +
>> +static bool dect_ccp_parse_sysinfo(struct dect_ari *pari, u8 *rpn,
>> +                                  struct dect_si *si, struct sk_buff 
>> *skb)
>> +{
>> +       struct dect_ccp_sysinfo_msg *msg;
>> +       unsigned int i;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return false;
>> +       msg = (struct dect_ccp_sysinfo_msg *)skb->data;
>> +       __skb_pull(skb, sizeof(*msg));
>> +
>> +       if (!dect_parse_ari(pari, be64_to_cpu(msg->pari)))
>> +               return false;
>> +       *rpn = msg->rpn;
>> +
>> +       if (msg->num_saris > ARRAY_SIZE(si->sari))
>> +               return false;
>> +       for (i = 0; i < msg->num_saris; i++) {
>> +               if (!dect_parse_ari(&si->sari[i].ari,
>> +                                   be64_to_cpu(msg->sari[i])))
>> +                       return false;
>> +       }
>> +       si->fpc.fpc = be64_to_cpu(msg->fpc);
>> +       si->fpc.hlc = be64_to_cpu(msg->hlc);
>> +       si->mfn.num = be32_to_cpu(msg->mfn);
>> +       return true;
>> +}
>> +
>> +static int dect_ccp_send_set_mode(const struct dect_cell_handle *ch,
>> +                                 enum dect_cluster_modes mode)
>> +{
>> +       struct dect_ccp_mode_msg *msg;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(*msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       msg = (struct dect_ccp_mode_msg *)__skb_push(skb, 
>> sizeof(*msg));
>> +       msg->mode = mode;
>> +
>> +       return dect_ccp_send_to_cell(ch, skb, DECT_CCP_SET_MODE);
>> +}
>> +
>> +static void dect_ccp_parse_set_mode(const struct dect_cell_handle 
>> *ch,
>> +                                   struct sk_buff *skb)
>> +{
>> +       struct dect_ccp_mode_msg *msg;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return;
>> +       msg = (struct dect_ccp_mode_msg *)skb->data;
>> +
>> +       ch->ops->set_mode(ch, msg->mode);
>> +}
>> +
>> +static int dect_ccp_send_scan(const struct dect_cell_handle *ch,
>> +                             const struct dect_llme_req *lreq,
>> +                             const struct dect_ari *ari,
>> +                             const struct dect_ari *ari_mask)
>> +{
>> +       struct dect_ccp_scan_msg *msg;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(*msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       msg = (struct dect_ccp_scan_msg *)__skb_push(skb, 
>> sizeof(*msg));
>> +       msg->ari = cpu_to_be64(dect_build_ari(ari));
>> +       msg->ari_mask = cpu_to_be64(dect_build_ari(ari_mask));
>> +
>> +       return dect_ccp_send_to_cell(ch, skb, DECT_CCP_SCAN);
>> +}
>> +
>> +static void dect_ccp_parse_scan(const struct dect_cell_handle *ch,
>> +                               struct sk_buff *skb)
>> +{
>> +       struct dect_ccp_scan_msg *msg;
>> +       struct dect_ari ari, ari_mask;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return;
>> +       msg = (struct dect_ccp_scan_msg *)skb->data;
>> +
>> +       if (!dect_parse_ari(&ari, be64_to_cpu(msg->ari)))
>> +               return;
>> +       if (!dect_parse_ari(&ari_mask, be64_to_cpu(msg->ari_mask)))
>> +               return;
>> +       ch->ops->scan(ch, NULL, &ari, &ari_mask);
>> +}
>> +
>> +static int dect_ccp_send_preload(const struct dect_cell_handle *ch,
>> +                                const struct dect_ari *pari, u8 rpn,
>> +                                const struct dect_si *si)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_sysinfo_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_sysinfo(skb, pari, rpn, si);
>> +
>> +       return dect_ccp_send_to_cell(ch, skb, DECT_CCP_PRELOAD);
>> +}
>> +
>> +static void dect_ccp_parse_preload(const struct dect_cell_handle *ch,
>> +                                  struct sk_buff *skb)
>> +{
>> +       struct dect_ari pari;
>> +       struct dect_si si;
>> +       u8 rpn;
>> +
>> +       if (!dect_ccp_parse_sysinfo(&pari, &rpn, &si, skb))
>> +               return;
>> +       ch->ops->preload(ch, &pari, rpn, &si);
>> +}
>> +
>> +static int dect_ccp_send_enable(const struct dect_cell_handle *ch)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(0);
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       return dect_ccp_send_to_cell(ch, skb, DECT_CCP_ENABLE);
>> +}
>> +
>> +static void dect_ccp_parse_enable(const struct dect_cell_handle *ch,
>> +                                 struct sk_buff *skb)
>> +{
>> +       ch->ops->enable(ch);
>> +}
>> +
>> +static void dect_ccp_send_page_req(const struct dect_cell_handle *ch,
>> +                                  struct sk_buff *skb)
>> +{
>> +       struct dect_ccp_page_msg *msg;
>> +
>> +       msg = (struct dect_ccp_page_msg *)__skb_push(skb, 
>> sizeof(*msg));
>> +       msg->fast_page = DECT_BMC_CB(skb)->fast_page;
>> +       msg->long_page = DECT_BMC_CB(skb)->long_page;
>> +
>> +       dect_ccp_send_to_cell(ch, skb, DECT_CCP_PAGE_REQ);
>> +}
>> +
>> +static void dect_ccp_parse_page_req(const struct dect_cell_handle 
>> *ch,
>> +                                   struct sk_buff *skb)
>> +{
>> +       struct dect_ccp_page_msg *msg;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return;
>> +       msg = (struct dect_ccp_page_msg *)skb->data;
>> +       __pskb_pull(skb, sizeof(*msg));
>> +
>> +       DECT_BMC_CB(skb)->fast_page = msg->fast_page;
>> +       DECT_BMC_CB(skb)->long_page = msg->long_page;
>> +
>> +       ch->ops->page_req(ch, skb);
>> +}
>> +
>> +static int dect_ccp_send_tbc_establish_req(const struct 
>> dect_cell_handle *ch,
>> +                                          const struct dect_tbc_id 
>> *id,
>> +                                          const struct 
>> dect_channel_desc *chd,
>> +                                          enum dect_mac_service_types 
>> service,
>> +                                          bool handover)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, 0);
>> +       return dect_ccp_send_to_cell(ch, skb, 
>> DECT_CCP_TBC_ESTABLISH_REQ);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_establish_req(const struct 
>> dect_cell_handle *ch,
>> +                                            struct sk_buff *skb)
>> +{
>> +       struct dect_tbc_id id;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, NULL, skb))
>> +               return;
>> +       ch->ops->tbc_establish_req(ch, &id, NULL, 
>> DECT_SERVICE_IN_MIN_DELAY, false);
>> +}
>> +
>> +static void dect_ccp_send_tbc_dis_req(const struct dect_cell_handle 
>> *ch,
>> +                                     const struct dect_tbc_id *id,
>> +                                     enum dect_release_reasons 
>> reason)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return;
>> +       dect_ccp_build_tbc_msg(skb, id, reason);
>> +       dect_ccp_send_to_cell(ch, skb, DECT_CCP_TBC_DIS_REQ);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_dis_req(const struct dect_cell_handle 
>> *ch,
>> +                                      struct sk_buff *skb)
>> +{
>> +       struct dect_tbc_id id;
>> +       u8 reason;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, &reason, skb))
>> +               return;
>> +       ch->ops->tbc_dis_req(ch, &id, reason);
>> +}
>> +
>> +static int dect_ccp_send_tbc_establish_res(const struct 
>> dect_cell_handle *ch,
>> +                                          const struct dect_tbc_id 
>> *id)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, 0);
>> +       return dect_ccp_send_to_cell(ch, skb, 
>> DECT_CCP_TBC_ESTABLISH_RES);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_establish_res(const struct 
>> dect_cell_handle *ch,
>> +                                            struct sk_buff *skb)
>> +{
>> +       struct dect_tbc_id id;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, NULL, skb))
>> +               return;
>> +       ch->ops->tbc_establish_res(ch, &id);
>> +}
>> +
>> +static void dect_ccp_send_tbc_data_req(const struct dect_cell_handle 
>> *ch,
>> +                                      const struct dect_tbc_id *id,
>> +                                      enum dect_data_channels chan,
>> +                                      struct sk_buff *skb)
>> +{
>> +       dect_ccp_build_tbc_msg(skb, id, chan);
>> +       dect_ccp_send_to_cell(ch, skb, DECT_CCP_TBC_DATA_REQ);
>> +}
>> +
>> +static int dect_ccp_send_tbc_enc_key_req(const struct 
>> dect_cell_handle *ch,
>> +                                        const struct dect_tbc_id *id, 
>> u64 ck)
>> +{
>> +       struct dect_ccp_enc_key_msg *msg;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg) + 
>> sizeof(*msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +
>> +       dect_ccp_build_tbc_msg(skb, id, 0);
>> +       msg = (struct dect_ccp_enc_key_msg *)skb_tail_pointer(skb);
>> +       msg->key = cpu_to_be64(ck);
>> +
>> +       return dect_ccp_send_to_cell(ch, skb, 
>> DECT_CCP_TBC_ENC_KEY_REQ);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_enc_key_req(const struct 
>> dect_cell_handle *ch,
>> +                                          struct sk_buff *skb)
>> +{
>> +       const struct dect_ccp_enc_key_msg *msg;
>> +       struct dect_tbc_id id;
>> +       u64 ck;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, NULL, skb))
>> +               return;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*msg)))
>> +               return;
>> +       msg = (struct dect_ccp_enc_key_msg *)skb->data;
>> +       ck = be64_to_cpu(msg->key);
>> +
>> +       ch->ops->tbc_enc_key_req(ch, &id, ck);
>> +}
>> +
>> +static int dect_ccp_send_tbc_enc_eks_req(const struct 
>> dect_cell_handle *ch,
>> +                                        const struct dect_tbc_id *id,
>> +                                        enum dect_cipher_states 
>> status)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, status);
>> +       return dect_ccp_send_to_cell(ch, skb, 
>> DECT_CCP_TBC_ENC_EKS_REQ);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_enc_eks_req(const struct 
>> dect_cell_handle *ch,
>> +                                          struct sk_buff *skb)
>> +{
>> +       struct dect_tbc_id id;
>> +       u8 status;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, &status, skb))
>> +               return;
>> +
>> +       switch (status) {
>> +       case DECT_CIPHER_DISABLED:
>> +       case DECT_CIPHER_ENABLED:
>> +               break;
>> +       default:
>> +               return;
>> +       }
>> +
>> +       ch->ops->tbc_enc_eks_req(ch, &id, status);
>> +}
>> +
>> +static void dect_ccp_send_scan_report(const struct 
>> dect_cluster_handle *clh,
>> +                                     const struct dect_scan_result 
>> *res)
>> +{
>> +}
>> +
>> +static void dect_ccp_send_mac_info_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                      const struct dect_idi *idi,
>> +                                      const struct dect_si *si)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_sysinfo_msg));
>> +       if (skb == NULL)
>> +               return;
>> +
>> +       dect_ccp_build_sysinfo(skb, &idi->pari, idi->rpn, si);
>> +       dect_ccp_send_to_cluster(clh, skb, DECT_CCP_MAC_INFO_IND);
>> +}
>> +
>> +static void dect_ccp_parse_mac_info_ind(const struct dect_cell_handle 
>> *ch,
>> +                                       struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_idi idi;
>> +       struct dect_si si;
>> +
>> +       if (!dect_ccp_parse_sysinfo(&idi.pari, &idi.rpn, &si, skb))
>> +               return;
>> +       idi.e = si.num_saris ? true : false;
>> +
>> +       clh->ops->mac_info_ind(clh, &idi, &si);
>> +}
>> +
>> +static int dect_ccp_send_tbc_establish_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                          const struct 
>> dect_cell_handle *ch,
>> +                                          const struct dect_tbc_id 
>> *id,
>> +                                          enum dect_mac_service_types 
>> service,
>> +                                          bool handover)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, 0);
>> +
>> +       return dect_ccp_send_to_cluster(clh, skb, 
>> DECT_CCP_TBC_ESTABLISH_IND);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_establish_ind(const struct 
>> dect_cell_handle *ch,
>> +                                            struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_tbc_id id;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, NULL, skb))
>> +               return;
>> +       clh->ops->tbc_establish_ind(clh, ch, &id, 
>> DECT_SERVICE_IN_MIN_DELAY, false);
>> +}
>> +
>> +static int dect_ccp_send_tbc_establish_cfm(const struct 
>> dect_cluster_handle *clh,
>> +                                          const struct dect_tbc_id 
>> *id,
>> +                                          bool success, u8 rx_slot)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, 0);
>> +
>> +       return dect_ccp_send_to_cluster(clh, skb, 
>> DECT_CCP_TBC_ESTABLISH_CFM);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_establish_cfm(const struct 
>> dect_cell_handle *ch,
>> +                                            struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_tbc_id id;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, NULL, skb))
>> +               return;
>> +       clh->ops->tbc_establish_cfm(clh, &id, true, 0);
>> +}
>> +
>> +static int dect_ccp_send_tbc_event_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                      const struct dect_tbc_id *id,
>> +                                      enum dect_tbc_event event)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, event);
>> +
>> +       return dect_ccp_send_to_cluster(clh, skb, 
>> DECT_CCP_TBC_EVENT_IND);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_event_ind(const struct 
>> dect_cell_handle *ch,
>> +                                        struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_tbc_id id;
>> +       u8 event;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, &event, skb))
>> +               return;
>> +       clh->ops->tbc_event_ind(clh, &id, event);
>> +}
>> +
>> +static void dect_ccp_send_tbc_data_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                      const struct dect_tbc_id *id,
>> +                                      enum dect_data_channels chan,
>> +                                      struct sk_buff *skb)
>> +{
>> +       dect_ccp_build_tbc_msg(skb, id, chan);
>> +       dect_ccp_send_to_cluster(clh, skb, DECT_CCP_TBC_DATA_IND);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_data_ind(const struct dect_cell_handle 
>> *ch,
>> +                                       struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_tbc_id id;
>> +       u8 chan;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, &chan, skb))
>> +               return;
>> +       clh->ops->tbc_data_ind(clh, &id, chan, skb);
>> +}
>> +
>> +static void dect_ccp_send_tbc_dis_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                     const struct dect_tbc_id *id,
>> +                                     enum dect_release_reasons 
>> reason)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_tbc_msg));
>> +       if (skb == NULL)
>> +               return;// -ENOMEM;
>> +       dect_ccp_build_tbc_msg(skb, id, reason);
>> +
>> +       dect_ccp_send_to_cluster(clh, skb, DECT_CCP_TBC_DIS_IND);
>> +}
>> +
>> +static void dect_ccp_parse_tbc_dis_ind(const struct dect_cell_handle 
>> *ch,
>> +                                      struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = ch->clh;
>> +       struct dect_tbc_id id;
>> +       u8 reason;
>> +
>> +       if (!dect_ccp_parse_tbc_msg(&id, &reason, skb))
>> +               return;
>> +       clh->ops->tbc_dis_ind(clh, &id, reason);
>> +}
>> +
>> +static void dect_ccp_rcv_cell_msg(void *handle, u32 portref,
>> +                                 struct sk_buff **pskb,
>> +                                 const u8 *data, u32 size)
>> +{
>> +       struct dect_cell_handle *ch = handle;
>> +       struct dect_ccp_msg_hdr *h;
>> +       struct sk_buff *skb = *pskb;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*h)))
>> +               return;
>> +       h = (struct dect_ccp_msg_hdr *)skb->data;
>> +       __skb_pull(skb, sizeof(*h));
>> +
>> +       switch (h->primitive) {
>> +       case DECT_CCP_MAC_INFO_IND:
>> +               return dect_ccp_parse_mac_info_ind(ch, skb);
>> +       case DECT_CCP_TBC_ESTABLISH_IND:
>> +               return dect_ccp_parse_tbc_establish_ind(ch, skb);
>> +       case DECT_CCP_TBC_ESTABLISH_CFM:
>> +               return dect_ccp_parse_tbc_establish_cfm(ch, skb);
>> +       case DECT_CCP_TBC_EVENT_IND:
>> +               return dect_ccp_parse_tbc_event_ind(ch, skb);
>> +       case DECT_CCP_TBC_DATA_IND:
>> +               return dect_ccp_parse_tbc_data_ind(ch, skb);
>> +       case DECT_CCP_TBC_DIS_IND:
>> +               return dect_ccp_parse_tbc_dis_ind(ch, skb);
>> +       }
>> +}
>> +
>> +static void dect_ccp_cl_disconnect(void *handle, u32 portref,
>> +                                  struct sk_buff **pskb,
>> +                                  const u8 *data, u32 size, int 
>> reason)
>> +{
>> +       struct dect_cell_handle *ch = handle;
>> +       struct dect_cluster_handle *clh = ch->clh;
>> +
>> +       pr_debug("cell disconnected\n");
>> +       clh->ops->unbind(clh, ch);
>> +       kfree(ch);
>> +}
>> +
>> +static const struct dect_csf_ops dect_ccp_csf_ops = {
>> +       .set_mode               = dect_ccp_send_set_mode,
>> +       .scan                   = dect_ccp_send_scan,
>> +       .enable                 = dect_ccp_send_enable,
>> +       .preload                = dect_ccp_send_preload,
>> +       .page_req               = dect_ccp_send_page_req,
>> +       .tbc_establish_req      = dect_ccp_send_tbc_establish_req,
>> +       .tbc_establish_res      = dect_ccp_send_tbc_establish_res,
>> +       .tbc_dis_req            = dect_ccp_send_tbc_dis_req,
>> +       .tbc_enc_key_req        = dect_ccp_send_tbc_enc_key_req,
>> +       .tbc_enc_eks_req        = dect_ccp_send_tbc_enc_eks_req,
>> +       .tbc_data_req           = dect_ccp_send_tbc_data_req,
>> +};
>> +
>> +static void dect_ccp_cl_named_msg(void *handle, u32 portref,
>> +                                 struct sk_buff **pskb,
>> +                                 const u8 *data, u32 size,
>> +                                 u32 importance,
>> +                                 const struct tipc_portid *source,
>> +                                 const struct tipc_name_seq *dest)
>> +{
>> +       struct dect_cluster *cl = handle;
>> +       struct dect_cluster_handle *clh = &cl->handle;
>> +       struct dect_cell_handle *ch;
>> +       struct iovec ack = { NULL, 0};
>> +       int err;
>> +
>> +       ch = kzalloc(sizeof(*ch), GFP_ATOMIC);
>> +       if (ch == NULL)
>> +               goto err1;
>> +       ch->ops = &dect_ccp_csf_ops;
>> +
>> +       err = tipc_createport(cl->tipc_id, ch, TIPC_HIGH_IMPORTANCE,
>> +                             NULL, NULL, dect_ccp_cl_disconnect,
>> +                             NULL, NULL, dect_ccp_rcv_cell_msg, NULL,
>> +                             &ch->portref);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       err = tipc_connect2port(ch->portref, source);
>> +       if (err < 0)
>> +               goto err3;
>> +
>> +       err = tipc_send(ch->portref, 1, &ack);
>> +       if (err < 0)
>> +               goto err3;
>> +
>> +       err = clh->ops->bind(clh, ch);
>> +       if (err < 0)
>> +               goto err4;
>> +       return;
>> +
>> +err4:
>> +       tipc_disconnect(ch->portref);
>> +err3:
>> +       tipc_deleteport(ch->portref);
>> +err2:
>> +       kfree(ch);
>> +err1:
>> +       return;
>> +}
>> +
>> +/**
>> + * dect_ccp_cluster_init - Initialize a cluster control CCP instance
>> + *
>> + * @cl:                DECT cluster
>> + */
>> +int dect_ccp_cluster_init(struct dect_cluster *cl)
>> +{
>> +       struct tipc_name_seq seq;
>> +       int err;
>> +
>> +       err = tipc_attach(&cl->tipc_id, NULL, NULL);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       err = tipc_createport(cl->tipc_id, cl, TIPC_HIGH_IMPORTANCE,
>> +                             NULL, NULL, NULL, NULL, 
>> dect_ccp_cl_named_msg,
>> +                             NULL, NULL, &cl->tipc_portref);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       seq.type  = DECT_CCP_TIPC_TYPE;
>> +       seq.lower = DECT_CCP_CLUSTER_PORT_BASE + cl->index;
>> +       seq.upper = DECT_CCP_CLUSTER_PORT_BASE + cl->index;
>> +       err = tipc_publish(cl->tipc_portref, TIPC_CLUSTER_SCOPE, 
>> &seq);
>> +       if (err < 0)
>> +               goto err3;
>> +       return 0;
>> +
>> +err3:
>> +       tipc_deleteport(cl->tipc_portref);
>> +err2:
>> +       tipc_detach(cl->tipc_id);
>> +err1:
>> +       return err;
>> +}
>> +
>> +void dect_ccp_cluster_shutdown(struct dect_cluster *cl)
>> +{
>> +       tipc_detach(cl->tipc_id);
>> +}
>> +
>> +static void dect_ccp_rcv_cluster_msg(void *handle, u32 portref,
>> +                                    struct sk_buff **pskb,
>> +                                    const u8 *data, u32 size)
>> +{
>> +       struct sk_buff *skb = *pskb;
>> +       struct dect_cell_handle *ch = handle;
>> +       struct dect_ccp_msg_hdr *h;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*h)))
>> +               return;
>> +       h = (struct dect_ccp_msg_hdr *)skb->data;
>> +       __skb_pull(skb, sizeof(*h));
>> +
>> +       switch (h->primitive) {
>> +       case DECT_CCP_SET_MODE:
>> +               return dect_ccp_parse_set_mode(ch, skb);
>> +       case DECT_CCP_SCAN:
>> +               return dect_ccp_parse_scan(ch, skb);
>> +       case DECT_CCP_ENABLE:
>> +               return dect_ccp_parse_enable(ch, skb);
>> +       case DECT_CCP_PRELOAD:
>> +               return dect_ccp_parse_preload(ch, skb);
>> +       case DECT_CCP_PAGE_REQ:
>> +               return dect_ccp_parse_page_req(ch, skb);
>> +       case DECT_CCP_TBC_ESTABLISH_REQ:
>> +               return dect_ccp_parse_tbc_establish_req(ch, skb);
>> +       case DECT_CCP_TBC_ESTABLISH_RES:
>> +               return dect_ccp_parse_tbc_establish_res(ch, skb);
>> +       case DECT_CCP_TBC_DIS_REQ:
>> +               return dect_ccp_parse_tbc_dis_req(ch, skb);
>> +       case DECT_CCP_TBC_ENC_KEY_REQ:
>> +               return dect_ccp_parse_tbc_enc_key_req(ch, skb);
>> +       case DECT_CCP_TBC_ENC_EKS_REQ:
>> +               return dect_ccp_parse_tbc_enc_eks_req(ch, skb);
>> +       }
>> +}
>> +
>> +static void dect_ccp_cluster_disconnect(void *handle, u32 portref,
>> +                                       struct sk_buff **pskb,
>> +                                       const u8 *data, u32 size, int 
>> reason)
>> +{
>> +       pr_debug("Cluster disconnected\n");
>> +#if 0
>> +       struct dect_cell_handle *clh = handle;
>> +
>> +       clh->ops->unbind(clh);
>> +#endif
>> +}
>> +
>> +static void dect_ccp_subscr_rcv(void *handle, u32 portref,
>> +                               struct sk_buff **pskb,
>> +                               const u8 *data, u32 size)
>> +{
>> +       struct dect_cell_handle *ch = handle;
>> +       struct dect_cluster_handle *clh = ch->clh;
>> +       struct sk_buff *skb = *pskb;
>> +       struct tipc_event *ev;
>> +       struct tipc_name name;
>> +       int err;
>> +
>> +       if (!pskb_may_pull(skb, sizeof(*ev)))
>> +               return;
>> +       ev = (struct tipc_event *)skb->data;
>> +
>> +       if (ev->event != TIPC_PUBLISHED)
>> +               return;
>> +
>> +       /* Connect to cluster */
>> +       err = tipc_createport(clh->tipc_id, ch, TIPC_HIGH_IMPORTANCE,
>> +                             NULL, NULL, dect_ccp_cluster_disconnect,
>> +                             NULL, NULL, dect_ccp_rcv_cluster_msg, 
>> NULL,
>> +                             &clh->portref);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       name.type = DECT_CCP_TIPC_TYPE;
>> +       name.instance = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
>> +       err = tipc_send2name(clh->portref, &name, 0, 0, NULL);
>> +       if (err < 0)
>> +               goto err2;
>> +       return;
>> +
>> +err2:
>> +       tipc_deleteport(clh->portref);
>> +err1:
>> +       return;
>> +}
>> +
>> +/**
>> + * dect_ccp_cell_init - Initialize a cell CCP instance
>> + *
>> + * @cell:      DECT cell
>> + */
>> +static int dect_ccp_bind_cell(struct dect_cluster_handle *clh,
>> +                             struct dect_cell_handle *ch)
>> +{
>> +       struct tipc_subscr subscr;
>> +       struct iovec iov = { &subscr, sizeof(subscr) };
>> +       struct tipc_name tname;
>> +       int err;
>> +
>> +       err = tipc_attach(&clh->tipc_id, NULL, NULL);
>> +       if (err < 0)
>> +               goto err1;
>> +       ch->clh = clh;
>> +
>> +       /* Connect to topology service and subscribe to cluster port 
>> */
>> +       err = tipc_createport(clh->tipc_id, ch, 
>> TIPC_CRITICAL_IMPORTANCE,
>> +                             NULL, NULL, NULL, NULL, NULL,
>> +                             dect_ccp_subscr_rcv, NULL, 
>> &clh->tportref);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       subscr.seq.type = DECT_CCP_TIPC_TYPE;
>> +       subscr.seq.lower = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
>> +       subscr.seq.upper = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
>> +       subscr.timeout = TIPC_WAIT_FOREVER;
>> +       subscr.filter = TIPC_SUB_PORTS;
>> +       memset(&subscr.usr_handle, 0, sizeof(subscr.usr_handle));
>> +
>> +       tname.type = TIPC_TOP_SRV;
>> +       tname.instance = TIPC_TOP_SRV;
>> +
>> +       err = tipc_send2name(clh->tportref, &tname, 0, 1, &iov);
>> +       if (err < 0)
>> +               goto err3;
>> +       return 0;
>> +
>> +err3:
>> +       tipc_deleteport(clh->tportref);
>> +err2:
>> +       tipc_detach(clh->tipc_id);
>> +err1:
>> +       return err;
>> +
>> +}
>> +
>> +static void dect_ccp_unbind_cell(struct dect_cluster_handle *clh,
>> +                                struct dect_cell_handle *ch)
>> +{
>> +       tipc_detach(clh->tipc_id);
>> +}
>> +
>> +static void dect_ccp_send_bmc_page_ind(const struct 
>> dect_cluster_handle *clh,
>> +                                      struct sk_buff *skb)
>> +{
>> +}
>> +
>> +static const struct dect_ccf_ops dect_ccp_ccf_ops = {
>> +       .bind                   = dect_ccp_bind_cell,
>> +       .unbind                 = dect_ccp_unbind_cell,
>> +       .scan_report            = dect_ccp_send_scan_report,
>> +       .mac_info_ind           = dect_ccp_send_mac_info_ind,
>> +       .tbc_establish_ind      = dect_ccp_send_tbc_establish_ind,
>> +       .tbc_establish_cfm      = dect_ccp_send_tbc_establish_cfm,
>> +       .tbc_event_ind          = dect_ccp_send_tbc_event_ind,
>> +       .tbc_dis_ind            = dect_ccp_send_tbc_dis_ind,
>> +       .tbc_data_ind           = dect_ccp_send_tbc_data_ind,
>> +       .bmc_page_ind           = dect_ccp_send_bmc_page_ind,
>> +};
>> +
>> +struct dect_cluster_handle *dect_ccp_cell_init(struct dect_cell 
>> *cell, u8 clindex)
>> +{
>> +       struct dect_cluster_handle *clh;
>> +
>> +       clh = kzalloc(sizeof(*clh), GFP_KERNEL);
>> +       if (clh == NULL)
>> +               return ERR_PTR(-ENOMEM);
>> +       clh->index = clindex;
>> +       clh->ops = &dect_ccp_ccf_ops;
>> +       return clh;
>> +}
>> diff --git a/target/linux/generic/files/net/dect/core.c 
>> b/target/linux/generic/files/net/dect/core.c
>> new file mode 100644
>> index 0000000..80a7dd8
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/core.c
>> @@ -0,0 +1,183 @@
>> +/*
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/mutex.h>
>> +#include <linux/list.h>
>> +#include <linux/notifier.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +static DEFINE_MUTEX(dect_cfg_mutex);
>> +
>> +void dect_lock(void)
>> +{
>> +       mutex_lock(&dect_cfg_mutex);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_lock);
>> +
>> +void dect_unlock(void)
>> +{
>> +       mutex_unlock(&dect_cfg_mutex);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_unlock);
>> +
>> +/*
>> + * MAC layer timers
>> + */
>> +
>> +#if 1
>> +#define timer_debug(name, base, fmt, args...) \
>> +       pr_debug("%s: %s %u.%.2u.%.2u: " fmt, name, \
>> +                (base)->base == DECT_TIMER_TX ? "TX" : "RX", \
>> +                base->mfn, base->framenum, base->slot, ## args)
>> +#else
>> +#define timer_debug(base, fmt, args...)
>> +#endif
>> +
>> +void __dect_run_timers(const char *name, struct dect_timer_base 
>> *base)
>> +{
>> +       struct dect_timer *t;
>> +
>> +       while (!list_empty(&base->timers)) {
>> +               t = list_first_entry(&base->timers, struct dect_timer, 
>> list);
>> +
>> +               if (dect_mfn_after(t->mfn, base->mfn) ||
>> +                   (t->mfn == base->mfn && t->frame > base->framenum) 
>> ||
>> +                   (t->mfn == base->mfn && t->frame == base->framenum 
>> &&
>> +                    t->slot > base->slot))
>> +                       break;
>> +
>> +               timer_debug(name, base, "timer %p: %u.%u.%u\n",
>> +                           t, t->mfn, t->frame, t->slot);
>> +               list_del_init(&t->list);
>> +               t->cb.cb(t->obj, t->data);
>> +       }
>> +}
>> +EXPORT_SYMBOL_GPL(__dect_run_timers);
>> +
>> +/**
>> + * dect_timer_add - (re)schedule a timer
>> + *
>> + * Frame numbers are relative to the current time, slot positions are 
>> absolute.
>> + * A timer scheduled for (1, 2) will expire in slot 2 in the next 
>> frame.
>> + *
>> + * A frame number of zero will expire at the next occurence of the 
>> slot, which
>> + * can be within the same frame in case the slot is not already in 
>> the past, or
>> + * in the next frame in case it is.
>> + */
>> +void __dect_timer_add(const char *name, struct dect_timer_base *base,
>> +                     struct dect_timer *timer, u32 frame, u8 slot)
>> +{
>> +       struct dect_timer *t;
>> +       u32 mfn;
>> +
>> +       if (frame == 0 && slot < base->slot)
>> +               frame++;
>> +       frame += base->framenum;
>> +       mfn = dect_mfn_add(base->mfn, frame / 
>> DECT_FRAMES_PER_MULTIFRAME);
>> +       frame %= DECT_FRAMES_PER_MULTIFRAME;
>> +
>> +       timer_debug(name, base, "timer %p: schedule for %u.%u.%u\n",
>> +                   timer, mfn, frame, slot);
>> +       if (!list_empty(&timer->list))
>> +               list_del(&timer->list);
>> +       list_for_each_entry(t, &base->timers, list) {
>> +               if (dect_mfn_after(t->mfn, mfn) ||
>> +                   (t->mfn == mfn && t->frame > frame) ||
>> +                   (t->mfn == mfn && t->frame == frame && t->slot > 
>> slot))
>> +                       break;
>> +       }
>> +
>> +       timer->mfn   = mfn;
>> +       timer->frame = frame;
>> +       timer->slot  = slot;
>> +       list_add_tail(&timer->list, &t->list);
>> +}
>> +EXPORT_SYMBOL_GPL(__dect_timer_add);
>> +
>> +struct sk_buff *skb_append_frag(struct sk_buff *head, struct sk_buff 
>> *skb)
>> +{
>> +       struct sk_buff **pprev;
>> +
>> +       if (head == NULL)
>> +               return skb;
>> +
>> +       pprev = &skb_shinfo(head)->frag_list;
>> +       while (*pprev != NULL)
>> +               pprev = &(*pprev)->next;
>> +       *pprev = skb;
>> +
>> +       head->data_len += skb->len;
>> +       head->len += skb->len;
>> +       head->truesize += skb->truesize;
>> +       return head;
>> +}
>> +EXPORT_SYMBOL_GPL(skb_append_frag);
>> +
>> +unsigned int skb_queue_pull(struct sk_buff_head *list, unsigned int 
>> len)
>> +{
>> +       unsigned int pulled = 0;
>> +       unsigned long flags;
>> +       struct sk_buff *skb;
>> +
>> +       spin_lock_irqsave(&list->lock, flags);
>> +       while (len > pulled) {
>> +               skb = skb_peek(list);
>> +               if (skb == NULL)
>> +                       break;
>> +               if (skb->len <= len) {
>> +                       __skb_unlink(skb, list);
>> +                       pulled += skb->len;
>> +                       kfree_skb(skb);
>> +               } else {
>> +                       __skb_pull(skb, len);
>> +                       pulled += len;
>> +               }
>> +       }
>> +       spin_unlock_irqrestore(&list->lock, flags);
>> +       return pulled;
>> +}
>> +EXPORT_SYMBOL_GPL(skb_queue_pull);
>> +
>> +static int __init dect_module_init(void)
>> +{
>> +       int err;
>> +
>> +       err = dect_netlink_module_init();
>> +       if (err < 0)
>> +               goto err1;
>> +       err = dect_af_module_init();
>> +       if (err < 0)
>> +               goto err2;
>> +       return 0;
>> +
>> +err2:
>> +       dect_netlink_module_exit();
>> +err1:
>> +       return err;
>> +}
>> +
>> +static void __exit dect_module_exit(void)
>> +{
>> +       dect_af_module_exit();
>> +       dect_netlink_module_exit();
>> +}
>> +
>> +module_init(dect_module_init);
>> +module_exit(dect_module_exit);
>> +
>> +MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
>> +MODULE_DESCRIPTION("DECT protocol stack");
>> +MODULE_LICENSE("GPL");
>> diff --git a/target/linux/generic/files/net/dect/dect_netlink.c 
>> b/target/linux/generic/files/net/dect/dect_netlink.c
>> new file mode 100644
>> index 0000000..7ed631c
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dect_netlink.c
>> @@ -0,0 +1,150 @@
>> +/*
>> + * DECT netlink control interface
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/netlink.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect_netlink.h>
>> +#include <linux/dect.h>
>> +#include <linux/security.h>
>> +#include <net/netlink.h>
>> +#include <net/sock.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_csf.h>
>> +
>> +struct sock *dect_nlsk __read_mostly;
>> +EXPORT_SYMBOL_GPL(dect_nlsk);
>> +
>> +LIST_HEAD(dect_cluster_list);
>> +EXPORT_SYMBOL_GPL(dect_cluster_list);
>> +
>> +struct dect_cluster *dect_cluster_get_by_index(int index)
>> +{
>> +       struct dect_cluster *cl;
>> +
>> +       list_for_each_entry(cl, &dect_cluster_list, list) {
>> +               if (cl->index == index)
>> +                       return cl;
>> +       }
>> +       return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_cluster_get_by_index);
>> +
>> +static const struct dect_netlink_handler 
>> *dect_dispatch[DECT_NR_MSGTYPES];
>> +
>> +void dect_netlink_register_handlers(const struct dect_netlink_handler 
>> *handler,
>> +                                   unsigned int base, unsigned int n)
>> +{
>> +       unsigned int i;
>> +
>> +       dect_lock();
>> +       base -= DECT_MSG_BASE;
>> +       for (i = 0; i < n; i++)
>> +               dect_dispatch[base + i] = handler + i;
>> +       dect_unlock();
>> +}
>> +EXPORT_SYMBOL_GPL(dect_netlink_register_handlers);
>> +
>> +void dect_netlink_unregister_handlers(unsigned int base, unsigned int 
>> n)
>> +{
>> +       unsigned int i;
>> +
>> +       dect_lock();
>> +       base -= DECT_MSG_BASE;
>> +       for (i = 0; i < n; i++)
>> +               dect_dispatch[base + i] = NULL;
>> +       dect_unlock();
>> +}
>> +EXPORT_SYMBOL_GPL(dect_netlink_unregister_handlers);
>> +
>> +static int dect_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr 
>> *nlh)
>> +{
>> +       const struct dect_netlink_handler *link;
>> +       u16 type;
>> +       int err;
>> +
>> +       type = nlh->nlmsg_type;
>> +       if (type > DECT_MSG_MAX)
>> +               return -EINVAL;
>> +
>> +       link = dect_dispatch[type - DECT_MSG_BASE];
>> +       if (link == NULL) {
>> +#ifdef CONFIG_MODULES
>> +               dect_unlock();
>> +               switch (type) {
>> +               case DECT_NEW_TRANSCEIVER ... DECT_GET_CELL:
>> +                       request_module("dect_csf");
>> +                       break;
>> +               case DECT_NEW_CLUSTER ... DECT_LLME_MSG:
>> +                       request_module("dect_ccf");
>> +                       break;
>> +               }
>> +               dect_lock();
>> +
>> +               link = dect_dispatch[type - DECT_MSG_BASE];
>> +               if (link == NULL)
>> +#endif
>> +                       return -EOPNOTSUPP;
>> +       }
>> +
>> +       /* dump and get requests don't require privileges */
>> +       if (link->dump == NULL && !capable(CAP_NET_ADMIN))
>> +               return -EPERM;
>> +
>> +       if (nlh->nlmsg_flags & NLM_F_DUMP) {
>> +               struct netlink_dump_control c = {
>> +                       .dump = link->dump,
>> +                       .done = link->done,
>> +               };
>> +               if (link->dump == NULL)
>> +                       return -EOPNOTSUPP;
>> +               return netlink_dump_start(dect_nlsk, skb, nlh, &c);
>> +       } else {
>> +               struct nlattr *nla[link->maxtype + 1];
>> +
>> +               err = nlmsg_parse(nlh, sizeof(struct dectmsg), nla,
>> +                                 link->maxtype, link->policy);
>> +               if (err < 0)
>> +                       return err;
>> +               if (link->doit == NULL)
>> +                       return -EOPNOTSUPP;
>> +               return link->doit(skb, nlh, (const struct nlattr 
>> **)nla);
>> +       }
>> +}
>> +
>> +static void dect_netlink_rcv(struct sk_buff *skb)
>> +{
>> +       dect_lock();
>> +       netlink_rcv_skb(skb, dect_netlink_rcv_msg);
>> +       dect_unlock();
>> +}
>> +
>> +int __init dect_netlink_module_init(void)
>> +{
>> +       struct sock *sk;
>> +       struct netlink_kernel_cfg cfg = {
>> +               .input  = dect_netlink_rcv,
>> +               .groups = DECTNLGRP_MAX,
>> +       };
>> +       sk = netlink_kernel_create(&init_net, NETLINK_DECT, &cfg);
>> +       if (sk == NULL)
>> +               return -ENOMEM;
>> +       dect_nlsk = sk;
>> +       return 0;
>> +}
>> +
>> +void dect_netlink_module_exit(void)
>> +{
>> +       netlink_kernel_release(dect_nlsk);
>> +}
>> +
>> +MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DECT);
>> diff --git a/target/linux/generic/files/net/dect/dlc.c 
>> b/target/linux/generic/files/net/dect/dlc.c
>> new file mode 100644
>> index 0000000..63d2235
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc.c
>> @@ -0,0 +1,282 @@
>> +/*
>> + * DECT DLC Layer
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +
>> +#define mc_debug(mc, fmt, args...) \
>> +       pr_debug("MC (MCEI %u/%s): " fmt, \
>> +                (mc)->mcei, dect_mc_states[(mc)->state], ## args)
>> +
>> +static const char * const dect_mc_states[] = {
>> +       [DECT_MAC_CONN_CLOSED]          = "CLOSED",
>> +       [DECT_MAC_CONN_OPEN_PENDING]    = "OPEN_PENDING",
>> +       [DECT_MAC_CONN_OPEN]            = "OPEN",
>> +};
>> +
>> +static struct dect_mac_conn *
>> +dect_mac_conn_get_by_mcei(const struct dect_cluster *cl, u32 mcei)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       list_for_each_entry(mc, &cl->mac_connections, list) {
>> +               if (mc->mcei == mcei)
>> +                       return mc;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +struct dect_mac_conn *
>> +dect_mac_conn_get_by_mci(const struct dect_cluster *cl, const struct 
>> dect_mci *mci)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       list_for_each_entry(mc, &cl->mac_connections, list) {
>> +               if (!dect_ari_cmp(&mc->mci.ari, &mci->ari) &&
>> +                   !dect_pmid_cmp(&mc->mci.pmid, &mci->pmid) &&
>> +                   mc->mci.lcn == mci->lcn)
>> +                       return mc;
>> +       }
>> +       return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_mac_conn_get_by_mci);
>> +
>> +void dect_dlc_mac_conn_destroy(struct dect_mac_conn *mc)
>> +{
>> +       mc_debug(mc, "destroy\n");
>> +       list_del(&mc->list);
>> +       kfree(mc);
>> +}
>> +
>> +void dect_dlc_mac_conn_bind(struct dect_mac_conn *mc)
>> +{
>> +       mc_debug(mc, "bind use %u\n", mc->use);
>> +       mc->use++;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_dlc_mac_conn_bind);
>> +
>> +void dect_dlc_mac_conn_unbind(struct dect_mac_conn *mc)
>> +{
>> +       mc_debug(mc, "unbind use %u\n", mc->use);
>> +       if (--mc->use)
>> +               return;
>> +
>> +       if (mc->state == DECT_MAC_CONN_OPEN ||
>> +           mc->state == DECT_MAC_CONN_OPEN_PENDING)
>> +               dect_mac_dis_req(mc->cl, mc->mcei);
>> +
>> +       dect_dlc_mac_conn_destroy(mc);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_dlc_mac_conn_unbind);
>> +
>> +struct dect_mac_conn *dect_mac_conn_init(struct dect_cluster *cl,
>> +                                        const struct dect_mci *mci,
>> +                                        const struct dect_mbc_id *id)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
>> +       if (mc == NULL)
>> +               return NULL;
>> +
>> +       mc->cl    = cl;
>> +       mc->mcei  = id != NULL ? id->mcei : dect_mbc_alloc_mcei(cl);
>> +       memcpy(&mc->mci, mci, sizeof(mc->mci));
>> +       mc->state = DECT_MAC_CONN_CLOSED;
>> +       mc_debug(mc, "init\n");
>> +
>> +       list_add_tail(&mc->list, &cl->mac_connections);
>> +       return mc;
>> +}
>> +
>> +static void dect_mac_conn_state_change(struct dect_mac_conn *mc,
>> +                                      enum dect_mac_conn_states 
>> state)
>> +{
>> +       mc_debug(mc, "state change: %s (%u) -> %s (%u)\n",
>> +                dect_mc_states[mc->state], mc->state,
>> +                dect_mc_states[state], state);
>> +
>> +       mc->state = state;
>> +       dect_cplane_notify_state_change(mc);
>> +}
>> +
>> +int dect_dlc_mac_conn_establish(struct dect_mac_conn *mc)
>> +{
>> +       struct dect_mbc_id mid = {
>> +               .mcei           = mc->mcei,
>> +               .ari            = mc->mci.ari,
>> +               .pmid           = mc->mci.pmid,
>> +               .type           = DECT_MAC_CONN_BASIC,
>> +               .ecn            = mc->mci.lcn,
>> +       };
>> +       int err;
>> +
>> +       err = dect_mac_con_req(mc->cl, &mid);
>> +       if (err < 0)
>> +               return err;
>> +       dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN_PENDING);
>> +       return 0;
>> +}
>> +
>> +int dect_mac_con_cfm(struct dect_cluster *cl, u32 mcei,
>> +                    enum dect_mac_service_types service)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (WARN_ON(mc == NULL))
>> +               return -ENOENT;
>> +       mc->service = service;
>> +
>> +       mc_debug(mc, "MAC_CON-cfm\n");
>> +       dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN);
>> +       return 0;
>> +}
>> +
>> +int dect_mac_con_ind(struct dect_cluster *cl, const struct 
>> dect_mbc_id *id,
>> +                    enum dect_mac_service_types service)
>> +{
>> +       struct dect_mac_conn *mc;
>> +       struct dect_mci mci = {
>> +               .ari            = id->ari,
>> +               .pmid           = id->pmid,
>> +               .lcn            = id->ecn & DECT_LCN_MASK,
>> +       };
>> +
>> +       mc = dect_mac_conn_init(cl, &mci, id);
>> +       if (mc == NULL)
>> +               return -ENOMEM;
>> +       mc->service = service;
>> +
>> +       mc_debug(mc, "MAC_CON-ind\n");
>> +       dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN);
>> +       return 0;
>> +}
>> +
>> +int dect_dlc_mac_conn_enc_key_req(struct dect_mac_conn *mc, u64 ck)
>> +{
>> +       mc->ck = ck;
>> +       return dect_mac_enc_key_req(mc->cl, mc->mcei, ck);
>> +}
>> +
>> +int dect_dlc_mac_conn_enc_eks_req(struct dect_mac_conn *mc,
>> +                                 enum dect_cipher_states status)
>> +{
>> +       return dect_mac_enc_eks_req(mc->cl, mc->mcei, status);
>> +}
>> +
>> +/* Encryption status change confirmation from CCF */
>> +void dect_mac_enc_eks_cfm(struct dect_cluster *cl, u32 mcei,
>> +                         enum dect_cipher_states status)
>> +
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (WARN_ON(mc == NULL))
>> +               return;
>> +       //dect_cplane_mac_enc_eks_ind(mc, status);
>> +}
>> +
>> +/* Encryption status change indication from CCF */
>> +void dect_mac_enc_eks_ind(struct dect_cluster *cl, u32 mcei,
>> +                         enum dect_cipher_states status)
>> +
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (WARN_ON(mc == NULL))
>> +               return;
>> +       mc_debug(mc, "MAC_ENC_EKS-ind: status: %u\n", status);
>> +       dect_cplane_mac_enc_eks_ind(mc, status);
>> +}
>> +
>> +/* Disconnection indication from CCF */
>> +int dect_mac_dis_ind(struct dect_cluster *cl, u32 mcei,
>> +                    enum dect_release_reasons reason)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (WARN_ON(mc == NULL))
>> +               return -ENOENT;
>> +
>> +       mc_debug(mc, "MAC_DIS-ind: reason: %x\n", reason);
>> +       dect_mac_conn_state_change(mc, DECT_MAC_CONN_CLOSED);
>> +       /* If nothing is using the connection, release immediately */
>> +       if (mc->use == 0)
>> +               dect_dlc_mac_conn_destroy(mc);
>> +       else
>> +               dect_cplane_mac_dis_ind(mc, reason);
>> +       return 0;
>> +}
>> +
>> +/* Data indication from CCF */
>> +void dect_mac_co_data_ind(struct dect_cluster *cl, u32 mcei,
>> +                         enum dect_data_channels chan,
>> +                         struct sk_buff *skb)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (WARN_ON(mc == NULL))
>> +               goto err;
>> +
>> +       mc_debug(mc, "MAC_CO_DATA-ind: chan: %u len: %u\n", chan, 
>> skb->len);
>> +       switch (chan) {
>> +       case DECT_MC_C_S:
>> +       case DECT_MC_C_F:
>> +               return dect_cplane_rcv(mc, chan, skb);
>> +       case DECT_MC_I_N:
>> +       case DECT_MC_I_P:
>> +               return dect_uplane_rcv(mc, chan, skb);
>> +       default:
>> +               goto err;
>> +       }
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +/* Data-ready indication from CCF */
>> +struct sk_buff *dect_mac_co_dtr_ind(struct dect_cluster *cl, u32 
>> mcei,
>> +                                   enum dect_data_channels chan)
>> +{
>> +       struct dect_mac_conn *mc;
>> +
>> +       mc = dect_mac_conn_get_by_mcei(cl, mcei);
>> +       if (mc == NULL) {
>> +               if (net_ratelimit())
>> +                       pr_debug("DLC: DTR no connection\n");
>> +               return NULL;
>> +       }
>> +
>> +       mc_debug(mc, "MAC_CO_DTR-ind: chan: %u\n", chan);
>> +       switch (chan) {
>> +       case DECT_MC_C_S:
>> +       case DECT_MC_C_F:
>> +               return dect_cplane_dtr(mc, chan);
>> +       case DECT_MC_I_N:
>> +       case DECT_MC_I_P:
>> +               return dect_uplane_dtr(mc, chan);
>> +       default:
>> +               return NULL;
>> +       }
>> +}
>> diff --git a/target/linux/generic/files/net/dect/dlc_b_sap.c 
>> b/target/linux/generic/files/net/dect/dlc_b_sap.c
>> new file mode 100644
>> index 0000000..004db42
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc_b_sap.c
>> @@ -0,0 +1,277 @@
>> +/*
>> + * DECT DLC B SAP sockets - DLC C-plane broadcast service access
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/net.h>
>> +#include <linux/socket.h>
>> +#include <linux/dect.h>
>> +#include <net/sock.h>
>> +#include <net/dect/dect.h>
>> +
>> +static DEFINE_SPINLOCK(dect_bsap_lock);
>> +static HLIST_HEAD(dect_bsap_sockets);
>> +
>> +struct dect_bsap {
>> +       struct sock             sk;
>> +};
>> +
>> +static inline struct dect_bsap *dect_bsap(struct sock *sk)
>> +{
>> +       return (struct dect_bsap *)sk;
>> +}
>> +
>> +void dect_bsap_rcv(const struct dect_cluster *cl, struct sk_buff 
>> *skb)
>> +{
>> +       struct sk_buff *skb2;
>> +       struct sock *sk, *prev = NULL;
>> +
>> +       spin_lock(&dect_bsap_lock);
>> +       sk_for_each(sk, &dect_bsap_sockets) {
>> +               if (sk->sk_bound_dev_if &&
>> +                   sk->sk_bound_dev_if != cl->index)
>> +                       continue;
>> +
>> +               skb2 = skb_clone(skb, GFP_ATOMIC);
>> +               if (skb2 == NULL) {
>> +                       sk->sk_err = -ENOMEM;
>> +                       sk->sk_error_report(sk);
>> +                       break;
>> +               }
>> +
>> +               if (prev != NULL) {
>> +                       if (dect_sock_queue_rcv_skb(prev, skb2) < 0)
>> +                               kfree_skb(skb2);
>> +               }
>> +               prev = sk;
>> +       }
>> +
>> +       if (prev == NULL || dect_sock_queue_rcv_skb(prev, skb) < 0)
>> +               kfree_skb(skb);
>> +
>> +       spin_unlock(&dect_bsap_lock);
>> +}
>> +
>> +static void dect_bsap_close(struct sock *sk, long timeout)
>> +{
>> +       sk_common_release(sk);
>> +}
>> +
>> +static int dect_bsap_bind(struct sock *sk, struct sockaddr *uaddr, 
>> int len)
>> +{
>> +       const struct sockaddr_dect *addr = (struct sockaddr_dect 
>> *)uaddr;
>> +       int err;
>> +
>> +       if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
>> +               return -EINVAL;
>> +
>> +       if (addr->dect_index != 0 &&
>> +           !dect_cluster_get_by_index(addr->dect_index))
>> +               return -ENODEV;
>> +
>> +       lock_sock(sk);
>> +       err = -EINVAL;
>> +       if (!sk_unhashed(sk))
>> +               goto out;
>> +
>> +       sk->sk_bound_dev_if = addr->dect_index;
>> +
>> +       spin_lock_bh(&dect_bsap_lock);
>> +       sk_add_node(sk, &dect_bsap_sockets);
>> +       spin_unlock_bh(&dect_bsap_lock);
>> +
>> +       err = 0;
>> +out:
>> +       release_sock(sk);
>> +       return err;
>> +}
>> +
>> +static void dect_bsap_unhash(struct sock *sk)
>> +{
>> +       if (sk_hashed(sk)) {
>> +               spin_lock_bh(&dect_bsap_lock);
>> +               sk_del_node_init(sk);
>> +               spin_unlock_bh(&dect_bsap_lock);
>> +       }
>> +}
>> +
>> +static int dect_bsap_getname(struct sock *sk, struct sockaddr *uaddr, 
>> int *len,
>> +                            int peer)
>> +{
>> +       struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
>> +
>> +       if (peer)
>> +               return -EOPNOTSUPP;
>> +
>> +       addr->dect_family = AF_DECT;
>> +       addr->dect_index  = sk->sk_bound_dev_if;
>> +       *len = sizeof(*addr);
>> +       return 0;
>> +}
>> +
>> +static int dect_bsap_recvmsg(struct kiocb *iocb, struct sock *sk,
>> +                            struct msghdr *msg, size_t len,
>> +                            int noblock, int flags, int *addrlen)
>> +{
>> +       struct sockaddr_dect *addr;
>> +       struct dect_bsap_auxdata aux;
>> +       struct sk_buff *skb;
>> +       size_t copied = 0;
>> +       int err;
>> +
>> +       if (flags & MSG_OOB)
>> +               return -EOPNOTSUPP;
>> +
>> +       skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +       if (skb == NULL)
>> +               goto out;
>> +
>> +       //msg->msg_flags |= DECT_LB_CB(skb)->expedited ? MSG_OOB : 0;
>> +
>> +       copied = skb->len;
>> +       if (len < copied) {
>> +               msg->msg_flags |= MSG_TRUNC;
>> +               copied = len;
>> +       }
>> +
>> +       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
>> +       if (err < 0)
>> +               goto out_free;
>> +
>> +       if (msg->msg_name != NULL) {
>> +               addr = (struct sockaddr_dect *)msg->msg_name;
>> +               addr->dect_family = AF_DECT;
>> +               addr->dect_index = DECT_SK_CB(skb)->index;
>> +               msg->msg_namelen = sizeof(*addr);
>> +       }
>> +
>> +       sock_recv_timestamp(msg, sk, skb);
>> +
>> +       aux.long_page = DECT_BMC_CB(skb)->long_page;
>> +       put_cmsg(msg, SOL_DECT, DECT_BSAP_AUXDATA, sizeof(aux), &aux);
>> +
>> +       if (flags & MSG_TRUNC)
>> +               copied = skb->len;
>> +out_free:
>> +       skb_free_datagram(sk, skb);
>> +out:
>> +       return err ? : copied;
>> +}
>> +
>> +static int dect_bsap_sendmsg(struct kiocb *kiocb, struct sock *sk,
>> +                            struct msghdr *msg, size_t len)
>> +{
>> +       const struct sockaddr_dect *addr = msg->msg_name;
>> +       bool expedited = msg->msg_flags & MSG_OOB;
>> +       struct dect_cluster *cl;
>> +       struct sk_buff *skb;
>> +       struct cmsghdr *cmsg;
>> +       struct dect_bsap_auxdata *aux;
>> +       bool long_page = false;
>> +       int index;
>> +       int err;
>> +
>> +       if (msg->msg_namelen) {
>> +               if (addr->dect_family != AF_DECT)
>> +                       return -EINVAL;
>> +               index = addr->dect_index;
>> +       } else
>> +               index = sk->sk_bound_dev_if;
>> +
>> +       /* Transmission is always in direction FP -> PP */
>> +       cl = dect_cluster_get_by_index(index);
>> +       if (cl == NULL)
>> +               return -ENODEV;
>> +       if (cl->mode != DECT_MODE_FP)
>> +               return -EOPNOTSUPP;
>> +
>> +       for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = 
>> CMSG_NXTHDR(msg, cmsg)) {
>> +               if (!CMSG_OK(msg, cmsg))
>> +                       return -EINVAL;
>> +               if (cmsg->cmsg_level != SOL_DECT)
>> +                       continue;
>> +
>> +               switch (cmsg->cmsg_type) {
>> +               case DECT_BSAP_AUXDATA:
>> +                       if (cmsg->cmsg_len != CMSG_LEN(sizeof(*aux)))
>> +                               return -EINVAL;
>> +                       aux = (struct dect_bsap_auxdata 
>> *)CMSG_DATA(cmsg);
>> +                       long_page = aux->long_page;
>> +                       break;
>> +               default:
>> +                       return -EINVAL;
>> +               }
>> +       }
>> +
>> +       /* Valid frame sizes are 3 bytes (short frame), 5 bytes (long 
>> frame)
>> +        * or multiples of 5 bytes up to 30 bytes (extended frame). 
>> Extended
>> +        * frames can not use expedited operation. */
>> +       if (len == DECT_LB_SHORT_FRAME_SIZE) {
>> +               if (long_page)
>> +                       return -EINVAL;
>> +       } else if (len % DECT_LB_LONG_FRAME_SIZE == 0) {
>> +               if (len == 0 || len > DECT_LB_EXTENDED_FRAME_SIZE_MAX)
>> +                       return -EMSGSIZE;
>> +               if (len > DECT_LB_LONG_FRAME_SIZE && !long_page)
>> +                       return -EINVAL;
>> +               if (expedited)
>> +                       return -EOPNOTSUPP;
>> +       } else
>> +               return -EINVAL;
>> +
>> +       skb = sock_alloc_send_skb(sk, len, msg->msg_flags & 
>> MSG_DONTWAIT, &err);
>> +       if (skb == NULL)
>> +               goto err1;
>> +       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
>> +       if (err < 0)
>> +               goto err2;
>> +       DECT_BMC_CB(skb)->long_page = long_page;
>> +       DECT_BMC_CB(skb)->fast_page = expedited;
>> +       dect_bmc_mac_page_req(cl, skb);
>> +       return len;
>> +
>> +err2:
>> +       kfree_skb(skb);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static struct dect_proto dect_bsap_proto __read_mostly = {
>> +       .type           = SOCK_DGRAM,
>> +       .protocol       = DECT_B_SAP,
>> +       .capability     = CAP_NET_RAW,
>> +       .ops            = &dect_dgram_ops,
>> +       .proto.name     = "DECT_B_SAP",
>> +       .proto.owner    = THIS_MODULE,
>> +       .proto.obj_size = sizeof(struct dect_bsap),
>> +       .proto.close    = dect_bsap_close,
>> +       .proto.bind     = dect_bsap_bind,
>> +       .proto.unhash   = dect_bsap_unhash,
>> +       .proto.recvmsg  = dect_bsap_recvmsg,
>> +       .proto.sendmsg  = dect_bsap_sendmsg,
>> +       .getname        = dect_bsap_getname,
>> +};
>> +
>> +int __init dect_bsap_module_init(void)
>> +{
>> +       return dect_proto_register(&dect_bsap_proto);
>> +}
>> +
>> +void dect_bsap_module_exit(void)
>> +{
>> +       dect_proto_unregister(&dect_bsap_proto);
>> +}
>> +
>> +MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
>> +MODULE_DESCRIPTION("DECT DLC B SAP sockets");
>> +MODULE_LICENSE("GPL");
>> +
>> +MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_B_SAP);
>> diff --git a/target/linux/generic/files/net/dect/dlc_cplane.c 
>> b/target/linux/generic/files/net/dect/dlc_cplane.c
>> new file mode 100644
>> index 0000000..9365b9d
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc_cplane.c
>> @@ -0,0 +1,981 @@
>> +/*
>> + * DECT DLC C-plane
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +
>> +void dect_mac_page_ind(struct dect_cluster *cl, struct sk_buff *skb)
>> +{
>> +       dect_bsap_rcv(cl, skb);
>> +}
>> +
>> +static void dect_fa_parse_len(struct dect_fa_len *len, const struct 
>> sk_buff *skb)
>> +{
>> +       u8 l;
>> +
>> +       l = skb->data[DECT_FA_LI_OFF];
>> +       len->len  = (l & DECT_FA_LI_LENGTH_MASK) >> 
>> DECT_FA_LI_LENGTH_SHIFT;
>> +       len->more = (l & DECT_FA_LI_M_FLAG);
>> +}
>> +
>> +/*
>> + * LAPC entity
>> + */
>> +
>> +#define lapc_debug(lapc, fmt, args...) \
>> +       pr_debug("LAPC (MCEI: %u LLN: %u): " fmt, \
>> +                (lapc)->lc->mc->mcei, (lapc)->dli.lln, ## args)
>> +
>> +static inline u8 lapc_seq_add(const struct dect_lapc *lapc, u8 s1, u8 
>> s2)
>> +{
>> +       return (s1 + s2) & (lapc->mod - 1);
>> +}
>> +
>> +static inline bool dect_fa_seq_before(const struct dect_lapc *lapc, 
>> u8 s1, u8 s2)
>> +{
>> +       if (lapc->window == 1)
>> +               return s1 != s2;
>> +       else
>> +               return (s8)((s2 << 5) - (s1 << 5)) > 0;
>> +}
>> +
>> +static inline bool dect_fa_seq_after(const struct dect_lapc *lapc, u8 
>> s1, u8 s2)
>> +{
>> +       return dect_fa_seq_before(lapc, s2, s1);
>> +}
>> +
>> +static void dect_lapc_transmit_skb(struct dect_lapc *lapc)
>> +{
>> +       struct sk_buff *skb = skb_peek(&lapc->retransmit_queue);
>> +       struct dect_fa_hdr *fh;
>> +
>> +       skb = skb_clone(skb, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return;
>> +
>> +       fh = (struct dect_fa_hdr *)skb->data;
>> +       lapc_debug(lapc, "queue I-frame: v_a: %u v_r: %u v_s: %u "
>> +                  "len: %u addr: %02x ctrl: %02x\n", lapc->v_a, 
>> lapc->v_r,
>> +                  lapc->v_s, skb->len, fh->addr, fh->ctrl);
>> +       skb_queue_tail(&lapc->lc->txq, skb);
>> +}
>> +
>> +static void dect_lapc_error_report(struct dect_lapc *lapc, int err)
>> +{
>> +       struct sock *sk = lapc->sk;
>> +
>> +       lapc_debug(lapc, "socket error: %d\n", err);
>> +       sk->sk_err = err;
>> +       sk->sk_error_report(sk);
>> +}
>> +
>> +static void dect_lapc_state_change(struct dect_lapc *lapc, int state)
>> +{
>> +       struct sock *sk = lapc->sk;
>> +
>> +       lapc_debug(lapc, "socket state change: %d\n", state);
>> +       sk->sk_state = state;
>> +       sk->sk_state_change(sk);
>> +}
>> +
>> +/**
>> + * dect_lapc_timeout - retransmission timer
>> + *
>> + * Handle missing acknowledgements:
>> + *
>> + * - If not already in timer recovery condition, enter it
>> + * - otherwise add one to retransmission count
>> + *
>> + * If the retransmission count is below the maximum, restart the 
>> timer and
>> + * send an "appropriate" S-frame acknowledgement or retransmit the 
>> last
>> + * I-frame, in both cases with the poll bit set.
>> + */
>> +static void dect_lapc_timeout(unsigned long data)
>> +{
>> +       struct dect_lapc *lapc = (struct dect_lapc *)data;
>> +
>> +       lapc_debug(lapc, "retransmission timer: cnt: %u\n", 
>> lapc->retransmit_cnt);
>> +       if (lapc->retransmit_cnt++ < DECT_LAPC_RETRANSMIT_MAX) {
>> +               dect_lapc_transmit_skb(lapc);
>> +               mod_timer(&lapc->timer, jiffies + 
>> DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT);
>> +       } else
>> +               dect_lapc_error_report(lapc, ETIMEDOUT);
>> +}
>> +
>> +static bool dect_lapc_done(const struct dect_lapc *lapc)
>> +{
>> +       return skb_queue_empty(&lapc->sk->sk_write_queue) &&
>> +              skb_queue_empty(&lapc->retransmit_queue);
>> +}
>> +
>> +void dect_lapc_destroy(struct dect_lapc *lapc)
>> +{
>> +       lapc_debug(lapc, "destroy\n");
>> +
>> +       del_timer_sync(&lapc->timer);
>> +       skb_queue_purge(&lapc->retransmit_queue);
>> +       dect_lc_unbind(lapc->lc, lapc);
>> +       sock_put(lapc->sk);
>> +       kfree(lapc);
>> +}
>> +
>> +static void dect_lapc_reset(struct dect_lapc *lapc)
>> +{
>> +       lapc->nlf = true;
>> +       lapc->v_s = 0;
>> +       lapc->v_a = 0;
>> +       lapc->v_r = 0;
>> +}
>> +
>> +/**
>> + * dect_lapc_init - initialize a new LAPC entity
>> + */
>> +struct dect_lapc *dect_lapc_init(struct sock *sk, const struct 
>> dect_dli *dli,
>> +                                enum dect_sapis sapi, struct dect_lc 
>> *lc,
>> +                                gfp_t gfp)
>> +{
>> +       struct dect_lapc *lapc;
>> +
>> +       lapc = kzalloc(sizeof(*lapc), gfp);
>> +       if (lapc == NULL)
>> +               return NULL;
>> +
>> +       lapc->sk = sk;
>> +       sock_hold(sk);
>> +
>> +       memcpy(&lapc->dli, dli, sizeof(lapc->dli));
>> +       lapc->sapi = sapi;
>> +       lapc->state = DECT_LAPC_ULI;
>> +       skb_queue_head_init(&lapc->retransmit_queue);
>> +
>> +       lapc->lc = lc;
>> +       setup_timer(&lapc->timer, dect_lapc_timeout, (unsigned 
>> long)lapc);
>> +       lapc->cmd = (lc->mc->cl->mode == DECT_MODE_FP) ? true : false;
>> +
>> +       switch (lapc->dli.lln) {
>> +       case DECT_LLN_CLASS_U:
>> +               break;
>> +       case DECT_LLN_CLASS_A:
>> +               lapc->window = DECT_LAPC_CLASS_A_WINDOW;
>> +               lapc->mod = DECT_LAPC_CLASS_A_MOD;
>> +               break;
>> +       default:
>> +               lapc->window = DECT_LAPC_CLASS_B_INITIAL_WINDOW;
>> +               lapc->mod = DECT_LAPC_CLASS_B_MOD;
>> +               break;
>> +       }
>> +
>> +       dect_lapc_reset(lapc);
>> +
>> +       lapc_debug(lapc, "init\n");
>> +       return lapc;
>> +}
>> +
>> +#define DECT_FA_FRAME_RESERVE  16
>> +#define DECT_FA_FRAME_SPACE    16
>> +
>> +static struct sk_buff *dect_lapc_alloc_skb(struct dect_lapc *lapc)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = alloc_skb(DECT_FA_FRAME_SPACE + DECT_FA_FRAME_RESERVE, 
>> GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return NULL;
>> +       skb_reset_mac_header(skb);
>> +       skb_reserve(skb, DECT_FA_FRAME_RESERVE);
>> +       skb_reserve(skb, DECT_FA_HDR_SIZE);
>> +       skb_reset_network_header(skb);
>> +       return skb;
>> +}
>> +
>> +static struct dect_fa_hdr *dect_prepare_fa_frame(const struct 
>> dect_lapc *lapc,
>> +                                                bool command,
>> +                                                struct sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh;
>> +       u8 ilen = skb->len;
>> +
>> +       fh = (struct dect_fa_hdr *)skb_push(skb, DECT_FA_HDR_SIZE);
>> +       fh->addr  = lapc->dli.lln << DECT_FA_ADDR_LLN_SHIFT;
>> +       fh->addr |= lapc->sapi << DECT_FA_ADDR_SAPI_SHIFT;
>> +       fh->addr |= DECT_FA_ADDR_RES_BIT;
>> +       fh->addr |= (command ? lapc->cmd : !lapc->cmd) ? 
>> DECT_FA_ADDR_CR_FLAG : 0;
>> +       fh->addr |= lapc->nlf ? DECT_FA_ADDR_NLF_FLAG : 0;
>> +       fh->ctrl  = 0;
>> +       fh->li    = ilen << DECT_FA_LI_LENGTH_SHIFT;
>> +       fh->li   |= DECT_FA_LI_EXT_FLAG;
>> +       return fh;
>> +}
>> +
>> +static bool dect_lapc_send_iframe(struct dect_lapc *lapc, bool pf)
>> +{
>> +       struct dect_fa_hdr *fh;
>> +       struct sk_buff *skb;
>> +
>> +       /* Window size full? */
>> +       lapc_debug(lapc, "send I-frame: v_a: %u window: %u v_s: %u\n",
>> +                  lapc->v_a, lapc->window, lapc->v_s);
>> +       if (lapc_seq_add(lapc, lapc->v_a, lapc->window) == lapc->v_s)
>> +               return false;
>> +
>> +       /* Prepare a new I-frame */
>> +       skb = skb_dequeue(&lapc->sk->sk_write_queue);
>> +       if (skb == NULL)
>> +               return false;
>> +       fh = dect_prepare_fa_frame(lapc, true, skb);
>> +       fh->ctrl |= DECT_FA_CTRL_I_FMT_ID;
>> +       fh->ctrl |= lapc->v_r << DECT_FA_CTRL_I_NR_SHIFT;
>> +       fh->ctrl |= lapc->v_s << DECT_FA_CTRL_I_NS_SHIFT;
>> +       fh->ctrl |= pf ? DECT_FA_CTRL_I_P_FLAG : 0;
>> +
>> +       /* Append to retransmission queue and (re)start retransmission 
>> timer */
>> +       skb_queue_tail(&lapc->retransmit_queue, skb);
>> +       if (!timer_pending(&lapc->timer))
>> +               mod_timer(&lapc->timer, jiffies + 
>> DECT_LAPC_RETRANSMISSION_TIMEOUT);
>> +
>> +       lapc->v_s = lapc_seq_add(lapc, lapc->v_s, 1);
>> +
>> +       dect_lapc_transmit_skb(lapc);
>> +       return true;
>> +}
>> +
>> +/*
>> + * Send a S-frame with the specified command. The command/response 
>> bit setting
>> + * depends on the role of the LAPC, a PP uses 0 for commands and 1 
>> for responses,
>> + * a FT 1 for commands and 0 for responses.
>> + */
>> +static bool dect_lapc_send_sframe(struct dect_lapc *lapc, u8 cr,
>> +                                 bool command, bool pf)
>> +{
>> +       struct dect_fa_hdr *fh;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_lapc_alloc_skb(lapc);
>> +       if (skb == NULL)
>> +               return false;
>> +
>> +       fh = dect_prepare_fa_frame(lapc, command, skb);
>> +       fh->ctrl |= DECT_FA_CTRL_S_FMT_ID;
>> +       fh->ctrl |= lapc->v_r << DECT_FA_CTRL_S_NR_SHIFT;
>> +       fh->ctrl |= cr;
>> +       fh->ctrl |= pf ? DECT_FA_CTRL_S_PF_FLAG : 0;
>> +
>> +       lapc_debug(lapc, "queue S-frame: v_r: %u len: %u addr: %02x 
>> ctrl: %02x\n",
>> +                  lapc->v_r, skb->len, fh->addr, fh->ctrl);
>> +       skb_queue_tail(&lapc->lc->txq, skb);
>> +
>> +       lapc->nlf = false;
>> +       return true;
>> +}
>> +
>> +/*
>> + * Send an acknowledgement frame. Class B entities use RNR responses 
>> to indicate
>> + * their status while busy. Otherwise an I-frame is used when data is 
>> available
>> + * and a RR response frame otherwise.
>> + */
>> +static void dect_lapc_send_ack(struct dect_lapc *lapc, bool pf)
>> +{
>> +       lapc_debug(lapc, "send ACK: I-frame present: %u\n",
>> +                  skb_peek(&lapc->sk->sk_write_queue) ? 1 : 0);
>> +       if (lapc->dli.lln != DECT_LLN_CLASS_A && lapc->busy)
>> +               dect_lapc_send_sframe(lapc, DECT_FA_CTRL_S_CR_RNR, 
>> false, false);
>> +       else if (!lapc->peer_busy && 
>> skb_peek(&lapc->sk->sk_write_queue))
>> +               dect_lapc_send_iframe(lapc, pf);
>> +       else
>> +               dect_lapc_send_sframe(lapc, DECT_FA_CTRL_S_CR_RR, 
>> false, pf);
>> +}
>> +
>> +static void dect_lapc_queue_data(struct dect_lapc *lapc, struct 
>> sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
>> +
>> +       skb_pull(skb, DECT_FA_HDR_SIZE);
>> +       if (skb->len == 0) {
>> +               kfree_skb(skb);
>> +               return;
>> +       }
>> +       lapc_debug(lapc, "reassemble message: segment len: %u more: 
>> %u\n",
>> +                  skb->len, (fh->li & DECT_FA_LI_M_FLAG) ? 1 : 0);
>> +
>> +       lapc->rcv_head = skb_append_frag(lapc->rcv_head, skb);
>> +       if (!(fh->li & DECT_FA_LI_M_FLAG)) {
>> +               skb = lapc->rcv_head;
>> +               lapc->rcv_head = NULL;
>> +               lapc_debug(lapc, "reassembled message: len: %u\n", 
>> skb->len);
>> +               sock_queue_rcv_skb(lapc->sk, skb);
>> +       }
>> +}
>> +
>> +static bool dect_lapc_update_ack(struct dect_lapc *lapc, u8 seq)
>> +{
>> +       u8 v_a = lapc->v_a;
>> +
>> +       lapc_debug(lapc, "update ACK: v_a: %u v_s: %u seq: %u\n",
>> +                  lapc->v_a, lapc->v_s, seq);
>> +#if 0
>> +       lapc_debug(lapc, "seq %u after v_a %u: %u\n", seq, lapc->v_a,
>> +                  dect_fa_seq_after(lapc, seq, lapc->v_a));
>> +       lapc_debug(lapc, "v_s %u !after seq %u: %u\n", lapc->v_s, seq,
>> +                  !dect_fa_seq_after(lapc, lapc->v_s, seq));
>> +#endif
>> +
>> +       /* If all outstanding I-frames have been acknowledged, stop
>> +        * retransmission timer, otherwise reset it.
>> +        */
>> +       if (dect_fa_seq_after(lapc, seq, lapc->v_a) &&
>> +           !dect_fa_seq_after(lapc, lapc->v_s, seq)) {
>> +               lapc->v_a = seq;
>> +               if (lapc->v_a == lapc->v_s) {
>> +                       del_timer_sync(&lapc->timer);
>> +                       lapc->retransmit_cnt = 0;
>> +               } else
>> +                       mod_timer(&lapc->timer, jiffies + 
>> DECT_LAPC_RETRANSMISSION_TIMEOUT);
>> +       } else if (seq != lapc->v_a)
>> +               return false;
>> +
>> +       /* Purge acknowledged frames from transmit queue */
>> +       while (v_a != lapc->v_a) {
>> +               lapc_debug(lapc, "purge retransmit queue: seq: %u\n", 
>> v_a);
>> +               kfree_skb(skb_dequeue(&lapc->retransmit_queue));
>> +               v_a = lapc_seq_add(lapc, v_a, 1);
>> +       }
>> +
>> +       if (lapc->sk->sk_state == DECT_SK_RELEASE_PENDING &&
>> +           dect_lapc_done(lapc)) {
>> +               dect_lapc_state_change(lapc, DECT_SK_RELEASED);
>> +               dect_lapc_destroy(lapc);
>> +               return false;
>> +       }
>> +
>> +       return true;
>> +}
>> +
>> +/*
>> + * Receive a Class A or Class B I-frame. Frames with valid sequence 
>> numbers
>> + * are acknowledged and queued for segment reassembly. Invalid 
>> sequence
>> + * numbers cause an ACK with the expected sequence number to be sent.
>> + *
>> + * Class B entities need to indicate their receiver busy status when 
>> busy or
>> + * when explicitly polled.
>> + */
>> +static void dect_lapc_rcv_iframe(struct dect_lapc *lapc, struct 
>> sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
>> +       bool poll = false;
>> +       u8 n_s, n_r, res;
>> +
>> +       if (lapc->dli.lln == DECT_LLN_CLASS_U) {
>> +               kfree_skb(skb);
>> +               return;
>> +       }
>> +
>> +       if (fh->addr & DECT_FA_ADDR_NLF_FLAG)
>> +               dect_lapc_reset(lapc);
>> +
>> +       n_r = (fh->ctrl & DECT_FA_CTRL_I_NR_MASK) >> 
>> DECT_FA_CTRL_I_NR_SHIFT;
>> +       n_s = (fh->ctrl & DECT_FA_CTRL_I_NS_MASK) >> 
>> DECT_FA_CTRL_I_NS_SHIFT;
>> +       if (lapc->dli.lln != DECT_LLN_CLASS_A)
>> +               poll = fh->ctrl & DECT_FA_CTRL_I_P_FLAG;
>> +
>> +       lapc_debug(lapc, "receive I-frame: n_r: %u n_s: %u poll: 
>> %u\n",
>> +                  n_r, n_s, poll);
>> +       dect_lapc_update_ack(lapc, n_r);
>> +
>> +       /* While in receiver busy condition, all I-frames are dropped 
>> after
>> +        * updating the acknowledgement number. In Class B mode 
>> receiver status
>> +        * queries are still answered.
>> +        */
>> +       if (lapc->busy) {
>> +               kfree_skb(skb);
>> +               if (poll)
>> +                       goto poll;
>> +               return;
>> +       }
>> +
>> +       /* When the frame contains an invalid sequence number, send an
>> +        * immediate ACK. */
>> +       if (n_s != lapc->v_r) {
>> +               lapc_debug(lapc, "invalid sequence number %u %u\n", 
>> n_s, lapc->v_r);
>> +               kfree_skb(skb);
>> +               goto ack;
>> +       }
>> +
>> +       lapc->v_r = lapc_seq_add(lapc, lapc->v_r, 1);
>> +       dect_lapc_queue_data(lapc, skb);
>> +       if (poll)
>> +               goto poll;
>> +ack:
>> +       return dect_lapc_send_ack(lapc, poll);
>> +
>> +poll:
>> +       res = lapc->busy ? DECT_FA_CTRL_S_CR_RNR : 
>> DECT_FA_CTRL_S_CR_RR;
>> +       dect_lapc_send_sframe(lapc, res, false, true);
>> +}
>> +
>> +static void dect_lapc_rcv_sframe(struct dect_lapc *lapc, struct 
>> sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
>> +       bool pf;
>> +       u8 n_r;
>> +
>> +       n_r = (fh->ctrl & DECT_FA_CTRL_S_NR_MASK) >> 
>> DECT_FA_CTRL_S_NR_SHIFT;
>> +       pf  = (fh->ctrl & DECT_FA_CTRL_S_PF_FLAG);
>> +       lapc_debug(lapc, "receive S-frame: n_r: %u pf: %u\n", n_r, 
>> pf);
>> +
>> +       switch (fh->ctrl & DECT_FA_CTRL_S_CR_MASK) {
>> +       case DECT_FA_CTRL_S_CR_RR:
>> +               if (!dect_lapc_update_ack(lapc, n_r))
>> +                       goto err;
>> +
>> +               if (lapc->lc->elapc == lapc) {
>> +                       /* Connection establishment completed */
>> +                       lapc_debug(lapc, "established\n");
>> +                       lapc->lc->elapc = NULL;
>> +                       del_timer_sync(&lapc->timer);
>> +                       dect_lapc_state_change(lapc, 
>> DECT_SK_ESTABLISHED);
>> +               }
>> +
>> +               dect_lapc_send_iframe(lapc, pf);
>> +               break;
>> +       case DECT_FA_CTRL_S_CR_RNR:
>> +               /*
>> +                * Note peer receiver busy condition. If it was a RNR 
>> command
>> +                * with the P bit set to 1, send a RR response with 
>> the F bit
>> +                * set to 1. If it was a RNR response with the F bit 
>> set to 1,
>> +                * clear timer recovery condition and update V(S).
>> +                */
>> +               lapc->peer_busy = true;
>> +
>> +               if (fh->addr & DECT_FA_ADDR_CR_FLAG && pf)
>> +                       dect_lapc_send_sframe(lapc, 
>> DECT_FA_CTRL_S_CR_RR, true, true);
>> +               else if (!(fh->addr & DECT_FA_ADDR_CR_FLAG) && pf) {
>> +                       del_timer_sync(&lapc->timer);
>> +                       lapc->v_s = n_r;
>> +               }
>> +
>> +               dect_lapc_update_ack(lapc, n_r);
>> +               break;
>> +       case DECT_FA_CTRL_S_CR_REJ:
>> +               lapc->peer_busy = false;
>> +               lapc->v_s = n_r;
>> +               lapc->v_a = n_r;
>> +               del_timer_sync(&lapc->timer);
>> +               break;
>> +       default:
>> +               goto err;
>> +       }
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_lapc_rcv_uframe(struct dect_lapc *lapc, struct 
>> sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
>> +       u8 pf, cr;
>> +
>> +       pf = (fh->ctrl & DECT_FA_CTRL_U_PF_FLAG);
>> +       cr = (fh->ctrl & DECT_FA_CTRL_U_U1_MASK) |
>> +            (fh->ctrl & DECT_FA_CTRL_U_CR_MASK);
>> +
>> +       /* unnumbered information is only valid in class U mode */
>> +       if (cr == DECT_FA_CTRL_U_CR_UI) {
>> +               if (lapc->dli.lln != DECT_LLN_CLASS_U)
>> +                       goto err;
>> +               lapc_debug(lapc, "queue UI message: len: %u\n", 
>> skb->len);
>> +               sock_queue_rcv_skb(lapc->sk, skb);
>> +               return;
>> +       }
>> +
>> +       /* the remaining commands/responses are only valid in class B 
>> mode */
>> +       if (lapc->dli.lln == DECT_LLN_CLASS_A)
>> +               goto err;
>> +
>> +       switch (cr) {
>> +       case DECT_FA_CTRL_U_CR_SABM:
>> +               break;
>> +       case DECT_FA_CTRL_U_CR_DM:
>> +               break;
>> +       case DECT_FA_CTRL_U_CR_DISC:
>> +               break;
>> +       case DECT_FA_CTRL_U_CR_UA:
>> +               break;
>> +       }
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_lapc_rcv(struct dect_lapc *lapc, struct sk_buff 
>> *skb)
>> +{
>> +       struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
>> +
>> +       if ((fh->ctrl & DECT_FA_CTRL_I_FMT_MASK) == 
>> DECT_FA_CTRL_I_FMT_ID)
>> +               return dect_lapc_rcv_iframe(lapc, skb);
>> +       else if ((fh->ctrl & DECT_FA_CTRL_S_FMT_MASK) == 
>> DECT_FA_CTRL_S_FMT_ID)
>> +               return dect_lapc_rcv_sframe(lapc, skb);
>> +       else if ((fh->ctrl & DECT_FA_CTRL_U_FMT_MASK) == 
>> DECT_FA_CTRL_U_FMT_ID)
>> +               return dect_lapc_rcv_uframe(lapc, skb);
>> +       else
>> +               kfree_skb(skb);
>> +}
>> +
>> +int dect_lapc_transmit(struct dect_lapc *lapc)
>> +{
>> +       dect_lapc_send_iframe(lapc, 0);
>> +       return 0;
>> +}
>> +
>> +int dect_lapc_establish(struct dect_lapc *lapc)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       lapc_debug(lapc, "establish\n");
>> +
>> +       /* Prepend zero-sized message to transmit queue to trigger 
>> connection
>> +        * establishment.
>> +        */
>> +       skb = dect_lapc_alloc_skb(lapc);
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       skb_queue_head(&lapc->sk->sk_write_queue, skb);
>> +
>> +       lapc->lc->elapc = lapc;
>> +       dect_lapc_send_iframe(lapc, lapc->dli.lln != 
>> DECT_LLN_CLASS_A);
>> +       lapc->nlf = false;
>> +
>> +       mod_timer(&lapc->timer, jiffies + 
>> DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT);
>> +       return 0;
>> +}
>> +
>> +/*
>> + * Initiate link release.
>> + */
>> +void dect_lapc_release(struct dect_lapc *lapc, bool normal)
>> +{
>> +       lapc_debug(lapc, "release: normal: %u\n", normal);
>> +       if (dect_lapc_done(lapc) || !normal) {
>> +               lapc->sk->sk_state = DECT_SK_RELEASED;
>> +               dect_lapc_destroy(lapc);
>> +       } else
>> +               dect_lapc_state_change(lapc, DECT_SK_RELEASE_PENDING);
>> +}
>> +
>> +/*
>> + * Lc entity
>> + *
>> + * The Lc entity receives and transmits LAPC frames from/to the MAC 
>> layer.
>> + *
>> + * For transmission the frames are checksummed and fragmented into 
>> channel
>> + * sized units. The channel is chosen before transmission of a new 
>> frame
>> + * based on availability and demand. All fragments of one frame are
>> + * transmitted in the chosen channel.
>> + *
>> + * Received fragments are resegmented and have their checksum 
>> validated,
>> + * then routed to the LAPC entity associated with the logical link 
>> number.
>> + */
>> +
>> +#define lc_debug(lc, fmt, args...) \
>> +       pr_debug("Lc (MCEI %u): " fmt, (lc)->mc->mcei, ## args)
>> +
>> +void dect_lc_destroy(struct dect_lc *lc)
>> +{
>> +       lc_debug(lc, "destroy\n");
>> +       dect_dlc_mac_conn_unbind(lc->mc);
>> +       kfree_skb(lc->rx_head);
>> +       kfree_skb(lc->tx_head);
>> +       __skb_queue_purge(&lc->txq);
>> +       kfree(lc);
>> +}
>> +
>> +static void dect_lc_put(struct dect_lc *lc)
>> +{
>> +       if (--lc->use > 0)
>> +               return;
>> +       dect_lc_destroy(lc);
>> +}
>> +
>> +static void dect_lc_hold(struct dect_lc *lc)
>> +{
>> +       lc->use++;
>> +}
>> +
>> +void dect_lc_unbind(struct dect_lc *lc, struct dect_lapc *lapc)
>> +{
>> +       lc_debug(lc, "unbind LLN: %u use: %u\n", lapc->dli.lln, 
>> lc->use);
>> +       if (WARN_ON(lc->lapcs[lapc->dli.lln] == NULL))
>> +               return;
>> +
>> +       lc->lapcs[lapc->dli.lln] = NULL;
>> +       dect_lc_put(lc);
>> +}
>> +
>> +void dect_lc_bind(struct dect_lc *lc, struct dect_lapc *lapc)
>> +{
>> +       lc_debug(lc, "bind LLN: %u use: %u\n", lapc->dli.lln, 
>> lc->use);
>> +
>> +       lc->lapcs[lapc->dli.lln] = lapc;
>> +       dect_lc_hold(lc);
>> +}
>> +
>> +struct dect_lc *dect_lc_init(struct dect_mac_conn *mc, gfp_t gfp)
>> +{
>> +       struct dect_lc *lc;
>> +
>> +       lc = kzalloc(sizeof(*lc), gfp);
>> +       if (lc == NULL)
>> +               return NULL;
>> +
>> +       lc->mc = mc;
>> +       dect_dlc_mac_conn_bind(mc);
>> +
>> +       lc_debug(lc, "init\n");
>> +       skb_queue_head_init(&lc->txq);
>> +       switch (mc->mci.pmid.type) {
>> +       case DECT_PMID_ASSIGNED:
>> +               lc->lsig = dect_build_pmid(&mc->mci.pmid);
>> +               break;
>> +       default:
>> +               lc->lsig = 0;
>> +               break;
>> +       }
>> +
>> +       return lc;
>> +}
>> +
>> +static void dect_fa_frame_csum(const struct dect_lc *lc, struct 
>> sk_buff *skb)
>> +{
>> +       u8 *data = skb->data;
>> +       unsigned int i;
>> +       u8 c0 = 0, c1 = 0;
>> +       u8 x, y;
>> +       u16 t;
>> +
>> +       data[skb->len - 2] = 0;
>> +       data[skb->len - 1] = 0;
>> +
>> +       for (i = 0; i < skb->len; i++) {
>> +               t = c0 + data[i];
>> +               c0 = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +               t = c1 + c0;
>> +               c1 = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +       }
>> +
>> +       t = c0 + (u8)~c1;
>> +       x = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +
>> +       t = (u8)~c0 + (u8)~c0;
>> +       t = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +       t += c1;
>> +       y = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +
>> +       data[skb->len - 2] = x ^ (lc->lsig >> 8);
>> +       data[skb->len - 1] = y ^ (lc->lsig & 0xff);
>> +       lc_debug(lc, "checksum: lsig: %.4x x: %.2x y: %.2x\n",
>> +                lc->lsig, x, y);
>> +}
>> +
>> +static bool dect_fa_frame_csum_verify(const struct dect_lc *lc,
>> +                                     struct sk_buff *skb)
>> +{
>> +       u8 *data = skb->data;
>> +       unsigned int i;
>> +       u8 c0 = 0, c1 = 0;
>> +       u16 t;
>> +
>> +       data[skb->len - 2] ^= lc->lsig >> 8;
>> +       data[skb->len - 1] ^= lc->lsig & 0xff;
>> +
>> +       for (i = 0; i < skb->len; i++) {
>> +               t = c0 + data[i];
>> +               c0 = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +               t = c1 + c0;
>> +               c1 = (t & 0xffU) + ((t >> 8) & 0x1U);
>> +       }
>> +
>> +       lc_debug(lc, "csum verify: lsig %.4x c0: %.2x c1: %.2x\n",
>> +                lc->lsig, c0, c1);
>> +       return c0 == (u8)~0 && c1 == (u8)~0;
>> +}
>> +
>> +static const u8 channel_sdu_size[] = {
>> +       [DECT_MC_C_S]   = DECT_C_S_SDU_SIZE,
>> +       [DECT_MC_C_F]   = DECT_C_F_SDU_SIZE,
>> +};
>> +
>> +/*
>> + * Prepare a DLC frame for transmission to the MAC layer. This 
>> involves
>> + * checksumming the frame, selecting the logical channel for 
>> transmission
>> + * and fragmenting it into units carried by the logical channel.
>> + */
>> +static struct sk_buff *dect_lc_tx(struct dect_lc *lc)
>> +{
>> +       struct sk_buff *skb, *frag;
>> +       u8 *fill, fill_len;
>> +       u8 flen;
>> +
>> +       skb = lc->tx_head;
>> +       if (skb == NULL) {
>> +               skb = skb_dequeue(&lc->txq);
>> +               if (skb == NULL)
>> +                       return NULL;
>> +               lc_debug(lc, "tx: begin new frame len: %u\n", 
>> skb->len);
>> +
>> +               flen = channel_sdu_size[DECT_MC_C_S];
>> +               fill_len = roundup(skb->len + DECT_FA_CSUM_SIZE, flen) 
>> -
>> +                          (skb->len + DECT_FA_CSUM_SIZE);
>> +               fill = skb_put(skb, fill_len);
>> +               memset(fill, DECT_FA_FILL_PATTERN, fill_len);
>> +
>> +               skb_put(skb, DECT_FA_CSUM_SIZE);
>> +               dect_fa_frame_csum(lc, skb);
>> +
>> +               lc->tx_head = skb;
>> +               lc->tx_len = flen;
>> +       }
>> +
>> +       /* Fragment into tx_len sized units */
>> +       if (skb->len > lc->tx_len) {
>> +               frag = skb_copy(skb, GFP_ATOMIC);
>> +               if (frag == NULL)
>> +                       return NULL;
>> +               skb_trim(frag, lc->tx_len);
>> +               skb_pull(skb, lc->tx_len);
>> +       } else {
>> +               frag = lc->tx_head;
>> +               lc->tx_head = NULL;
>> +       }
>> +
>> +       lc_debug(lc, "tx: %sfragment len: %u\n",
>> +                lc->tx_head ? "" : "last ", frag->len);
>> +       return frag;
>> +}
>> +
>> +static struct sk_buff *dect_lc_reassemble(struct dect_lc *lc,
>> +                                         enum dect_data_channels 
>> chan,
>> +                                         struct sk_buff *skb)
>> +{
>> +       struct dect_fa_len fl;
>> +       u8 flen, len;
>> +
>> +       if (lc->rx_head == NULL) {
>> +               dect_fa_parse_len(&fl, skb);
>> +               len = fl.len;
>> +               len += DECT_FA_HDR_SIZE + DECT_FA_CSUM_SIZE;
>> +
>> +               flen = channel_sdu_size[chan];
>> +               lc->rx_len = roundup(len, flen);
>> +               lc_debug(lc, "new SDU: len: %u flen: %u\n", len, 
>> flen);
>> +       }
>> +
>> +       lc->rx_head = skb_append_frag(lc->rx_head, skb);
>> +       skb = NULL;
>> +
>> +       if (lc->rx_head->len >= lc->rx_len) {
>> +               WARN_ON(lc->rx_head->len != lc->rx_len);
>> +               skb = lc->rx_head;
>> +               lc->rx_head = NULL;
>> +
>> +               if (skb_linearize(skb) < 0)
>> +                       goto err;
>> +               if (!dect_fa_frame_csum_verify(lc, skb))
>> +                       goto err;
>> +
>> +               /* Trim checksum and filling */
>> +               dect_fa_parse_len(&fl, skb);
>> +               skb_trim(skb, fl.len + DECT_FA_HDR_SIZE);
>> +               lc_debug(lc, "reassembled SDU: len: %u\n", skb->len);
>> +       }
>> +
>> +       return skb;
>> +
>> +err:
>> +       lc_debug(lc, "reassembly failed\n");
>> +       kfree_skb(skb);
>> +       return NULL;
>> +}
>> +
>> +static void dect_lc_rcv(struct dect_lc *lc, enum dect_data_channels 
>> chan,
>> +                       struct sk_buff *skb)
>> +{
>> +       struct dect_fa_hdr *fh;
>> +       struct dect_lapc *lapc;
>> +       struct dect_dli dli;
>> +       enum dect_sapis sapi;
>> +
>> +       skb = dect_lc_reassemble(lc, chan, skb);
>> +       if (skb == NULL)
>> +               return;
>> +       fh = (struct dect_fa_hdr *)skb->data;
>> +
>> +       dli.lln = (fh->addr & DECT_FA_ADDR_LLN_MASK) >> 
>> DECT_FA_ADDR_LLN_SHIFT;
>> +       lc_debug(lc, "receive: LLN %u NLF %u SAPI %u\n",
>> +                dli.lln, (fh->addr & DECT_FA_ADDR_NLF_FLAG) ? 1 : 0,
>> +                (fh->addr & DECT_FA_ADDR_SAPI_MASK) >> 
>> DECT_FA_ADDR_SAPI_SHIFT);
>> +
>> +       if (lc->lapcs[dli.lln] != NULL)
>> +               return dect_lapc_rcv(lc->lapcs[dli.lln], skb);
>> +
>> +       /* Link establishment: new requests are only valid while no 
>> link
>> +        * establishment is in progress.
>> +        */
>> +       if (!(fh->addr & DECT_FA_ADDR_NLF_FLAG))
>> +               goto err;
>> +       if ((fh->ctrl & DECT_FA_CTRL_I_FMT_MASK) != 
>> DECT_FA_CTRL_I_FMT_ID)
>> +               goto err;
>> +       if (lc->elapc != NULL)
>> +               goto err;
>> +
>> +       sapi = (fh->addr & DECT_FA_ADDR_SAPI_MASK) >> 
>> DECT_FA_ADDR_SAPI_SHIFT;
>> +       if (sapi != DECT_SAPI_CO_SIGNALLING && sapi != 
>> DECT_SAPI_CL_SIGNALLING)
>> +               goto err;
>> +       memcpy(&dli.mci, &lc->mc->mci, sizeof(dli.mci));
>> +
>> +       lapc = dect_ssap_rcv_request(lc, &dli, sapi);
>> +       if (lapc == NULL)
>> +               goto err;
>> +       dect_lc_bind(lc, lapc);
>> +
>> +       return dect_lapc_rcv(lapc, skb);
>> +
>> +err:
>> +       lc_debug(lc, "packet ignored\n");
>> +       kfree_skb(skb);
>> +}
>> +
>> +void dect_cplane_rcv(struct dect_mac_conn *mc, enum 
>> dect_data_channels chan,
>> +                    struct sk_buff *skb)
>> +{
>> +       struct dect_lc *lc;
>> +
>> +       if (mc->lc == NULL) {
>> +               lc = dect_lc_init(mc, GFP_ATOMIC);
>> +               if (lc == NULL)
>> +                       goto err;
>> +               mc->lc = lc;
>> +       }
>> +
>> +       lc_debug(mc->lc, "MAC_CO_DATA-ind: chan: %u len: %u\n", chan, 
>> skb->len);
>> +       return dect_lc_rcv(mc->lc, chan, skb);
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +struct sk_buff *dect_cplane_dtr(struct dect_mac_conn *mc, enum 
>> dect_data_channels chan)
>> +{
>> +       struct dect_lc *lc;
>> +
>> +       lc = mc->lc;
>> +       if (lc == NULL)
>> +               return NULL;
>> +       lc_debug(lc, "MAC_CO_DTR-ind: chan: %u\n", chan);
>> +       return dect_lc_tx(lc);
>> +}
>> +
>> +void dect_cplane_notify_state_change(struct dect_mac_conn *mc)
>> +{
>> +       struct dect_lc *lc = mc->lc;
>> +       unsigned int i;
>> +
>> +       if (lc == NULL)
>> +               return;
>> +
>> +       lc_debug(lc, "mac conn state change: state: %u\n", mc->state);
>> +       switch (mc->state) {
>> +       // FIXME: this does not make sense for incoming connections
>> +       case DECT_MAC_CONN_OPEN_PENDING:
>> +               break;
>> +       case DECT_MAC_CONN_OPEN:
>> +               for (i = 0; i < ARRAY_SIZE(lc->lapcs); i++) {
>> +                       if (lc->lapcs[i] == NULL)
>> +                               continue;
>> +                       dect_lapc_establish(lc->lapcs[i]);
>> +                       break;
>> +               }
>> +               break;
>> +       case DECT_MAC_CONN_CLOSED:
>> +               break;
>> +       }
>> +}
>> +
>> +void dect_cplane_mac_dis_ind(const struct dect_mac_conn *mc,
>> +                            enum dect_release_reasons reason)
>> +{
>> +       struct dect_lc *lc = mc->lc;
>> +       unsigned int i;
>> +       int err;
>> +
>> +       if (lc == NULL)
>> +               return;
>> +
>> +       switch (reason) {
>> +       case DECT_REASON_BEARER_RELEASE:
>> +               err = 0;
>> +               break;
>> +       case DECT_REASON_BEARER_SETUP_OR_HANDOVER_FAILED:
>> +               err = EHOSTUNREACH;
>> +               break;
>> +       case DECT_REASON_TIMEOUT_LOST_HANDSHAKE:
>> +               err = ETIMEDOUT;
>> +               break;
>> +       default:
>> +               err = EIO;
>> +               break;
>> +       }
>> +
>> +       dect_lc_hold(lc);
>> +       for (i = 0; i < ARRAY_SIZE(lc->lapcs); i++) {
>> +               if (lc->lapcs[i] == NULL)
>> +                       continue;
>> +               lc->lapcs[i]->sk->sk_state = DECT_SK_RELEASED;
>> +               dect_lapc_error_report(lc->lapcs[i], err);
>> +               dect_lapc_destroy(lc->lapcs[i]);
>> +       }
>> +       dect_lc_put(lc);
>> +}
>> +
>> +void dect_cplane_mac_enc_eks_ind(const struct dect_mac_conn *mc,
>> +                                enum dect_cipher_states status)
>> +{
>> +       struct dect_lc *lc = mc->lc;
>> +       struct dect_dl_encrypt enc;
>> +       struct sk_buff *skb, *nskb;
>> +       unsigned int i;
>> +
>> +       if (lc == NULL || lc->use == 0)
>> +               return;
>> +
>> +       enc.status = status;
>> +       skb = dect_alloc_notification(DECT_DL_ENCRYPT, &enc, 
>> sizeof(enc));
>> +
>> +       for (i = 0; i < ARRAY_SIZE(lc->lapcs); i++) {
>> +               if (lc->lapcs[i] == NULL)
>> +                       continue;
>> +
>> +               nskb = skb ? skb_clone(skb, GFP_ATOMIC) : NULL;
>> +               if (nskb != NULL)
>> +                       sock_queue_err_skb(lc->lapcs[i]->sk, nskb);
>> +               else
>> +                       dect_lapc_error_report(lc->lapcs[i], ENOMEM);
>> +       }
>> +
>> +       kfree_skb(skb);
>> +}
>> diff --git a/target/linux/generic/files/net/dect/dlc_lu1_sap.c 
>> b/target/linux/generic/files/net/dect/dlc_lu1_sap.c
>> new file mode 100644
>> index 0000000..ef75758
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc_lu1_sap.c
>> @@ -0,0 +1,474 @@
>> +/*
>> + * DECT DLC LU1 SAP sockets
>> + *
>> + * Copyright (c) 2009-2010 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/socket.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/sock.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +#define DECT_LU1_FRAME_NONE    255
>> +#define DECT_LU1_PREQUEUE_LEN  5
>> +
>> +#define lu1_debug(lu1, fmt, args...) \
>> +       pr_debug("LU1: rx_bytes: %u tx_bytes: %u " fmt, \
>> +                (lu1)->qstats.rx_bytes, (lu1)->qstats.tx_bytes, \
>> +                ## args)
>> +
>> +struct dect_lu1_sap {
>> +       struct sock                     sk;
>> +       int                             index;
>> +       struct dect_ulei                ulei;
>> +       struct dect_mac_conn            *mc;
>> +       u8                              frame;
>> +       u8                              slot;
>> +       struct sk_buff                  *last;
>> +       struct dect_lux                 lux;
>> +       struct dect_lu1_queue_stats     qstats;
>> +};
>> +
>> +/* Seamless handover slot offsets as per ETS 300 175-3 Annex F */
>> +static const u8 slot_offset_tbl[][DECT_HALF_FRAME_SIZE] = {
>> +       [DECT_FULL_SLOT] = {
>> +               [0]             = 0,
>> +               [1]             = 1,
>> +               [2]             = 3,
>> +               [3]             = 5,
>> +               [4]             = 6,
>> +               [5]             = 8,
>> +               [6]             = 10,
>> +               [7]             = 11,
>> +               [8]             = 13,
>> +               [9]             = 15,
>> +               [10]            = 16,
>> +               [11]            = 18,
>> +       },
>> +       [DECT_DOUBLE_SLOT] = {
>> +               [0]             = 0,
>> +               [2]             = 8,
>> +               [4]             = 16,
>> +               [6]             = 24,
>> +               [8]             = 32,
>> +               [10]            = 40,
>> +       },
>> +       [DECT_LONG_SLOT_640] = {
>> +               [0]             = 0,
>> +               [1]             = 3,
>> +               [2]             = 6,
>> +               [3]             = 10,
>> +               [4]             = 13,
>> +               [5]             = 16,
>> +               [6]             = 20,
>> +               [7]             = 23,
>> +               [8]             = 26,
>> +               [9]             = 30,
>> +               [10]            = 33,
>> +       },
>> +};
>> +
>> +static struct sk_buff *dect_lu1_dequeue(struct dect_lux *lux)
>> +{
>> +       struct dect_lu1_sap *lu1 = container_of(lux, struct 
>> dect_lu1_sap, lux);
>> +       struct dect_cluster *cl = lu1->mc->cl;
>> +       struct sock *sk = &lu1->sk;
>> +       struct sk_buff *skb, *clone, *head = NULL;
>> +       u8 frame, slot, off, last_off, need = 40;
>> +
>> +       /* Fill queue up to prequeue len before delivering the first 
>> frame */
>> +       if (lu1->frame == DECT_LU1_FRAME_NONE &&
>> +           sk->sk_write_queue.qlen < DECT_LU1_PREQUEUE_LEN)
>> +               return NULL;
>> +
>> +       /* Calculate seamless handover data offset */
>> +       frame = __dect_framenum(&cl->timer_base[DECT_TIMER_TX]);
>> +       slot  = __dect_slotnum(&cl->timer_base[DECT_TIMER_TX]);
>> +       if (slot >= DECT_HALF_FRAME_SIZE)
>> +               slot -= DECT_HALF_FRAME_SIZE;
>> +
>> +       last_off = slot_offset_tbl[DECT_FULL_SLOT][lu1->slot];
>> +       off      = slot_offset_tbl[DECT_FULL_SLOT][slot];
>> +
>> +       if (off > last_off)
>> +               off -= last_off;
>> +       else
>> +               off += need - last_off;
>> +
>> +       /* Advance queue */
>> +       lu1_debug(lu1, "dequeue: slot: %u off: %u need: %u\n", slot, 
>> off, need);
>> +       if (lu1->frame != DECT_LU1_FRAME_NONE && lu1->frame != frame)
>> +               lu1->qstats.tx_bytes -= 
>> skb_queue_pull(&sk->sk_write_queue, off);
>> +
>> +       lu1->frame = frame;
>> +       lu1->slot  = slot;
>> +
>> +       /* Duplicate data from last frame on underflow */
>> +       if (lu1->qstats.tx_bytes < need && lu1->last) {
>> +               lu1->qstats.tx_underflow++;
>> +               skb = skb_clone(lu1->last, GFP_ATOMIC);
>> +               if (skb == NULL)
>> +                       goto err;
>> +               skb_pull(skb, skb->len - (need - 
>> lu1->qstats.tx_bytes));
>> +
>> +               skb_queue_head(&sk->sk_write_queue, skb);
>> +               lu1->qstats.tx_bytes += skb->len;
>> +               lu1_debug(lu1, "fill: len: %u need: %u\n", skb->len, 
>> need);
>> +
>> +       }
>> +
>> +       skb = NULL;
>> +       while (need > 0) {
>> +               if (skb == NULL) {
>> +                       skb = skb_peek(&sk->sk_write_queue);
>> +                       if (skb == NULL)
>> +                               goto underflow;
>> +                       /* The head needs to be copied to avoid 
>> sharing the
>> +                        * frag list. */
>> +                       clone = skb_copy(skb, GFP_ATOMIC);
>> +               } else {
>> +                       if (skb_queue_is_last(&sk->sk_write_queue, 
>> skb))
>> +                               goto underflow;
>> +                       skb = skb->next;
>> +                       clone = skb_clone(skb, GFP_ATOMIC);
>> +               }
>> +
>> +               if (clone == NULL)
>> +                       goto err;
>> +
>> +               if (clone->len > need)
>> +                       skb_trim(clone, need);
>> +               need -= clone->len;
>> +
>> +               head = skb_append_frag(head, clone);
>> +               lu1_debug(lu1, "dequeue: head: %u need: %u\n", 
>> head->len, need);
>> +       }
>> +
>> +       if (skb_linearize(head) < 0)
>> +               goto err;
>> +
>> +       kfree_skb(lu1->last);
>> +       lu1->last = skb_get(head);
>> +
>> +       lu1_debug(lu1, "dequeued: len: %u\n", head->len);
>> +       return head;
>> +
>> +underflow:
>> +       lu1->qstats.tx_underflow++;
>> +err:
>> +       kfree_skb(head);
>> +       lu1_debug(lu1, "dequeue: no frame available\n");
>> +       return NULL;
>> +}
>> +
>> +static void dect_lu1_enqueue(struct dect_lux *lux, struct sk_buff 
>> *skb)
>> +{
>> +       struct dect_lu1_sap *lu1 = container_of(lux, struct 
>> dect_lu1_sap, lux);
>> +       unsigned int len = skb->len;
>> +
>> +       if (sock_queue_rcv_skb(&lu1->sk, skb) < 0)
>> +               kfree_skb(skb);
>> +       else
>> +               lu1->qstats.rx_bytes += len;
>> +}
>> +
>> +static void dect_lu1_disconnect(struct dect_lux *lux)
>> +{
>> +       struct dect_lu1_sap *lu1 = container_of(lux, struct 
>> dect_lu1_sap, lux);
>> +       struct sock *sk = &lu1->sk;
>> +
>> +       sk->sk_state = DECT_SK_RELEASED;
>> +       sk->sk_err = ENETDOWN;
>> +       if (!sock_flag(sk, SOCK_DEAD))
>> +               sk->sk_error_report(sk);
>> +       lu1->mc->fbx = NULL;
>> +       dect_dlc_mac_conn_unbind(lu1->mc);
>> +       lu1->mc = NULL;
>> +}
>> +
>> +static const struct dect_lux_ops dect_lu1_ops = {
>> +       .dequeue        = dect_lu1_dequeue,
>> +       .enqueue        = dect_lu1_enqueue,
>> +       .disconnect     = dect_lu1_disconnect,
>> +};
>> +
>> +static inline struct dect_lu1_sap *dect_lu1_sap(struct sock *sk)
>> +{
>> +       return (struct dect_lu1_sap *)sk;
>> +}
>> +
>> +static int dect_parse_ulei(struct dect_ulei *ulei,
>> +                          const struct sockaddr_dect_lu *addr)
>> +{
>> +       if (dect_parse_ari(&ulei->mci.ari, (u64)addr->dect_ari << 24) 
>> == 0)
>> +               return -EINVAL;
>> +       dect_parse_pmid(&ulei->mci.pmid, addr->dect_pmid);
>> +       ulei->mci.lcn = addr->dect_lcn;
>> +       return 0;
>> +}
>> +
>> +static void dect_build_ulei(struct sockaddr_dect_lu *addr,
>> +                           const struct dect_ulei *ulei)
>> +{
>> +       addr->dect_family = AF_DECT;
>> +       addr->dect_pmid   = dect_build_pmid(&ulei->mci.pmid);
>> +       addr->dect_lcn    = ulei->mci.lcn;
>> +}
>> +
>> +static int dect_lu1_init(struct sock *sk)
>> +{
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +
>> +       sk->sk_state = DECT_SK_RELEASED;
>> +       lu1->frame   = DECT_LU1_FRAME_NONE;
>> +       return 0;
>> +}
>> +
>> +static void dect_lu1_close(struct sock *sk, long timeout)
>> +{
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +
>> +       if (sk->sk_state == DECT_SK_ESTABLISHED) {
>> +               lu1->mc->fbx = NULL;
>> +               dect_dlc_mac_conn_unbind(lu1->mc);
>> +               sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
>> +       }
>> +
>> +       __skb_queue_purge(&sk->sk_receive_queue);
>> +       __skb_queue_purge(&sk->sk_write_queue);
>> +       kfree_skb(lu1->last);
>> +
>> +       sock_orphan(sk);
>> +       sock_put(sk);
>> +}
>> +
>> +static int dect_lu1_getname(struct sock *sk, struct sockaddr *uaddr,
>> +                            int *len, int peer)
>> +{
>> +       struct sockaddr_dect_lu *addr = (struct sockaddr_dect_lu 
>> *)uaddr;
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +
>> +       if (peer)
>> +               return -EOPNOTSUPP;
>> +
>> +       addr->dect_index = lu1->index;
>> +       dect_build_ulei(addr, &lu1->ulei);
>> +       *len = sizeof(*addr);
>> +       return 0;
>> +}
>> +
>> +static int dect_lu1_connect(struct sock *sk, struct sockaddr *uaddr, 
>> int len)
>> +{
>> +       struct sockaddr_dect_lu *addr = (struct sockaddr_dect_lu 
>> *)uaddr;
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +       struct dect_cluster *cl;
>> +       struct dect_ulei ulei;
>> +       struct dect_mac_conn *mc;
>> +       int err;
>> +
>> +       err = dect_parse_ulei(&ulei, addr);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       err = -ENODEV;
>> +       cl = dect_cluster_get_by_index(addr->dect_index);
>> +       if (cl == NULL)
>> +               goto err1;
>> +
>> +       err = -ENETDOWN;
>> +       mc = dect_mac_conn_get_by_mci(cl, &ulei.mci);
>> +       if (mc == NULL)
>> +               goto err1;
>> +       WARN_ON(mc->state == DECT_MAC_CONN_CLOSED);
>> +
>> +       err = -EBUSY;
>> +       if (mc->fbx != NULL)
>> +               goto err1;
>> +
>> +       memcpy(&lu1->ulei, &ulei, sizeof(lu1->ulei));
>> +
>> +       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
>> +       sk->sk_state = DECT_SK_ESTABLISHED;
>> +
>> +       lu1->lux.fbx.ops = &dect_fbn_ops;
>> +       lu1->lux.ops = &dect_lu1_ops;
>> +       lu1->mc = mc;
>> +       mc->fbx = &lu1->lux.fbx;
>> +       dect_dlc_mac_conn_bind(lu1->mc);
>> +       pr_debug("LU1: bound to MCEI %u\n", mc->mcei);
>> +       return 0;
>> +
>> +err1:
>> +       return err;
>> +}
>> +
>> +static int dect_lu1_getsockopt(struct sock *sk, int level, int 
>> optname,
>> +                              char __user *optval, int __user 
>> *optlen)
>> +{
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +       int len;
>> +
>> +       if (get_user(len, optlen))
>> +               return -EFAULT;
>> +       if (len < 0)
>> +               return -EINVAL;
>> +
>> +       switch (optname) {
>> +       case DECT_LU1_QUEUE_STATS:
>> +               if (len > sizeof(lu1->qstats))
>> +                       len = sizeof(lu1->qstats);
>> +               if (put_user(len, optlen) ||
>> +                   copy_to_user(optval, &lu1->qstats, len))
>> +                       return -EFAULT;
>> +               break;
>> +       default:
>> +               return -ENOPROTOOPT;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int dect_lu1_recvmsg(struct kiocb *iocb, struct sock *sk,
>> +                           struct msghdr *msg, size_t len,
>> +                           int noblock, int flags, int *addr_len)
>> +{
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +       struct sk_buff *skb;
>> +       size_t copied = 0, copy;
>> +       long timeo;
>> +       int err = 0;
>> +
>> +       if (flags & (MSG_OOB | MSG_TRUNC))
>> +               return -EOPNOTSUPP;
>> +
>> +       lock_sock(sk);
>> +
>> +       if (sk->sk_state != DECT_SK_ESTABLISHED) {
>> +               err = -ENOTCONN;
>> +               goto out;
>> +       }
>> +
>> +       timeo = sock_rcvtimeo(sk, noblock);
>> +
>> +       while (copied < len) {
>> +               skb = skb_peek(&sk->sk_receive_queue);
>> +               if (skb != NULL)
>> +                       goto copy;
>> +
>> +               if (!timeo) {
>> +                       err = -EAGAIN;
>> +                       break;
>> +               }
>> +
>> +               if (signal_pending(current)) {
>> +                       err = sock_intr_errno(timeo);
>> +                       break;
>> +               }
>> +
>> +               sk_wait_data(sk, &timeo);
>> +               continue;
>> +
>> +copy:
>> +               copy = len - copied;
>> +               if (copy > skb->len)
>> +                       copy = skb->len;
>> +
>> +               err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, 
>> copy);
>> +               if (err < 0)
>> +                       break;
>> +               copied += copy;
>> +
>> +               if (copy < skb->len) {
>> +                       __skb_pull(skb, copy);
>> +                       break;
>> +               } else
>> +                       sk_eat_skb(sk, skb, 0);
>> +       }
>> +
>> +out:
>> +       lu1->qstats.rx_bytes -= copied;
>> +       if (copied < len)
>> +               lu1->qstats.rx_underflow++;
>> +
>> +       release_sock(sk);
>> +       lu1_debug(lu1, "recvmsg: dequeued: %zu len: %zu\n", copied, 
>> len);
>> +       return copied ? : err;
>> +}
>> +
>> +static int dect_lu1_sendmsg(struct kiocb *kiocb, struct sock *sk,
>> +                           struct msghdr *msg, size_t len)
>> +{
>> +       struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
>> +       struct sk_buff *skb;
>> +       int err;
>> +
>> +       if (msg->msg_flags & MSG_OOB)
>> +               return -EOPNOTSUPP;
>> +
>> +       if (sk->sk_state != DECT_SK_ESTABLISHED)
>> +               return -ENOTCONN;
>> +
>> +       skb = sock_alloc_send_skb(sk, len, msg->msg_flags & 
>> MSG_DONTWAIT, &err);
>> +       if (skb == NULL)
>> +               goto err1;
>> +       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       skb_queue_tail(&sk->sk_write_queue, skb);
>> +       lu1->qstats.tx_bytes += len;
>> +       lu1_debug(lu1, "sendmsg: queued: %zu\n", len);
>> +       return len;
>> +
>> +err2:
>> +       kfree_skb(skb);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static struct dect_proto dect_lu1_proto = {
>> +       .type                   = SOCK_STREAM,
>> +       .protocol               = DECT_LU1_SAP,
>> +       .capability             = -1,
>> +       .ops                    = &dect_stream_ops,
>> +       .proto.name             = "DECT_LU1_SAP",
>> +       .proto.owner            = THIS_MODULE,
>> +       .proto.obj_size         = sizeof(struct dect_lu1_sap),
>> +       .proto.init             = dect_lu1_init,
>> +       .proto.close            = dect_lu1_close,
>> +       .proto.connect          = dect_lu1_connect,
>> +       .proto.getsockopt       = dect_lu1_getsockopt,
>> +       .proto.recvmsg          = dect_lu1_recvmsg,
>> +       .proto.sendmsg          = dect_lu1_sendmsg,
>> +       .getname                = dect_lu1_getname,
>> +};
>> +
>> +static int __init dect_lu1_sap_module_init(void)
>> +{
>> +       BUILD_BUG_ON(sizeof(struct sockaddr_dect_lu) >
>> +                    sizeof(struct sockaddr));
>> +       return dect_proto_register(&dect_lu1_proto);
>> +}
>> +
>> +static void dect_lu1_sap_module_exit(void)
>> +{
>> +       dect_proto_unregister(&dect_lu1_proto);
>> +}
>> +
>> +module_init(dect_lu1_sap_module_init);
>> +module_exit(dect_lu1_sap_module_exit);
>> +
>> +MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
>> +MODULE_DESCRIPTION("DECT DLC LU1 SAP sockets");
>> +MODULE_LICENSE("GPL");
>> +
>> +MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_LU1_SAP);
>> diff --git a/target/linux/generic/files/net/dect/dlc_s_sap.c 
>> b/target/linux/generic/files/net/dect/dlc_s_sap.c
>> new file mode 100644
>> index 0000000..37baa5c
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc_s_sap.c
>> @@ -0,0 +1,659 @@
>> +/*
>> + * DECT DLC S SAP sockets - DLC C-plane data link service access
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/socket.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <asm/uaccess.h>
>> +#include <net/sock.h>
>> +#include <net/dect/dect.h>
>> +
>> +static DEFINE_SPINLOCK(dect_ssap_lock);
>> +static HLIST_HEAD(dect_ssap_sockets);
>> +static HLIST_HEAD(dect_ssap_listeners);
>> +
>> +struct dect_ssap {
>> +       struct dect_csk         csk;
>> +       int                     index;
>> +       struct dect_dlei        dlei;
>> +       struct dect_lapc        *lapc;
>> +};
>> +
>> +static inline struct dect_ssap *dect_ssap(struct sock *sk)
>> +{
>> +       return (struct dect_ssap *)sk;
>> +}
>> +
>> +static int dect_parse_dlei(struct dect_dlei *dlei,
>> +                          const struct sockaddr_dect_ssap *addr)
>> +{
>> +       if (dect_parse_ari(&dlei->mci.ari, (u64)addr->dect_ari << 24) 
>> == 0)
>> +               return -EINVAL;
>> +       dect_parse_pmid(&dlei->mci.pmid, addr->dect_pmid);
>> +       dlei->mci.lcn = addr->dect_lcn;
>> +
>> +       dlei->lln = addr->dect_lln;
>> +       if (dlei->lln > DECT_LLN_UNASSIGNED &&
>> +           dlei->lln != DECT_LLN_ANY)
>> +               return -EINVAL;
>> +
>> +       dlei->sapi = addr->dect_sapi;
>> +       switch (dlei->sapi) {
>> +       case DECT_SAPI_CO_SIGNALLING:
>> +       case DECT_SAPI_CL_SIGNALLING:
>> +       case DECT_SAPI_ANY:
>> +               break;
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void dect_build_dlei(struct sockaddr_dect_ssap *addr,
>> +                           const struct dect_dlei *dlei)
>> +{
>> +       addr->dect_family = AF_DECT;
>> +       addr->dect_pmid = dect_build_pmid(&dlei->mci.pmid);
>> +       addr->dect_ari  = dect_build_ari(&dlei->mci.ari) >> 24;
>> +       addr->dect_lcn  = dlei->mci.lcn;
>> +       addr->dect_lln  = dlei->lln;
>> +       addr->dect_sapi = dlei->sapi;
>> +}
>> +
>> +static void dect_ssap_insert(struct sock *sk)
>> +{
>> +       sk_add_node(sk, &dect_ssap_sockets);
>> +       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
>> +}
>> +
>> +static void dect_ssap_unlink(struct sock *sk)
>> +{
>> +       if (sk_del_node_init(sk))
>> +               sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
>> +}
>> +
>> +static int dect_ssap_init(struct sock *sk)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +
>> +       INIT_HLIST_HEAD(&ssap->csk.accept_queue);
>> +       return 0;
>> +}
>> +
>> +static struct sock *dect_ssap_acceptq_dequeue(struct dect_ssap *ssap)
>> +{
>> +       struct sock *sk;
>> +
>> +       if (hlist_empty(&ssap->csk.accept_queue))
>> +               return NULL;
>> +       sk = hlist_entry(ssap->csk.accept_queue.first, struct sock, 
>> sk_bind_node);
>> +       __sk_del_bind_node(sk);
>> +       sk_node_init(&sk->sk_bind_node);
>> +       sk_acceptq_removed(&ssap->csk.sk);
>> +       return sk;
>> +}
>> +
>> +static void dect_ssap_close(struct sock *sk, long timeout)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct sock *req;
>> +
>> +       pr_debug("close sock %p refcnt %u rmem %u wmem %u\n",
>> +                sk, atomic_read(&sk->sk_refcnt),
>> +                atomic_read(&sk->sk_rmem_alloc),
>> +                atomic_read(&sk->sk_wmem_alloc));
>> +
>> +       spin_lock_bh(&dect_ssap_lock);
>> +       dect_ssap_unlink(sk);
>> +       spin_unlock_bh(&dect_ssap_lock);
>> +
>> +       if (sk->sk_state != DECT_SK_RELEASED && ssap->lapc != NULL)
>> +               dect_lapc_release(ssap->lapc, false);
>> +
>> +       if (!hlist_unhashed(&sk->sk_bind_node))
>> +               __sk_del_bind_node(sk);
>> +
>> +       while ((req = dect_ssap_acceptq_dequeue(ssap)) != NULL) {
>> +               spin_lock_bh(&dect_ssap_lock);
>> +               dect_ssap_unlink(req);
>> +               spin_unlock_bh(&dect_ssap_lock);
>> +
>> +               dect_lapc_release(dect_ssap(req)->lapc, false);
>> +       }
>> +
>> +       sk_common_release(sk);
>> +}
>> +
>> +static int dect_ssap_bind_conflict(int index, const struct dect_dlei 
>> *dlei)
>> +{
>> +       struct dect_ssap *ssap;
>> +       struct sock *sk;
>> +
>> +       // FIXME: wildcards
>> +       sk_for_each(sk, &dect_ssap_sockets) {
>> +               ssap = dect_ssap(sk);
>> +               if (ssap->index == index &&
>> +                   !dect_ari_cmp(&ssap->dlei.mci.ari, &dlei->mci.ari) 
>> &&
>> +                   !dect_pmid_cmp(&ssap->dlei.mci.pmid, 
>> &dlei->mci.pmid) &&
>> +                   ssap->dlei.lln == dlei->lln &&
>> +                   ssap->dlei.sapi == dlei->sapi)
>> +                       return -EADDRINUSE;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int dect_ssap_bind(struct sock *sk, struct sockaddr *uaddr, 
>> int len)
>> +{
>> +       struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap 
>> *)uaddr;
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct dect_dlei dlei;
>> +       int err;
>> +
>> +       if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
>> +               return -EINVAL;
>> +
>> +       err = dect_parse_dlei(&dlei, addr);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       lock_sock(sk);
>> +       spin_lock_bh(&dect_ssap_lock);
>> +
>> +       err = dect_ssap_bind_conflict(addr->dect_index, &dlei);
>> +       if (err < 0)
>> +               goto out;
>> +
>> +       ssap->index = addr->dect_index;
>> +       memcpy(&ssap->dlei, &dlei, sizeof(ssap->dlei));
>> +       dect_ssap_insert(sk);
>> +out:
>> +       spin_unlock_bh(&dect_ssap_lock);
>> +       release_sock(sk);
>> +       return err;
>> +}
>> +
>> +static struct dect_ssap *dect_ssap_lookup_listener(const struct 
>> dect_cluster *cl,
>> +                                                  const struct 
>> dect_dli *dli,
>> +                                                  enum dect_sapis 
>> sapi)
>> +{
>> +       struct dect_ssap *ssap;
>> +       struct sock *sk;
>> +
>> +       pr_debug("lookup listener: lln %u sapi %u\n", dli->lln, sapi);
>> +       sk_for_each_bound(sk, &dect_ssap_listeners) {
>> +               ssap = dect_ssap(sk);
>> +               if (cl->index != ssap->index)
>> +                       continue;
>> +#if 0
>> +               if (!dect_ari_cmp(&ssap->dlei.mci.ari, &dli->mci.ari))
>> +                       continue;
>> +               if (!dect_pmid_cmp(&ssap->dlei.mci.pmid, 
>> &dli->mci.pmid))
>> +                       continue;
>> +#endif
>> +               pr_debug("ssap: lln %u sapi %u\n", ssap->dlei.lln, 
>> ssap->dlei.sapi);
>> +               if (ssap->dlei.lln != DECT_LLN_ANY &&
>> +                   ssap->dlei.lln != dli->lln)
>> +                       continue;
>> +               if (ssap->dlei.sapi != DECT_SAPI_ANY &&
>> +                   ssap->dlei.sapi != sapi)
>> +                       continue;
>> +               return ssap;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +struct dect_lapc *dect_ssap_rcv_request(struct dect_lc *lc,
>> +                                       const struct dect_dli *dli,
>> +                                       enum dect_sapis sapi)
>> +{
>> +       struct dect_ssap *ssap, *newssap;
>> +       struct sock *sk, *newsk;
>> +       struct dect_lapc *lapc = NULL;
>> +
>> +       spin_lock(&dect_ssap_lock);
>> +       ssap = dect_ssap_lookup_listener(lc->mc->cl, dli, sapi);
>> +       if (ssap == NULL)
>> +               goto out;
>> +
>> +       sk = &ssap->csk.sk;
>> +       if (sk_acceptq_is_full(sk))
>> +               goto out;
>> +
>> +       newsk = sk_alloc(&init_net, PF_DECT, GFP_ATOMIC, sk->sk_prot);
>> +       if (newsk == NULL)
>> +               goto out;
>> +
>> +       sock_init_data(NULL, newsk);
>> +       newsk->sk_type     = sk->sk_type;
>> +       newsk->sk_protocol = sk->sk_protocol;
>> +       newsk->sk_destruct = sk->sk_destruct;
>> +
>> +       lapc = dect_lapc_init(newsk, dli, sapi, lc, GFP_ATOMIC);
>> +       if (lapc == NULL)
>> +               goto err1;
>> +
>> +       newssap = dect_ssap(newsk);
>> +       newssap->index     = lc->mc->cl->index;
>> +       memcpy(&newssap->dlei.mci, &dli->mci, 
>> sizeof(newssap->dlei.mci));
>> +       newssap->dlei.lln  = dli->lln;
>> +       newssap->dlei.sapi = sapi;
>> +       newssap->lapc      = lapc;
>> +
>> +       newsk->sk_state = DECT_SK_ESTABLISHED;
>> +       dect_ssap_insert(newsk);
>> +       sk_add_bind_node(newsk, &ssap->csk.accept_queue);
>> +       sk_acceptq_added(sk);
>> +
>> +       sk->sk_state_change(sk);
>> +       sk->sk_data_ready(sk, 0);
>> +       goto out;
>> +
>> +err1:
>> +       sk_free(newsk);
>> +       goto out;
>> +
>> +out:
>> +       spin_unlock(&dect_ssap_lock);
>> +       return lapc;
>> +}
>> +
>> +static void dect_ssap_hash(struct sock *sk)
>> +{
>> +       sk->sk_state = DECT_SK_LISTEN;
>> +
>> +       spin_lock_bh(&dect_ssap_lock);
>> +       sk_add_bind_node(sk, &dect_ssap_listeners);
>> +       spin_unlock_bh(&dect_ssap_lock);
>> +}
>> +
>> +static void dect_ssap_unhash(struct sock *sk)
>> +{
>> +       if (sk_hashed(sk)) {
>> +               spin_lock_bh(&dect_ssap_lock);
>> +               __sk_del_bind_node(sk);
>> +               spin_unlock_bh(&dect_ssap_lock);
>> +       }
>> +}
>> +
>> +static int dect_ssap_wait_req(struct sock *sk, int noblock)
>> +{
>> +       struct task_struct *tsk = current;
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       long timeo = sock_rcvtimeo(sk, noblock);
>> +
>> +       for (;;) {
>> +               DEFINE_WAIT(wait);
>> +
>> +               if (sk->sk_state != DECT_SK_LISTEN)
>> +                       return -EINVAL;
>> +               if (!hlist_empty(&ssap->csk.accept_queue))
>> +                       break;
>> +               if (!timeo)
>> +                       return -EWOULDBLOCK;
>> +               if (signal_pending(tsk))
>> +                       return sock_intr_errno(timeo);
>> +
>> +               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
>> +                                         TASK_INTERRUPTIBLE);
>> +               release_sock(sk);
>> +               timeo = schedule_timeout(timeo);
>> +               lock_sock(sk);
>> +               finish_wait(sk_sleep(sk), &wait);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static struct sock *dect_ssap_accept(struct sock *sk, int flags, int 
>> *errp)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct sock *newsk;
>> +       int err;
>> +
>> +       lock_sock(sk);
>> +       err = dect_ssap_wait_req(sk, flags & O_NONBLOCK);
>> +       if (err < 0)
>> +               goto err;
>> +
>> +       newsk = dect_ssap_acceptq_dequeue(ssap);
>> +       release_sock(sk);
>> +
>> +       *errp = 0;
>> +       return newsk;
>> +
>> +err:
>> +       release_sock(sk);
>> +       *errp = err;
>> +       return NULL;
>> +}
>> +
>> +static int dect_ssap_connect(struct sock *sk, struct sockaddr *uaddr, 
>> int len)
>> +{
>> +       struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap 
>> *)uaddr;
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct dect_cluster *cl;
>> +       struct dect_dlei dlei;
>> +       struct dect_dli dli;
>> +       struct dect_lapc *lapc;
>> +       struct dect_lc *lc;
>> +       struct dect_mac_conn *mc;
>> +       bool new_mc = false, new_lc = false;
>> +       int err;
>> +
>> +       if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
>> +               return -EINVAL;
>> +
>> +       err = dect_parse_dlei(&dlei, addr);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       err = -ENODEV;
>> +       cl = dect_cluster_get_by_index(addr->dect_index);
>> +       if (cl == NULL)
>> +               goto err1;
>> +
>> +       /* The assignable class B LLNs may only be used for 
>> connections
>> +        * originating from a PT. The unassigned LLN may be used by an 
>> FT
>> +        * to request class B operation. Class A and U may be used by 
>> both.
>> +        */
>> +       err = -EINVAL;
>> +       switch (dlei.lln) {
>> +       case DECT_LLN_ASSIGNABLE_MIN ... DECT_LLN_ASSIGNABLE_MAX:
>> +               if (cl->mode != DECT_MODE_PP)
>> +                       goto err1;
>> +               break;
>> +       case DECT_LLN_UNASSIGNED:
>> +               if (cl->mode != DECT_MODE_FP)
>> +                       goto err1;
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       /* Lookup MAC connection and initiate new one if necessary */
>> +       err = -ENOMEM;
>> +       mc = dect_mac_conn_get_by_mci(cl, &dlei.mci);
>> +       if (mc == NULL) {
>> +               mc = dect_mac_conn_init(cl, &dlei.mci, NULL);
>> +               if (mc == NULL)
>> +                       goto err1;
>> +               new_mc = true;
>> +               lc = NULL;
>> +       } else {
>> +               WARN_ON(mc->state == DECT_MAC_CONN_CLOSED);
>> +               lc = mc->lc;
>> +       }
>> +
>> +       /* Get Lc entity and verify LLN is available */
>> +       if (lc == NULL) {
>> +               lc = dect_lc_init(mc, GFP_KERNEL);
>> +               if (lc == NULL)
>> +                       goto err2;
>> +               mc->lc = lc;
>> +               new_lc = true;
>> +       } else {
>> +               err = -EADDRINUSE;
>> +               if (lc->lapcs[dlei.lln] != NULL)
>> +                       goto err2;
>> +       }
>> +
>> +       memcpy(&dli.mci, &dlei.mci, sizeof(dli.mci));
>> +       dli.lln = dlei.lln;
>> +
>> +       lapc = dect_lapc_init(sk, &dli, dlei.sapi, lc, GFP_KERNEL);
>> +       if (lapc == NULL)
>> +               goto err3;
>> +       ssap->lapc = lapc;
>> +
>> +       dect_lc_bind(lc, lapc);
>> +
>> +       if (new_mc)
>> +               err = dect_dlc_mac_conn_establish(mc);
>> +       else
>> +               err = dect_lapc_establish(lapc);
>> +
>> +       if (err < 0)
>> +               goto err4;
>> +
>> +       sk->sk_state = DECT_SK_ESTABLISH_PENDING;
>> +       return 0;
>> +
>> +err4:
>> +       dect_lapc_destroy(lapc);
>> +       /* Both will be release by dect_lapc_destroy() */
>> +       new_lc = false;
>> +       new_mc = false;
>> +err3:
>> +       if (new_lc)
>> +               dect_lc_destroy(lc);
>> +err2:
>> +       if (new_mc)
>> +               dect_dlc_mac_conn_destroy(mc);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static int dect_ssap_getname(struct sock *sk, struct sockaddr *uaddr, 
>> int *len,
>> +                            int peer)
>> +{
>> +       struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap 
>> *)uaddr;
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +
>> +#if 0
>> +       if (peer)
>> +               return -EOPNOTSUPP;
>> +#endif
>> +       addr->dect_index = ssap->index;
>> +       dect_build_dlei(addr, &ssap->dlei);
>> +       *len = sizeof(*addr);
>> +       return 0;
>> +}
>> +
>> +static void dect_ssap_shutdown(struct sock *sk, int how)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +
>> +       if (!(how & SEND_SHUTDOWN))
>> +               return;
>> +
>> +       if (sk->sk_state == DECT_SK_ESTABLISHED)
>> +               dect_lapc_release(ssap->lapc, true);
>> +}
>> +
>> +static int dect_ssap_setsockopt(struct sock *sk, int level, int 
>> optname,
>> +                               char __user *optval, unsigned int 
>> optlen)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct dect_dl_encrypt dle;
>> +       int err;
>> +       u64 ck;
>> +
>> +       switch (optname) {
>> +       case DECT_DL_ENC_KEY:
>> +               if (optlen != sizeof(ck))
>> +                       return -EINVAL;
>> +               if (sk->sk_state != DECT_SK_ESTABLISH_PENDING &&
>> +                   sk->sk_state != DECT_SK_ESTABLISHED)
>> +                       return -ENOTCONN;
>> +               if (copy_from_user(&ck, optval, sizeof(ck)))
>> +                       return -EFAULT;
>> +               err = 
>> dect_dlc_mac_conn_enc_key_req(ssap->lapc->lc->mc, ck);
>> +               break;
>> +       case DECT_DL_ENCRYPT:
>> +               if (optlen != sizeof(dle))
>> +                       return -EINVAL;
>> +               if (sk->sk_state != DECT_SK_ESTABLISHED)
>> +                       return -ENOTCONN;
>> +               if (ssap->lapc->lc->mc->cl->mode != DECT_MODE_PP)
>> +                       return -EOPNOTSUPP;
>> +               if (copy_from_user(&dle, optval, sizeof(dle)))
>> +                       return -EFAULT;
>> +               err = 
>> dect_dlc_mac_conn_enc_eks_req(ssap->lapc->lc->mc,
>> +                                                   dle.status);
>> +               break;
>> +       default:
>> +               err = -ENOPROTOOPT;
>> +       }
>> +       return err;
>> +}
>> +
>> +static int dect_ssap_recvmsg(struct kiocb *iocb, struct sock *sk,
>> +                            struct msghdr *msg, size_t len,
>> +                            int noblock, int flags, int *addr_len)
>> +{
>> +       struct sockaddr_dect *addr;
>> +       struct sk_buff *skb, *eskb;
>> +       size_t copied = 0;
>> +       int err;
>> +
>> +       if (flags & MSG_OOB)
>> +               return -EOPNOTSUPP;
>> +
>> +       eskb = skb_dequeue(&sk->sk_error_queue);
>> +       skb = skb_recv_datagram(sk, flags, noblock, &err);
>> +       if (skb == NULL) {
>> +               if (eskb != NULL && err == -EAGAIN) {
>> +                       err = 0;
>> +                       goto out;
>> +               }
>> +               if (sk->sk_type == SOCK_SEQPACKET) {
>> +                       lock_sock(sk);
>> +                       if (sk->sk_state != DECT_SK_ESTABLISHED &&
>> +                           err == -EAGAIN)
>> +                               err = -ENOTCONN;
>> +                       release_sock(sk);
>> +               }
>> +               goto out;
>> +       }
>> +
>> +       copied = skb->len;
>> +       if (len < copied) {
>> +               msg->msg_flags |= MSG_TRUNC;
>> +               copied = len;
>> +       }
>> +
>> +       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
>> +       if (err < 0)
>> +               goto out_free;
>> +
>> +       if (msg->msg_name != NULL) {
>> +               addr = (struct sockaddr_dect *)msg->msg_name;
>> +               addr->dect_family = AF_DECT;
>> +               addr->dect_index = DECT_SK_CB(skb)->index;
>> +               msg->msg_namelen = sizeof(*addr);
>> +       }
>> +
>> +       sock_recv_timestamp(msg, sk, skb);
>> +
>> +       if (flags & MSG_TRUNC)
>> +               copied = skb->len;
>> +out_free:
>> +       skb_free_datagram(sk, skb);
>> +out:
>> +       if (eskb != NULL)
>> +               put_cmsg(msg, SOL_DECT, DECT_NOTIFY_CB(eskb)->type,
>> +                        eskb->len, eskb->data);
>> +       kfree_skb(eskb);
>> +
>> +       return err ? : copied;
>> +}
>> +
>> +static int dect_ssap_sendmsg(struct kiocb *kiocb, struct sock *sk,
>> +                            struct msghdr *msg, size_t len)
>> +{
>> +       struct dect_ssap *ssap = dect_ssap(sk);
>> +       struct sk_buff *skb;
>> +       long timeo;
>> +       int err;
>> +
>> +       if (msg->msg_flags & MSG_OOB)
>> +               return -EOPNOTSUPP;
>> +
>> +       if (len > DECT_FA_I_MAX)
>> +               return -EMSGSIZE;
>> +
>> +       lock_sock(sk);
>> +       if (sk->sk_type == SOCK_SEQPACKET) {
>> +               if (sk->sk_state != DECT_SK_ESTABLISHED) {
>> +                       timeo = sock_sndtimeo(sk, msg->msg_flags & 
>> MSG_DONTWAIT);
>> +                       err = sk_stream_wait_connect(sk, &timeo);
>> +                       if (err < 0)
>> +                               goto err1;
>> +               }
>> +       }
>> +
>> +       err = -EPIPE;
>> +       if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
>> +               goto err1;
>> +
>> +       skb = sock_alloc_send_skb(sk, len + 32, msg->msg_flags & 
>> MSG_DONTWAIT, &err);
>> +       if (skb == NULL)
>> +               goto err1;
>> +       skb_reset_mac_header(skb);
>> +       skb_reserve(skb, 16);
>> +       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       skb_queue_tail(&sk->sk_write_queue, skb);
>> +       release_sock(sk);
>> +
>> +       dect_lapc_transmit(ssap->lapc);
>> +       return len;
>> +
>> +err2:
>> +       kfree_skb(skb);
>> +err1:
>> +       err = sk_stream_error(sk, msg->msg_flags, err);
>> +       release_sock(sk);
>> +       return err;
>> +}
>> +
>> +static struct dect_proto dect_ssap_proto __read_mostly = {
>> +       .type                   = SOCK_SEQPACKET,
>> +       .protocol               = DECT_S_SAP,
>> +       .capability             = CAP_NET_RAW,
>> +       .ops                    = &dect_stream_ops,
>> +       .proto.name             = "DECT_S_SAP",
>> +       .proto.owner            = THIS_MODULE,
>> +       .proto.obj_size         = sizeof(struct dect_ssap),
>> +       .proto.init             = dect_ssap_init,
>> +       .proto.close            = dect_ssap_close,
>> +       .proto.bind             = dect_ssap_bind,
>> +       .proto.hash             = dect_ssap_hash,
>> +       .proto.unhash           = dect_ssap_unhash,
>> +       .proto.accept           = dect_ssap_accept,
>> +       .proto.connect          = dect_ssap_connect,
>> +       .proto.shutdown         = dect_ssap_shutdown,
>> +       .proto.setsockopt       = dect_ssap_setsockopt,
>> +       .proto.recvmsg          = dect_ssap_recvmsg,
>> +       .proto.sendmsg          = dect_ssap_sendmsg,
>> +       .getname                = dect_ssap_getname,
>> +};
>> +
>> +int __init dect_ssap_module_init(void)
>> +{
>> +       BUILD_BUG_ON(sizeof(struct sockaddr_dect_ssap) >
>> +                    sizeof(struct sockaddr));
>> +       return dect_proto_register(&dect_ssap_proto);
>> +}
>> +
>> +void dect_ssap_module_exit(void)
>> +{
>> +       dect_proto_unregister(&dect_ssap_proto);
>> +}
>> +
>> +MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_S_SAP);
>> diff --git a/target/linux/generic/files/net/dect/dlc_uplane.c 
>> b/target/linux/generic/files/net/dect/dlc_uplane.c
>> new file mode 100644
>> index 0000000..6d8d318
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dlc_uplane.c
>> @@ -0,0 +1,86 @@
>> +/*
>> + * DECT DLC U-plane
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +
>> +static struct sk_buff *dect_fbn_dequeue(struct dect_fbx *fbx)
>> +{
>> +       struct dect_lux *lux = container_of(fbx, struct dect_lux, 
>> fbx);
>> +
>> +       return lux->ops->dequeue(lux);
>> +}
>> +
>> +static void dect_fbn_enqueue(struct dect_fbx *fbx, struct sk_buff 
>> *skb)
>> +{
>> +       struct dect_lux *lux = container_of(fbx, struct dect_lux, 
>> fbx);
>> +
>> +       lux->ops->enqueue(lux, skb);
>> +}
>> +
>> +const struct dect_fbx_ops dect_fbn_ops = {
>> +       .dequeue        = dect_fbn_dequeue,
>> +       .enqueue        = dect_fbn_enqueue,
>> +};
>> +EXPORT_SYMBOL_GPL(dect_fbn_ops);
>> +
>> +struct sk_buff *dect_uplane_dtr(struct dect_mac_conn *mc, enum 
>> dect_data_channels chan)
>> +{
>> +       struct dect_fbx *fbx;
>> +
>> +       fbx = mc->fbx;
>> +       if (fbx == NULL)
>> +               return NULL;
>> +       return fbx->ops->dequeue(fbx);
>> +}
>> +
>> +void dect_uplane_rcv(struct dect_mac_conn *mc, enum 
>> dect_data_channels chan,
>> +                    struct sk_buff *skb)
>> +{
>> +       struct dect_fbx *fbx;
>> +
>> +       fbx = mc->fbx;
>> +       if (fbx == NULL)
>> +               goto err;
>> +       return fbx->ops->enqueue(fbx, skb);
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +void dect_uplane_notify_state_change(struct dect_mac_conn *mc)
>> +{
>> +       struct dect_lux *lux;
>> +       struct dect_fbx *fbx;
>> +
>> +       fbx = mc->fbx;
>> +       if (fbx == NULL)
>> +               return;
>> +       lux = container_of(fbx, struct dect_lux, fbx);
>> +
>> +       switch (mc->state) {
>> +       case DECT_MAC_CONN_OPEN_PENDING:
>> +               break;
>> +       case DECT_MAC_CONN_OPEN:
>> +               break;
>> +       case DECT_MAC_CONN_CLOSED:
>> +               return lux->ops->disconnect(lux);
>> +       }
>> +}
>> diff --git a/target/linux/generic/files/net/dect/dsc.c 
>> b/target/linux/generic/files/net/dect/dsc.c
>> new file mode 100644
>> index 0000000..d3f597a
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/dsc.c
>> @@ -0,0 +1,141 @@
>> +/*
>> + * DECT Standard Cipher
>> + *
>> + * Copyright (c) 2010 Erik Tews 
>> <e_tews at cdc.informatik.tu-darmstadt.de>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/string.h>
>> +#include <net/dect/dsc.h>
>> +
>> +#define R1_LEN                 17
>> +#define R2_LEN                 19
>> +#define R3_LEN                 21
>> +#define R4_LEN                 23
>> +
>> +#define MASK_R1                        (65536 | 32)
>> +#define MASK_R2                        (262144 | 4096 | 8 | 4)
>> +#define MASK_R3                        (1048576 | 2)
>> +#define MASK_R4                        (256 | 4194304)
>> +
>> +#define R1_CLOCKMASK           (1 << 8)
>> +#define R2_CLOCKMASK           (1 << 9)
>> +#define R3_CLOCKMASK           (1 << 10)
>> +
>> +#define R1_R4_CLOCKMASK                (1 << 0)
>> +#define R2_R4_CLOCKMASK                (1 << 1)
>> +#define R3_R4_CLOCKMASK                (1 << 2)
>> +
>> +static uint32_t clock(uint32_t lfsr, int length, uint32_t mask)
>> +{
>> +       return (lfsr >> 1) ^ (-(lfsr & 1) & mask);
>> +}
>> +
>> +static uint32_t combine(uint32_t comb, uint32_t r1, uint32_t r2, 
>> uint32_t r3)
>> +{
>> +       uint32_t c, x10, x11, x20, x21, x30, x31;
>> +
>> +       c = comb;
>> +       x10 = r1 & 1;
>> +       x11 = (r1 >> 1) & 1;
>> +       x20 = r2 & 1;
>> +       x21 = (r2 >> 1) & 1;
>> +       x30 = r3 & 1;
>> +       x31 = (r3 >> 1) & 1;
>> +
>> +       return (x11 & x10 & c) ^
>> +              (x20 & x11 & x10) ^
>> +              (x21 & x10 & c) ^
>> +              (x21 & x20 & x10) ^
>> +              (x30 & x10 & c) ^
>> +              (x30 & x20 & x10) ^
>> +              (x11 & c) ^
>> +              (x11 & x10) ^
>> +              (x20 & x11) ^
>> +              (x30 & c) ^
>> +              (x31 & c) ^
>> +              (x31 & x10) ^
>> +              (x21) ^
>> +              (x31);
>> +}
>> +
>> +void dect_dsc_keystream(uint64_t iv, const uint8_t *key,
>> +                       uint8_t *output, unsigned int len)
>> +{
>> +       uint8_t input[16];
>> +       uint32_t R1, R2, R3, R4, N1, N2, N3, COMB;
>> +       unsigned int i, keybit;
>> +
>> +       memset(output, 0, len);
>> +       input[0] = iv & 0xff;
>> +       input[1] = (iv >> 8) & 0xff;
>> +       input[2] = (iv >> 16) & 0xff;
>> +       input[3] = (iv >> 24) & 0xff;
>> +       input[4] = (iv >> 32) & 0xff;
>> +       for (i = 5; i < 8; i++)
>> +               input[i] = 0;
>> +       for (i = 0; i < 8; i++)
>> +               input[i + 8] = key[i];
>> +
>> +       R1 = R2 = R3 = R4 = COMB = 0;
>> +
>> +       /* load IV and KEY */
>> +       for (i = 0; i < 128; i++) {
>> +               keybit = (input[i / 8] >> ((i) & 7)) & 1;
>> +               R1 = clock(R1, R1_LEN, MASK_R1) ^ (keybit << (R1_LEN - 
>> 1));
>> +               R2 = clock(R2, R2_LEN, MASK_R2) ^ (keybit << (R2_LEN - 
>> 1));
>> +               R3 = clock(R3, R3_LEN, MASK_R3) ^ (keybit << (R3_LEN - 
>> 1));
>> +               R4 = clock(R4, R4_LEN, MASK_R4) ^ (keybit << (R4_LEN - 
>> 1));
>> +       }
>> +
>> +       for (i = 0; i < 40 + (len * 8); i++) {
>> +               N1 = R1;
>> +               N2 = R2;
>> +               N3 = R3;
>> +               COMB = combine(COMB, R1, R2, R3);
>> +               if (((R2 & R2_CLOCKMASK) != 0) ^
>> +                   ((R3 & R3_CLOCKMASK) != 0) ^
>> +                   ((R4 & R1_R4_CLOCKMASK) != 0))
>> +                       N1 = clock(R1, R1_LEN, MASK_R1);
>> +               if (((R1 & R1_CLOCKMASK) != 0) ^
>> +                   ((R3 & R3_CLOCKMASK) != 0) ^
>> +                   ((R4 & R2_R4_CLOCKMASK) != 0))
>> +                       N2 = clock(R2, R2_LEN, MASK_R2);
>> +               if (((R1 & R1_CLOCKMASK) != 0) ^
>> +                   ((R2 & R2_CLOCKMASK) != 0) ^
>> +                   ((R4 & R3_R4_CLOCKMASK) != 0))
>> +                       N3 = clock(R3, R3_LEN, MASK_R3);
>> +
>> +               /* Check whether any registers are zero after 11 
>> pre-ciphering
>> +                * steps. If a register is all-zero after 11 steps, 
>> set input
>> +                * bit to one (see U.S. patent 5608802)
>> +                */
>> +               if (i == 11) {
>> +                       if (!R1)
>> +                               N1 ^= (1 << (R1_LEN - 1));
>> +                       if (!R2)
>> +                               N2 ^= (1 << (R2_LEN - 1));
>> +                       if (!R3)
>> +                               N3 ^= (1 << (R3_LEN - 1));
>> +                       if (!R4)
>> +                               R4 ^= (1 << (R4_LEN - 1));
>> +               }
>> +
>> +               N1 = clock(N1, R1_LEN, MASK_R1);
>> +               R1 = clock(N1, R1_LEN, MASK_R1);
>> +               N2 = clock(N2, R2_LEN, MASK_R2);
>> +               R2 = clock(N2, R2_LEN, MASK_R2);
>> +               N3 = clock(N3, R3_LEN, MASK_R3);
>> +               R3 = clock(N3, R3_LEN, MASK_R3);
>> +               R4 = clock(R4, R4_LEN, MASK_R4);
>> +               R4 = clock(R4, R4_LEN, MASK_R4);
>> +               R4 = clock(R4, R4_LEN, MASK_R4);
>> +
>> +               if (i >= 40)
>> +                       output[(i - 40) / 8] |= ((COMB) << (7 - ((i - 
>> 40) & 7)));
>> +       }
>> +}
>> diff --git a/target/linux/generic/files/net/dect/identities.c 
>> b/target/linux/generic/files/net/dect/identities.c
>> new file mode 100644
>> index 0000000..64438ef
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/identities.c
>> @@ -0,0 +1,221 @@
>> +/*
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +
>> +bool dect_ari_masked_cmp(const struct dect_ari *a1, const struct 
>> dect_ari *a2,
>> +                        const struct dect_ari *m)
>> +{
>> +       /* An empty class mask implies a wildcard for everything */
>> +       if (!m->arc)
>> +               return false;
>> +       if (a1->arc != a2->arc)
>> +               return true;
>> +
>> +       if ((a1->fpn ^ a2->fpn) & m->fpn)
>> +               return true;
>> +
>> +       switch (a1->arc) {
>> +       case DECT_ARC_A:
>> +               return  ((a1->emc ^ a2->emc) & m->emc);
>> +       case DECT_ARC_B:
>> +               return (((a1->eic ^ a2->eic) & m->eic) |
>> +                       ((a1->fps ^ a2->fps) & m->fps));
>> +       case DECT_ARC_C:
>> +               return (((a1->poc ^ a2->poc) & m->poc) |
>> +                       ((a1->fps ^ a2->fps) & m->fps));
>> +       case DECT_ARC_D:
>> +               return  ((a1->gop ^ a2->gop) & m->gop);
>> +       case DECT_ARC_E:
>> +               return  ((a1->fil ^ a2->fil) & m->fil);
>> +       default:
>> +               return true;
>> +       }
>> +}
>> +EXPORT_SYMBOL_GPL(dect_ari_masked_cmp);;
>> +
>> +bool dect_ari_cmp(const struct dect_ari *a1, const struct dect_ari 
>> *a2)
>> +{
>> +       static const struct dect_ari mask = {
>> +               .arc = ~0,
>> +               .fpn = ~0,
>> +               .fps = ~0,
>> +               { ~0 }
>> +       };
>> +       return dect_ari_masked_cmp(a1, a2, &mask);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_ari_cmp);
>> +
>> +u8 dect_parse_ari(struct dect_ari *ari, u64 a)
>> +{
>> +       ari->arc = (a & DECT_ARI_ARC_MASK) >> DECT_ARI_ARC_SHIFT;
>> +       switch (ari->arc) {
>> +       case DECT_ARC_A:
>> +               ari->emc = (a & DECT_ARI_A_EMC_MASK) >> 
>> DECT_ARI_A_EMC_SHIFT;
>> +               ari->fpn = (a & DECT_ARI_A_FPN_MASK) >> 
>> DECT_ARI_A_FPN_SHIFT;
>> +               return DECT_ARC_A_LEN;
>> +       case DECT_ARC_B:
>> +               ari->eic = (a & DECT_ARI_B_EIC_MASK) >> 
>> DECT_ARI_B_EIC_SHIFT;
>> +               ari->fpn = (a & DECT_ARI_B_FPN_MASK) >> 
>> DECT_ARI_B_FPN_SHIFT;
>> +               ari->fps = (a & DECT_ARI_B_FPS_MASK) >> 
>> DECT_ARI_B_FPS_SHIFT;
>> +               return DECT_ARC_B_LEN;
>> +       case DECT_ARC_C:
>> +               ari->poc = (a & DECT_ARI_C_POC_MASK) >> 
>> DECT_ARI_C_POC_SHIFT;
>> +               ari->fpn = (a & DECT_ARI_C_FPN_MASK) >> 
>> DECT_ARI_C_FPN_SHIFT;
>> +               ari->fps = (a & DECT_ARI_C_FPS_MASK) >> 
>> DECT_ARI_C_FPS_SHIFT;
>> +               return DECT_ARC_C_LEN;
>> +       case DECT_ARC_D:
>> +               ari->gop = (a & DECT_ARI_D_GOP_MASK) >> 
>> DECT_ARI_D_GOP_SHIFT;
>> +               ari->fpn = (a & DECT_ARI_D_FPN_MASK) >> 
>> DECT_ARI_D_FPN_SHIFT;
>> +               return DECT_ARC_D_LEN;
>> +       case DECT_ARC_E:
>> +               ari->fil = (a & DECT_ARI_E_FIL_MASK) >> 
>> DECT_ARI_E_FIL_SHIFT;
>> +               ari->fpn = (a & DECT_ARI_E_FPN_MASK) >> 
>> DECT_ARI_E_FPN_SHIFT;
>> +               return DECT_ARC_E_LEN;
>> +       default:
>> +               return 0;
>> +       }
>> +}
>> +EXPORT_SYMBOL_GPL(dect_parse_ari);
>> +
>> +u64 dect_build_ari(const struct dect_ari *ari)
>> +{
>> +       u64 a = 0;
>> +
>> +       a |= (u64)ari->arc << DECT_ARI_ARC_SHIFT;
>> +       switch (ari->arc) {
>> +       case DECT_ARC_A:
>> +               a |= (u64)ari->emc << DECT_ARI_A_EMC_SHIFT;
>> +               a |= (u64)ari->fpn << DECT_ARI_A_FPN_SHIFT;
>> +               break;
>> +       case DECT_ARC_B:
>> +               a |= (u64)ari->eic << DECT_ARI_B_EIC_SHIFT;
>> +               a |= (u64)ari->fpn << DECT_ARI_B_FPN_SHIFT;
>> +               a |= (u64)ari->fps << DECT_ARI_B_FPS_SHIFT;
>> +               break;
>> +       case DECT_ARC_C:
>> +               a |= (u64)ari->poc << DECT_ARI_C_POC_SHIFT;
>> +               a |= (u64)ari->fpn << DECT_ARI_C_FPN_SHIFT;
>> +               a |= (u64)ari->fps << DECT_ARI_C_FPS_SHIFT;
>> +               break;
>> +       case DECT_ARC_D:
>> +               a |= (u64)ari->gop << DECT_ARI_D_GOP_SHIFT;
>> +               a |= (u64)ari->fpn << DECT_ARI_D_FPN_SHIFT;
>> +               break;
>> +       case DECT_ARC_E:
>> +               a |= (u64)ari->fil << DECT_ARI_E_FIL_SHIFT;
>> +               a |= (u64)ari->fpn << DECT_ARI_E_FPN_SHIFT;
>> +               break;
>> +       }
>> +       return a;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_build_ari);
>> +
>> +u64 dect_build_rfpi(const struct dect_idi *idi)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= idi->e ? DECT_RFPI_E_FLAG : 0;
>> +       t |= dect_build_ari(&idi->pari) >> DECT_RFPI_ARI_SHIFT;
>> +       t |= (u64)idi->rpn << DECT_RFPI_RPN_SHIFT;
>> +       return t;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_build_rfpi);
>> +
>> +bool dect_rfpi_cmp(const struct dect_idi *i1, const struct dect_idi 
>> *i2)
>> +{
>> +       return dect_ari_cmp(&i1->pari, &i2->pari) ||
>> +              i1->rpn != i2->rpn ||
>> +              i1->e   != i2->e;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_rfpi_cmp);
>> +
>> +u16 dect_build_fmid(const struct dect_idi *idi)
>> +{
>> +       u64 rfpi;
>> +
>> +       rfpi = dect_build_rfpi(idi);
>> +       rfpi >>= (sizeof(rfpi) - DECT_NT_ID_RFPI_LEN - 1) * 
>> BITS_PER_BYTE;
>> +       return rfpi & DECT_FMID_MASK;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_build_fmid);
>> +
>> +/*
>> + * PMID (Portable MAC Identity)
>> + */
>> +
>> +void dect_parse_pmid(struct dect_pmid *pmid, u32 p)
>> +{
>> +       if ((p & DECT_PMID_DEFAULT_ID_MASK) == DECT_PMID_DEFAULT_ID) {
>> +               pmid->type = DECT_PMID_DEFAULT;
>> +               pmid->num  = p & DECT_PMID_DEFAULT_NUM_MASK;
>> +       } else if ((p & DECT_PMID_EMERGENCY_ID_MASK) == 
>> DECT_PMID_EMERGENCY_ID) {
>> +               pmid->type = DECT_PMID_EMERGENCY;
>> +               pmid->tpui = p & DECT_PMID_EMERGENCY_TPUI_MASK;
>> +       } else {
>> +               pmid->type = DECT_PMID_ASSIGNED;
>> +               pmid->tpui = p & DECT_PMID_ASSIGNED_TPUI_MASK;
>> +       }
>> +}
>> +EXPORT_SYMBOL_GPL(dect_parse_pmid);
>> +
>> +u32 dect_build_pmid(const struct dect_pmid *pmid)
>> +{
>> +       u32 p = 0;
>> +
>> +       switch (pmid->type) {
>> +       case DECT_PMID_DEFAULT:
>> +               p |= DECT_PMID_DEFAULT_ID;
>> +               p |= pmid->tpui;
>> +               break;
>> +       case DECT_PMID_EMERGENCY:
>> +               p |= DECT_PMID_EMERGENCY_ID;
>> +               p |= pmid->tpui;
>> +               break;
>> +       case DECT_PMID_ASSIGNED:
>> +               p |= pmid->tpui;
>> +               break;
>> +       }
>> +       return p;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_build_pmid);
>> +
>> +bool dect_pmid_cmp(const struct dect_pmid *p1, const struct dect_pmid 
>> *p2)
>> +{
>> +       return memcmp(p1, p2, sizeof(*p1));
>> +}
>> +EXPORT_SYMBOL(dect_pmid_cmp);
>> +
>> +/**
>> + * dect_parse_mci - Extract the MCI elements from a packed MCI in a
>> + *                 struct sockaddr_dect_lu
>> + *
>> + * The packed MCI is build from ARI + PMID + LCN
>> + */
>> +int dect_parse_mci(struct dect_mci *mci, u64 m)
>> +{
>> +       u32 p;
>> +       u8 len;
>> +
>> +       len = dect_parse_ari(&mci->ari, m);
>> +
>> +       len += DECT_PMID_SIZE;
>> +       p = (m >> (sizeof(m) * BITS_PER_BYTE - len)) & DECT_PMID_MASK;
>> +       dect_parse_pmid(&mci->pmid, p);
>> +
>> +       len += DECT_ECN_SIZE;
>> +       mci->lcn = (m >> (sizeof(m) * BITS_PER_BYTE - len)) & 
>> DECT_LCN_MASK;
>> +       return 0;
>> +}
>> +
>> +u64 dect_build_mci(const struct dect_mci *mci)
>> +{
>> +       return 0;
>> +}
>> diff --git a/target/linux/generic/files/net/dect/mac_ccf.c 
>> b/target/linux/generic/files/net/dect/mac_ccf.c
>> new file mode 100644
>> index 0000000..6445829
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/mac_ccf.c
>> @@ -0,0 +1,2070 @@
>> +/*
>> + * DECT MAC Cluster Control Functions
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_ccf.h>
>> +#include <net/dect/mac_csf.h>
>> +#include <net/dect/ccp.h>
>> +
>> +MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
>> +MODULE_DESCRIPTION("DECT MAC Layer");
>> +MODULE_LICENSE("GPL");
>> +
>> +static void dect_llme_scan_result_notify(const struct dect_cluster 
>> *cl,
>> +                                        const struct dect_scan_result 
>> *res);
>> +static void dect_llme_mac_info_ind(const struct dect_cluster *cl,
>> +                                  const struct dect_idi *idi,
>> +                                  const struct dect_si *si);
>> +
>> +static struct dect_cluster *dect_cluster_get_by_name(const struct 
>> nlattr *nla)
>> +{
>> +       struct dect_cluster *cl;
>> +
>> +       list_for_each_entry(cl, &dect_cluster_list, list) {
>> +               if (!nla_strcmp(nla, cl->name))
>> +                       return cl;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static struct dect_cluster *dect_cluster(const struct 
>> dect_cluster_handle *clh)
>> +{
>> +       return container_of(clh, struct dect_cluster, handle);
>> +}
>> +
>> +static struct dect_cell_handle *
>> +dect_cluster_get_cell_by_rpn(struct dect_cluster *cl, u8 rpn)
>> +{
>> +       struct dect_cell_handle *ch;
>> +
>> +       list_for_each_entry(ch, &cl->cells, list) {
>> +               if (ch->rpn == rpn)
>> +                       return ch;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +/*
>> + * MAC CCF layer timers
>> + */
>> +
>> +static u8 dect_framenum(const struct dect_cluster *cl, enum 
>> dect_timer_bases b)
>> +{
>> +       return __dect_framenum(&cl->timer_base[b]);
>> +}
>> +
>> +static void dect_run_timers(struct dect_cluster *cl, enum 
>> dect_timer_bases b)
>> +{
>> +       __dect_run_timers(cl->name, &cl->timer_base[b]);
>> +}
>> +
>> +static void dect_timer_base_update(struct dect_cluster *cl,
>> +                                  enum dect_timer_bases base,
>> +                                  u32 mfn, u8 framenum, u8 slot)
>> +{
>> +       cl->timer_base[base].mfn      = mfn;
>> +       cl->timer_base[base].framenum = framenum;
>> +       cl->timer_base[base].slot     = slot;
>> +}
>> +
>> +static void dect_timer_add(struct dect_cluster *cl, struct dect_timer 
>> *timer,
>> +                          enum dect_timer_bases b, u32 frame, u8 
>> slot)
>> +{
>> +       timer->cluster = cl;
>> +       __dect_timer_add(cl->name, &cl->timer_base[b], timer, frame, 
>> slot);
>> +}
>> +
>> +static void dect_timer_setup(struct dect_timer *timer,
>> +                            void (*func)(struct dect_cluster *, void 
>> *),
>> +                            void *data)
>> +{
>> +       dect_timer_init(timer);
>> +       timer->cb.cluster = func;
>> +       timer->data       = data;
>> +}
>> +
>> +static void dect_ccf_time_ind(struct dect_cluster_handle *clh,
>> +                             enum dect_timer_bases base,
>> +                             u32 mfn, u8 framenum, u8 slot)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +
>> +       if (base == DECT_TIMER_TX) {
>> +               dect_timer_base_update(cl, base, mfn, framenum, slot);
>> +               dect_run_timers(cl, base);
>> +       } else {
>> +               dect_run_timers(cl, base);
>> +               dect_timer_base_update(cl, base, mfn, framenum, slot);
>> +       }
>> +}
>> +
>> +static void dect_scan_report(const struct dect_cluster_handle *clh,
>> +                            const struct dect_scan_result *res)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +
>> +       dect_llme_scan_result_notify(cl, res);
>> +}
>> +
>> +static void dect_mac_info_ind(const struct dect_cluster_handle *clh,
>> +                             const struct dect_idi *idi,
>> +                             const struct dect_si *si)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +
>> +       pr_debug("cl %p: MAC_INFO-ind: rpn: %u\n", cl, idi->rpn);
>> +       cl->si  = *si;
>> +       cl->rpn = idi->rpn;
>> +
>> +       dect_llme_mac_info_ind(cl, idi, &cl->si);
>> +}
>> +
>> +/*
>> + * Broadcast message control
>> + */
>> +
>> +/**
>> + * dect_bmc_mac_page_req - queue one segment of B_S channel data
>> + *
>> + * @cl:                DECT cluster
>> + * @skb:       SDU
>> + */
>> +void dect_bmc_mac_page_req(struct dect_cluster *cl, struct sk_buff 
>> *skb)
>> +{
>> +       const struct dect_cell_handle *ch, *prev = NULL;
>> +       struct sk_buff *clone;
>> +
>> +       BUG_ON(cl->mode != DECT_MODE_FP);
>> +
>> +       list_for_each_entry(ch, &cl->cells, list) {
>> +               if (prev != NULL) {
>> +                       clone = skb_clone(skb, GFP_ATOMIC);
>> +                       if (clone != NULL)
>> +                               prev->ops->page_req(prev, clone);
>> +               }
>> +               prev = ch;
>> +       }
>> +       if (prev != NULL)
>> +               prev->ops->page_req(prev, skb);
>> +}
>> +
>> +static void dect_bmc_page_ind(const struct dect_cluster_handle *clh,
>> +                             struct sk_buff *skb)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +
>> +       return dect_mac_page_ind(cl, skb);
>> +}
>> +
>> +/*
>> + * Multi-Bearer Control
>> + */
>> +
>> +#define mbc_debug(mbc, fmt, args...) \
>> +       pr_debug("MBC (MCEI %u/%s): " fmt, \
>> +                (mbc)->id.mcei, dect_mbc_states[(mbc)->state], ## 
>> args);
>> +
>> +static const char * const dect_mbc_states[] = {
>> +       [DECT_MBC_NONE]         = "NONE",
>> +       [DECT_MBC_INITIATED]    = "INITIATED",
>> +       [DECT_MBC_ESTABLISHED]  = "ESTABLISHED",
>> +       [DECT_MBC_RELEASED]     = "RELEASED",
>> +};
>> +
>> +static void dect_mbc_hold(struct dect_mbc *mbc)
>> +{
>> +       mbc->refcnt++;
>> +}
>> +
>> +static void dect_mbc_put(struct dect_mbc *mbc)
>> +{
>> +       if (--mbc->refcnt > 0)
>> +               return;
>> +       kfree(mbc);
>> +}
>> +
>> +static struct dect_tb *dect_mbc_tb_get_by_tbei(const struct dect_mbc 
>> *mbc,
>> +                                              const struct 
>> dect_tbc_id *id)
>> +{
>> +       struct dect_tb *tb;
>> +
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               if (tb->id.tbei == id->tbei)
>> +                       return tb;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static struct dect_mbc *dect_mbc_get_by_tbc_id(const struct 
>> dect_cluster *cl,
>> +                                              const struct 
>> dect_tbc_id *id)
>> +{
>> +       struct dect_mbc *mbc;
>> +
>> +       list_for_each_entry(mbc, &cl->mbcs, list) {
>> +               if (!memcmp(&mbc->id.ari, &id->ari, sizeof(id->ari)) 
>> &&
>> +                   !memcmp(&mbc->id.pmid, &id->pmid, 
>> sizeof(id->pmid)) &&
>> +                   mbc->id.ecn == id->ecn)
>> +                       return mbc;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static struct dect_mbc *dect_mbc_get_by_mcei(const struct 
>> dect_cluster *cl, u32 mcei)
>> +{
>> +       struct dect_mbc *mbc;
>> +
>> +       list_for_each_entry(mbc, &cl->mbcs, list) {
>> +               if (mbc->id.mcei == mcei)
>> +                       return mbc;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +u32 dect_mbc_alloc_mcei(struct dect_cluster *cl)
>> +{
>> +       u32 mcei;
>> +
>> +       while (1) {
>> +               mcei = ++cl->mcei_rover;
>> +               if (mcei == 0)
>> +                       continue;
>> +               if (dect_mbc_get_by_mcei(cl, mcei))
>> +                       continue;
>> +               return mcei;
>> +       }
>> +}
>> +
>> +static bool dect_ct_tail_allowed(const struct dect_cluster *cl, u8 
>> framenum)
>> +{
>> +       if (cl->mode == DECT_MODE_FP)
>> +               return (framenum & 0x1) == 0x1;
>> +       else
>> +               return (framenum & 0x1) == 0x0;
>> +}
>> +
>> +/*
>> + * MBC normal receive half frame timer:
>> + *
>> + * Deliver received data segments to the DLC at half frame 
>> boundaries.
>> + * Data is delivered for the following channels:
>> + *
>> + * - C_S after an ARQ window
>> + * - I_N normal delay
>> + *
>> + * Additionally in half frames that end an ARQ window, acknowledgment
>> + * of C_S segment reception of the preceeding transmit half frame is
>> + * verified.
>> + */
>> +static void dect_mbc_normal_rx_timer(struct dect_cluster *cl, void 
>> *data)
>> +{
>> +       struct dect_mbc *mbc = data;
>> +       struct dect_tb *tb;
>> +       struct sk_buff *skb;
>> +
>> +       mbc_debug(mbc, "Normal RX timer\n");
>> +       dect_mbc_hold(mbc);
>> +
>> +       if (mbc->cs_rx_skb != NULL) {
>> +               skb = mbc->cs_rx_skb;
>> +               mbc->cs_rx_skb = NULL;
>> +               mbc->stats.cs_rx_bytes += skb->len;
>> +               dect_mac_co_data_ind(cl, mbc->id.mcei, DECT_MC_C_S, 
>> skb);
>> +
>> +               /* C-channel reception might trigger release of the 
>> MBC in case
>> +                * it acknowledges the last outstanding LAPC I-frame. 
>> */
>> +               if (mbc->state == DECT_MBC_RELEASED)
>> +                       goto out;
>> +       }
>> +
>> +       if (mbc->cs_tx_ok && mbc->cs_rx_ok) {
>> +               mbc->stats.cs_tx_bytes += mbc->cs_tx_skb->len;
>> +               kfree_skb(mbc->cs_tx_skb);
>> +               mbc->cs_tx_skb = NULL;
>> +               mbc->cs_tx_ok  = false;
>> +       }
>> +       mbc->cs_rx_ok = false;
>> +
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               if (tb->b_rx_skb == NULL)
>> +                       continue;
>> +               skb = tb->b_rx_skb;
>> +               tb->b_rx_skb = NULL;
>> +               mbc->stats.i_rx_bytes += skb->len;
>> +               dect_mac_co_data_ind(cl, mbc->id.mcei, DECT_MC_I_N, 
>> skb);
>> +       }
>> +
>> +       dect_timer_add(cl, &mbc->normal_rx_timer, DECT_TIMER_RX,
>> +                      1, dect_normal_receive_end(cl->mode));
>> +out:
>> +       dect_mbc_put(mbc);
>> +}
>> +
>> +/*
>> + * MBC slot based receive timer:
>> + *
>> + * Deliver received I_N minimal delay B-field segments to the DLC.
>> + */
>> +static void dect_mbc_slot_rx_timer(struct dect_cluster *cl, void 
>> *data)
>> +{
>> +       struct dect_tb *tb = data;
>> +       struct dect_mbc *mbc = tb->mbc;
>> +       struct sk_buff *skb;
>> +
>> +       mbc_debug(mbc, "Slot RX timer: TBEI: %u LBN: %u slot: %u\n",
>> +                 tb->id.tbei, tb->id.lbn, tb->rx_slot);
>> +
>> +       if (tb->b_rx_skb != NULL) {
>> +               skb = tb->b_rx_skb;
>> +               tb->b_rx_skb = NULL;
>> +               mbc->stats.i_rx_bytes += skb->len;
>> +               dect_mac_co_data_ind(cl, mbc->id.mcei, DECT_MC_I_N, 
>> skb);
>> +       }
>> +
>> +       dect_timer_add(cl, &tb->slot_rx_timer, DECT_TIMER_RX, 1, 
>> tb->rx_slot);
>> +}
>> +
>> +/*
>> + * MBC normal transmit half frame timer:
>> + *
>> + * Request data from the DLC for the next frame. Data is requested 
>> for the
>> + * following channels:
>> + *
>> + * - C_S before an ARQ window starts
>> + * - I_N normal delay
>> + */
>> +static void dect_mbc_normal_tx_timer(struct dect_cluster *cl, void 
>> *data)
>> +{
>> +       const struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc = data;
>> +       struct dect_tb *tb;
>> +       struct sk_buff *skb;
>> +
>> +       mbc_debug(mbc, "Normal TX timer\n");
>> +
>> +       if (dect_ct_tail_allowed(cl, dect_framenum(cl, 
>> DECT_TIMER_TX))) {
>> +               if (mbc->cs_tx_skb == NULL) {
>> +                       skb = dect_mac_co_dtr_ind(cl, mbc->id.mcei, 
>> DECT_MC_C_S);
>> +                       if (skb != NULL) {
>> +                               DECT_CS_CB(skb)->seq = mbc->cs_tx_seq;
>> +                               mbc->cs_tx_seq = !mbc->cs_tx_seq;
>> +                               mbc->cs_tx_skb = skb;
>> +                       }
>> +               }
>> +
>> +               if (mbc->cs_tx_skb != NULL) {
>> +                       list_for_each_entry(tb, &mbc->tbs, list) {
>> +                               skb = skb_clone(mbc->cs_tx_skb, 
>> GFP_ATOMIC);
>> +                               if (skb == NULL)
>> +                                       continue;
>> +                               ch = tb->ch;
>> +                               ch->ops->tbc_data_req(ch, &tb->id, 
>> DECT_MC_C_S, skb);
>> +                               mbc->cs_tx_ok = true;
>> +                       }
>> +               }
>> +       }
>> +
>> +       if (mbc->service != DECT_SERVICE_IN_MIN_DELAY) {
>> +               list_for_each_entry(tb, &mbc->tbs, list) {
>> +                       ch = tb->ch;
>> +                       skb = dect_mac_co_dtr_ind(cl, mbc->id.mcei, 
>> DECT_MC_I_N);
>> +                       if (skb != NULL) {
>> +                               mbc->stats.i_tx_bytes += skb->len;
>> +                               ch->ops->tbc_data_req(ch, &tb->id, 
>> DECT_MC_I_N, skb);
>> +                       }
>> +               }
>> +       }
>> +
>> +       dect_timer_add(cl, &mbc->normal_tx_timer, DECT_TIMER_TX,
>> +                      1, dect_normal_transmit_base(cl->mode));
>> +}
>> +
>> +/*
>> + * MBC slot based transmit timer:
>> + *
>> + * Request data from the DLC for the I_N minimal delay channel.
>> + */
>> +static void dect_mbc_slot_tx_timer(struct dect_cluster *cl, void 
>> *data)
>> +{
>> +       struct dect_tb *tb = data;
>> +       struct dect_mbc *mbc = tb->mbc;
>> +       const struct dect_cell_handle *ch = tb->ch;
>> +       struct sk_buff *skb;
>> +
>> +       mbc_debug(mbc, "Slot TX timer: TBEI: %u LBN: %u slot: %u\n",
>> +                 tb->id.tbei, tb->id.lbn, tb->tx_slot);
>> +
>> +       skb = dect_mac_co_dtr_ind(cl, mbc->id.mcei, DECT_MC_I_N);
>> +       if (skb != NULL) {
>> +               mbc->stats.i_tx_bytes += skb->len;
>> +               ch->ops->tbc_data_req(ch, &tb->id, DECT_MC_I_N, skb);
>> +       }
>> +       dect_timer_add(cl, &tb->slot_tx_timer, DECT_TIMER_TX, 1, 
>> tb->tx_slot);
>> +}
>> +
>> +static int dect_mbc_complete_setup(struct dect_cluster *cl, struct 
>> dect_mbc *mbc)
>> +{
>> +       if (!del_timer(&mbc->timer))
>> +               return 0;
>> +
>> +       dect_timer_add(cl, &mbc->normal_rx_timer, DECT_TIMER_RX,
>> +                      0, dect_normal_receive_end(cl->mode));
>> +       dect_timer_add(cl, &mbc->normal_tx_timer, DECT_TIMER_TX,
>> +                      0, dect_normal_transmit_base(cl->mode));
>> +       mbc->state = DECT_MBC_ESTABLISHED;
>> +
>> +       return 1;
>> +}
>> +
>> +static void dect_mbc_tb_release(struct dect_tb *tb);
>> +
>> +static void dect_mbc_tb_handover_timer(struct dect_cluster *cl, void 
>> *data)
>> +{
>> +       struct dect_tb *tb = data, *tb1, *i;
>> +       struct dect_mbc *mbc = tb->mbc;
>> +
>> +       mbc_debug(mbc, "Handover timer: TBEI: %u LBN: %u\n",
>> +                 tb->id.tbei, tb->id.lbn);
>> +
>> +       tb1 = NULL;
>> +       list_for_each_entry(i, &mbc->tbs, list) {
>> +               if (i->id.lbn == tb->id.lbn) {
>> +                       tb1 = i;
>> +                       break;
>> +               }
>> +       }
>> +       if (tb1 == NULL)
>> +               return;
>> +
>> +       tb1->ch->ops->tbc_dis_req(tb1->ch, &tb1->id,
>> +                                 
>> DECT_REASON_BEARER_HANDOVER_COMPLETED);
>> +       list_del(&tb1->list);
>> +       dect_mbc_tb_release(tb1);
>> +       mbc->stats.handovers++;
>> +}
>> +
>> +static void dect_mbc_tb_complete_setup(struct dect_cluster *cl, 
>> struct dect_tb *tb)
>> +{
>> +       if (cl->mode == DECT_MODE_FP && tb->handover)
>> +               dect_timer_add(cl, &tb->handover_timer, DECT_TIMER_RX,
>> +                              DECT_MBC_TB_HANDOVER_TIMEOUT, 
>> tb->rx_slot);
>> +
>> +       if (tb->mbc->service == DECT_SERVICE_IN_MIN_DELAY) {
>> +               dect_timer_add(cl, &tb->slot_rx_timer, DECT_TIMER_RX,
>> +                              0, tb->rx_slot);
>> +               dect_timer_add(cl, &tb->slot_tx_timer, DECT_TIMER_TX,
>> +                              0, tb->tx_slot);
>> +       }
>> +}
>> +
>> +static void dect_mbc_tb_release(struct dect_tb *tb)
>> +{
>> +       dect_timer_del(&tb->handover_timer);
>> +       dect_timer_del(&tb->slot_rx_timer);
>> +       dect_timer_del(&tb->slot_tx_timer);
>> +       kfree(tb);
>> +}
>> +
>> +static struct dect_tb *dect_mbc_tb_init(struct dect_mbc *mbc,
>> +                                       const struct dect_cell_handle 
>> *ch, u8 lbn)
>> +{
>> +       struct dect_tb *tb;
>> +
>> +       tb = kzalloc(sizeof(*tb), GFP_ATOMIC);
>> +       if (tb == NULL)
>> +               return NULL;
>> +
>> +       tb->mbc      = mbc;
>> +       tb->ch       = ch;
>> +       tb->id.ari   = mbc->id.ari;
>> +       tb->id.pmid  = mbc->id.pmid;
>> +       tb->id.ecn   = 0;
>> +       tb->id.lbn   = lbn;
>> +       tb->id.tbei  = 0;
>> +       tb->handover = false;
>> +       tb->rx_slot  = 0;
>> +       tb->tx_slot  = 0;
>> +
>> +       dect_timer_setup(&tb->handover_timer, 
>> dect_mbc_tb_handover_timer, tb);
>> +       dect_timer_setup(&tb->slot_rx_timer, dect_mbc_slot_rx_timer, 
>> tb);
>> +       dect_timer_setup(&tb->slot_tx_timer, dect_mbc_slot_tx_timer, 
>> tb);
>> +
>> +       return tb;
>> +}
>> +
>> +static void dect_mbc_release(struct dect_mbc *mbc)
>> +{
>> +       struct dect_tb *tb, *next;
>> +
>> +       mbc_debug(mbc, "release\n");
>> +       mbc->state = DECT_MBC_RELEASED;
>> +       del_timer(&mbc->timer);
>> +       list_del(&mbc->list);
>> +
>> +       dect_timer_del(&mbc->normal_rx_timer);
>> +       dect_timer_del(&mbc->normal_tx_timer);
>> +
>> +       list_for_each_entry_safe(tb, next, &mbc->tbs, list)
>> +               dect_mbc_tb_release(tb);
>> +
>> +       kfree_skb(mbc->cs_rx_skb);
>> +       kfree_skb(mbc->cs_tx_skb);
>> +       dect_mbc_put(mbc);
>> +}
>> +
>> +static void dect_mbc_timeout(unsigned long data)
>> +{
>> +       struct dect_mbc *mbc = (struct dect_mbc *)data;
>> +       struct dect_tb *tb;
>> +       enum dect_release_reasons reason;
>> +
>> +       mbc_debug(mbc, "timeout\n");
>> +       reason = DECT_REASON_BEARER_SETUP_OR_HANDOVER_FAILED;
>> +
>> +       list_for_each_entry(tb, &mbc->tbs, list)
>> +               tb->ch->ops->tbc_dis_req(tb->ch, &tb->id, reason);
>> +
>> +       if (mbc->state != DECT_MBC_NONE)
>> +               dect_mac_dis_ind(mbc->cl, mbc->id.mcei, reason);
>> +
>> +       dect_mbc_release(mbc);
>> +}
>> +
>> +static struct dect_mbc *dect_mbc_init(struct dect_cluster *cl,
>> +                                     const struct dect_mbc_id *id)
>> +{
>> +       struct dect_mbc *mbc;
>> +
>> +       mbc = kzalloc(sizeof(*mbc), GFP_ATOMIC);
>> +       if (mbc == NULL)
>> +               return NULL;
>> +       mbc->refcnt   = 1;
>> +       mbc->cl       = cl;
>> +       mbc->id       = *id;
>> +       mbc->state    = DECT_MBC_NONE;
>> +       mbc->ho_stamp = jiffies - DECT_MBC_HANDOVER_TIMER;
>> +
>> +       INIT_LIST_HEAD(&mbc->tbs);
>> +       dect_timer_setup(&mbc->normal_rx_timer, 
>> dect_mbc_normal_rx_timer, mbc);
>> +       dect_timer_setup(&mbc->normal_tx_timer, 
>> dect_mbc_normal_tx_timer, mbc);
>> +
>> +       mbc->cs_tx_seq = 1;
>> +       mbc->cs_rx_seq = 1;
>> +
>> +       setup_timer(&mbc->timer, dect_mbc_timeout, (unsigned 
>> long)mbc);
>> +       list_add_tail(&mbc->list, &cl->mbcs);
>> +       return mbc;
>> +}
>> +
>> +static int dect_mbc_tb_setup(struct dect_mbc *mbc, struct dect_tb 
>> *tb)
>> +{
>> +       const struct dect_cell_handle *ch = tb->ch;
>> +       struct dect_channel_desc chd;
>> +       int err;
>> +
>> +       memset(&chd, 0, sizeof(chd));
>> +       chd.pkt   = DECT_PACKET_P32;
>> +       chd.b_fmt = DECT_B_UNPROTECTED;
>> +
>> +       err = ch->ops->tbc_establish_req(ch, &tb->id, &chd,
>> +                                        DECT_SERVICE_IN_MIN_DELAY,
>> +                                        tb->handover);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       mbc->setup_cnt++;
>> +       return 0;
>> +}
>> +
>> +/**
>> + * dect_mac_con_req - request a new MAC connection
>> + *
>> + * @cl:                DECT cluster
>> + * @id:                MBC identifier
>> + */
>> +int dect_mac_con_req(struct dect_cluster *cl, const struct 
>> dect_mbc_id *id)
>> +{
>> +       struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +       int err;
>> +
>> +       err = -EHOSTUNREACH;
>> +       ch = dect_cluster_get_cell_by_rpn(cl, 0);
>> +       if (ch == NULL)
>> +               goto err1;
>> +
>> +       err = -ENOMEM;
>> +       mbc = dect_mbc_init(cl, id);
>> +       if (mbc == NULL)
>> +               goto err1;
>> +       mbc->state = DECT_MBC_INITIATED;
>> +       mbc_debug(mbc, "MAC_CON-req\n");
>> +
>> +       tb = dect_mbc_tb_init(mbc, ch, 0xf);
>> +       if (tb == NULL)
>> +               goto err2;
>> +
>> +       err = dect_mbc_tb_setup(mbc, tb);
>> +       if (err < 0)
>> +               goto err3;
>> +
>> +       list_add_tail(&tb->list, &mbc->tbs);
>> +       mod_timer(&mbc->timer, jiffies + DECT_MBC_SETUP_TIMEOUT);
>> +       return 0;
>> +
>> +err3:
>> +       dect_mbc_tb_release(tb);
>> +err2:
>> +       dect_mbc_release(mbc);
>> +err1:
>> +       return err;
>> +}
>> +
>> +void dect_mac_dis_req(struct dect_cluster *cl, u32 mcei)
>> +{
>> +       const struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +
>> +       mbc = dect_mbc_get_by_mcei(cl, mcei);
>> +       if (mbc == NULL)
>> +               return;
>> +       mbc_debug(mbc, "MAC_DIS-req\n");
>> +
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               ch = tb->ch;
>> +               ch->ops->tbc_dis_req(ch, &tb->id, 
>> DECT_REASON_CONNECTION_RELEASE);
>> +       }
>> +
>> +       dect_mbc_release(mbc);
>> +}
>> +
>> +/* TBC establishment indication from CSF */
>> +static int dect_tbc_establish_ind(const struct dect_cluster_handle 
>> *clh,
>> +                                 const struct dect_cell_handle *ch,
>> +                                 const struct dect_tbc_id *id,
>> +                                 enum dect_mac_service_types service,
>> +                                 bool handover)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       struct dect_mbc_id mid;
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +       unsigned int cnt;
>> +       int err;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL) {
>> +               if (handover)
>> +                       return -ENOENT;
>> +
>> +               mid.mcei = dect_mbc_alloc_mcei(cl);
>> +               mid.type = 0;
>> +               mid.ari  = id->ari;
>> +               mid.pmid = id->pmid;
>> +               mid.ecn  = id->ecn;
>> +
>> +               err = -ENOMEM;
>> +               mbc = dect_mbc_init(cl, &mid);
>> +               if (mbc == NULL)
>> +                       goto err1;
>> +               mbc->service = service;
>> +       } else {
>> +               if (!handover)
>> +                       return -EEXIST;
>> +
>> +               cnt = 0;
>> +               list_for_each_entry(tb, &mbc->tbs, list) {
>> +                       if (tb->id.lbn == id->lbn)
>> +                               cnt++;
>> +               }
>> +               if (cnt > 1)
>> +                       return -EEXIST;
>> +
>> +               if (mbc->cipher_state == DECT_CIPHER_ENABLED) {
>> +                       err = ch->ops->tbc_enc_req(ch, id, mbc->ck);
>> +                       if (err < 0)
>> +                               return err;
>> +               }
>> +       }
>> +
>> +       mbc_debug(mbc, "TBC_ESTABLISH-ind: TBEI: %u LBN: %u H/O: 
>> %u\n",
>> +                 id->tbei, id->lbn, handover);
>> +
>> +       err = -ENOMEM;
>> +       tb = dect_mbc_tb_init(mbc, ch, id->lbn);
>> +       if (tb == NULL)
>> +               goto err2;
>> +       tb->handover = handover;
>> +
>> +       err = ch->ops->tbc_establish_res(ch, id);
>> +       if (err < 0)
>> +               goto err3;
>> +
>> +       list_add_tail(&tb->list, &mbc->tbs);
>> +       if (!handover)
>> +               mod_timer(&mbc->timer, jiffies + 
>> DECT_MBC_SETUP_TIMEOUT);
>> +       return 0;
>> +
>> +err3:
>> +       dect_mbc_tb_release(tb);
>> +err2:
>> +       dect_mbc_release(mbc);
>> +err1:
>> +       return err;
>> +}
>> +
>> +static int dect_tbc_establish_cfm(const struct dect_cluster_handle 
>> *clh,
>> +                                 const struct dect_tbc_id *id, bool 
>> success,
>> +                                 u8 rx_slot)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       const struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb, *i;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL)
>> +               return -ENOENT;
>> +
>> +       mbc_debug(mbc, "TBC_ESTABLISH-cfm: TBEI: %u LBN: %u success: 
>> %d\n",
>> +                 id->tbei, id->lbn, success);
>> +
>> +       tb = NULL;
>> +       list_for_each_entry(i, &mbc->tbs, list) {
>> +               if (i->id.lbn  == id->lbn &&
>> +                   i->id.tbei == 0) {
>> +                       tb = i;
>> +                       break;
>> +               }
>> +       }
>> +       if (tb == NULL)
>> +               return -ENOENT;
>> +
>> +       if (success) {
>> +               tb->id.tbei = id->tbei;
>> +               tb->rx_slot = rx_slot;
>> +               tb->tx_slot = dect_tdd_slot(rx_slot);
>> +
>> +               switch (mbc->state) {
>> +               case DECT_MBC_NONE:
>> +                       if (!dect_mbc_complete_setup(cl, mbc))
>> +                               return 0;
>> +                       dect_mbc_tb_complete_setup(cl, tb);
>> +
>> +                       return dect_mac_con_ind(cl, &mbc->id, 
>> mbc->service);
>> +               case DECT_MBC_INITIATED:
>> +                       if (!dect_mbc_complete_setup(cl, mbc))
>> +                               return 0;
>> +                       dect_mbc_tb_complete_setup(cl, tb);
>> +
>> +                       return dect_mac_con_cfm(cl, mbc->id.mcei, 
>> mbc->service);
>> +               case DECT_MBC_ESTABLISHED:
>> +                       ch = tb->ch;
>> +                       if (mbc->cipher_state == DECT_CIPHER_ENABLED 
>> &&
>> +                           ch->ops->tbc_enc_req(ch, id, mbc->ck) < 0) 
>> {
>> +                               ch->ops->tbc_dis_req(ch, id, 
>> DECT_REASON_UNKNOWN);
>> +                               return -1;
>> +                       }
>> +                       dect_mbc_tb_complete_setup(cl, tb);
>> +                       return 0;
>> +               default:
>> +                       return WARN_ON(-1);
>> +               }
>> +       } else {
>> +               switch (mbc->state) {
>> +               case DECT_MBC_NONE:
>> +                       dect_mbc_release(mbc);
>> +                       return 0;
>> +               case DECT_MBC_INITIATED:
>> +                       if (mbc->setup_cnt > 
>> DECT_MBC_SETUP_MAX_ATTEMPTS ||
>> +                           dect_mbc_tb_setup(mbc, tb) < 0) {
>> +                               dect_mac_dis_ind(cl, mbc->id.mcei,
>> +                                       
>> DECT_REASON_BEARER_SETUP_OR_HANDOVER_FAILED);
>> +                               dect_mbc_release(mbc);
>> +                       }
>> +                       return 0;
>> +               case DECT_MBC_ESTABLISHED:
>> +                       list_del(&tb->list);
>> +                       dect_mbc_tb_release(tb);
>> +                       return 0;
>> +               default:
>> +                       return WARN_ON(-1);
>> +               }
>> +       }
>> +}
>> +
>> +static int dect_tbc_event_ind(const struct dect_cluster_handle *clh,
>> +                             const struct dect_tbc_id *id,
>> +                             enum dect_tbc_event event)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL)
>> +               return -ENOENT;
>> +       mbc_debug(mbc, "TBC_EVENT-ind: TBEI: %u LBN: %u event: %u\n",
>> +                 id->tbei, id->lbn, event);
>> +
>> +       tb = dect_mbc_tb_get_by_tbei(mbc, id);
>> +       if (tb == NULL)
>> +               return -ENOENT;
>> +
>> +       switch (event) {
>> +       case DECT_TBC_ACK_RECEIVED:
>> +               mbc->cs_rx_ok = true;
>> +               return 0;
>> +       case DECT_TBC_CIPHER_ENABLED:
>> +               mbc->cipher_state = DECT_TBC_CIPHER_ENABLED;
>> +               dect_mac_enc_eks_ind(cl, mbc->id.mcei, 
>> DECT_CIPHER_ENABLED);
>> +               return 0;
>> +       case DECT_TBC_CIPHER_DISABLED:
>> +               mbc->cipher_state = DECT_TBC_CIPHER_DISABLED;
>> +               dect_mac_enc_eks_ind(cl, mbc->id.mcei, 
>> DECT_CIPHER_DISABLED);
>> +               return 0;
>> +       default:
>> +               return WARN_ON(-1);
>> +       }
>> +}
>> +
>> +static int dect_tbc_handover_req(const struct dect_cluster_handle 
>> *clh,
>> +                                const struct dect_tbc_id *id)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +       unsigned int cnt;
>> +       int err;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL)
>> +               return -ENOENT;
>> +       mbc_debug(mbc, "TBC_HANDOVER-req: TBEI: %u LBN: %u\n",
>> +                 id->tbei, id->lbn);
>> +
>> +       /* Handover already in progress or two bearers active?? */
>> +       cnt = 0;
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               if (tb->id.lbn  != id->lbn)
>> +                       continue;
>> +                if (tb->id.tbei == 0)
>> +                       return 0;
>> +                cnt++;
>> +       }
>> +       if (cnt > 1)
>> +               return 0;
>> +
>> +       /* Handover rate-limiting */
>> +       if (mbc->ho_tokens == 0) {
>> +               if (time_after_eq(jiffies, mbc->ho_stamp + 
>> DECT_MBC_HANDOVER_TIMER)) {
>> +                       mbc->ho_tokens = DECT_MBC_HANDOVER_LIMIT;
>> +                       mbc->ho_stamp  = jiffies;
>> +               }
>> +               mbc_debug(mbc, "handover: tokens: %u\n", 
>> mbc->ho_tokens);
>> +               if (mbc->ho_tokens == 0)
>> +                       return 0;
>> +       }
>> +
>> +       ch = dect_cluster_get_cell_by_rpn(cl, 0);
>> +       if (ch == NULL)
>> +               return -EHOSTUNREACH;
>> +
>> +       tb = dect_mbc_tb_init(mbc, ch, id->lbn);
>> +       if (tb == NULL)
>> +               return -ENOMEM;
>> +       tb->handover = true;
>> +
>> +       err = dect_mbc_tb_setup(mbc, tb);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       list_add_tail(&tb->list, &mbc->tbs);
>> +       mbc->ho_tokens--;
>> +       return 0;
>> +
>> +err1:
>> +       dect_mbc_tb_release(tb);
>> +       return err;
>> +}
>> +
>> +/* TBC release indication from CSF */
>> +static void dect_tbc_dis_ind(const struct dect_cluster_handle *clh,
>> +                            const struct dect_tbc_id *id,
>> +                            enum dect_release_reasons reason)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL)
>> +               return;
>> +       mbc_debug(mbc, "TBC_DIS-ind: TBEI: %u LBN: %u reason: %u\n",
>> +                 id->tbei, id->lbn, reason);
>> +
>> +       tb = dect_mbc_tb_get_by_tbei(mbc, id);
>> +       if (tb == NULL)
>> +               return;
>> +
>> +       list_del(&tb->list);
>> +       dect_mbc_tb_release(tb);
>> +       if (!list_empty(&mbc->tbs))
>> +               return;
>> +
>> +       dect_mac_dis_ind(cl, mbc->id.mcei, reason);
>> +       dect_mbc_release(mbc);
>> +}
>> +
>> +/* Set Encryption key request from DLC */
>> +int dect_mac_enc_key_req(const struct dect_cluster *cl, u32 mcei, u64 
>> ck)
>> +{
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +       int err;
>> +
>> +       mbc = dect_mbc_get_by_mcei(cl, mcei);
>> +       if (mbc == NULL)
>> +               return -ENOENT;
>> +       mbc_debug(mbc, "MAC_ENC_KEY-req: key: %016llx\n", (unsigned 
>> long long)ck);
>> +
>> +       mbc->ck = ck;
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               err = tb->ch->ops->tbc_enc_key_req(tb->ch, &tb->id, 
>> ck);
>> +               if (err < 0)
>> +                       return err;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/* Change encryption status requst from DLC */
>> +int dect_mac_enc_eks_req(const struct dect_cluster *cl, u32 mcei,
>> +                        enum dect_cipher_states status)
>> +{
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +       int err;
>> +
>> +       mbc = dect_mbc_get_by_mcei(cl, mcei);
>> +       if (mbc == NULL)
>> +               return -ENOENT;
>> +       mbc_debug(mbc, "MAC_ENC_EKS-req: status: %d\n", status);
>> +
>> +       if (mbc->cipher_state == status)
>> +               return 0;
>> +
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               err = tb->ch->ops->tbc_enc_eks_req(tb->ch, &tb->id, 
>> status);
>> +               if (err < 0)
>> +                       return err;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void dect_tbc_data_ind(const struct dect_cluster_handle *clh,
>> +                             const struct dect_tbc_id *id,
>> +                             enum dect_data_channels chan,
>> +                             struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster *cl = dect_cluster(clh);
>> +       struct dect_mbc *mbc;
>> +       struct dect_tb *tb;
>> +
>> +       mbc = dect_mbc_get_by_tbc_id(cl, id);
>> +       if (mbc == NULL)
>> +               goto err;
>> +       mbc_debug(mbc, "TBC_DATA-ind: TBEI: %u LBN: %u chan: %u len: 
>> %u\n",
>> +                 id->tbei, id->lbn, chan, skb->len);
>> +
>> +       switch (chan) {
>> +       case DECT_MC_C_S:
>> +               /* Drop duplicate segments */
>> +               if (DECT_CS_CB(skb)->seq != mbc->cs_rx_seq)
>> +                       goto err;
>> +               if (mbc->cs_rx_skb != NULL)
>> +                       goto err;
>> +               mbc->cs_rx_seq = !mbc->cs_rx_seq;
>> +               mbc->cs_rx_skb = skb;
>> +               return;
>> +       case DECT_MC_I_N:
>> +               tb = dect_mbc_tb_get_by_tbei(mbc, id);
>> +               if (tb == NULL)
>> +                       goto err;
>> +               tb->b_rx_skb = skb;
>> +               return;
>> +       default:
>> +               break;
>> +       }
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_cluster_unbind_cell(struct dect_cluster_handle *clh,
>> +                                    struct dect_cell_handle *ch)
>> +{
>> +       list_del(&ch->list);
>> +}
>> +
>> +static int dect_cluster_enable_cell(struct dect_cluster *cl,
>> +                                   struct dect_cell_handle *ch)
>> +{
>> +       int err;
>> +
>> +       err = ch->ops->preload(ch, &cl->pari, ch->rpn, &cl->si);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       err = ch->ops->enable(ch);
>> +       if (err < 0)
>> +               return err;
>> +       return 0;
>> +}
>> +
>> +static int dect_cluster_bind_cell(struct dect_cluster_handle *clh,
>> +                                 struct dect_cell_handle *ch)
>> +{
>> +       struct dect_cluster *cl = dect_cluster(clh);
>> +       u8 rpn, max;
>> +       int err;
>> +
>> +       /* Allocate RPN for the cell */
>> +       max = 8;
>> +       for (rpn = 0; rpn < max; rpn++) {
>> +               if (!dect_cluster_get_cell_by_rpn(cl, rpn))
>> +                       break;
>> +       }
>> +       if (rpn == max)
>> +               return -EMFILE;
>> +
>> +       ch->clh = clh;
>> +       ch->rpn = rpn;
>> +
>> +       err = ch->ops->set_mode(ch, cl->mode);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       err = dect_cluster_enable_cell(cl, ch);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       list_add_tail(&ch->list, &cl->cells);
>> +       return 0;
>> +}
>> +
>> +static const struct dect_ccf_ops dect_ccf_ops = {
>> +       .bind                   = dect_cluster_bind_cell,
>> +       .unbind                 = dect_cluster_unbind_cell,
>> +       .time_ind               = dect_ccf_time_ind,
>> +       .scan_report            = dect_scan_report,
>> +       .mac_info_ind           = dect_mac_info_ind,
>> +       .tbc_establish_ind      = dect_tbc_establish_ind,
>> +       .tbc_establish_cfm      = dect_tbc_establish_cfm,
>> +       .tbc_event_ind          = dect_tbc_event_ind,
>> +       .tbc_handover_req       = dect_tbc_handover_req,
>> +       .tbc_dis_ind            = dect_tbc_dis_ind,
>> +       .tbc_data_ind           = dect_tbc_data_ind,
>> +       .bmc_page_ind           = dect_bmc_page_ind,
>> +};
>> +
>> +static int dect_cluster_preload(struct dect_cluster *cl,
>> +                               const struct dect_ari *pari,
>> +                               const struct dect_si *si)
>> +{
>> +       const struct dect_cell_handle *ch;
>> +       int err = 0;
>> +
>> +       list_for_each_entry(ch, &cl->cells, list) {
>> +               err = ch->ops->preload(ch, pari, ch->rpn, si);
>> +               if (err < 0)
>> +                       return err;
>> +       }
>> +
>> +       cl->pari = *pari;
>> +       cl->si   = *si;
>> +       return 0;
>> +}
>> +
>> +static int dect_cluster_scan(struct dect_cluster *cl,
>> +                            const struct dect_llme_req *lreq,
>> +                            const struct dect_ari *pari,
>> +                            const struct dect_ari *pari_mask)
>> +{
>> +       struct dect_cell_handle *ch;
>> +
>> +       ch = dect_cluster_get_cell_by_rpn(cl, 0);
>> +       if (ch == NULL)
>> +               return -ENOENT;
>> +       return ch->ops->scan(ch, lreq, pari, pari_mask);
>> +}
>> +
>> +static void dect_fp_init_si(struct dect_cluster *cl)
>> +{
>> +       struct dect_si *si = &cl->si;
>> +
>> +       /* Make phone not go into "call technician" mode :) */
>> +       si->fpc.fpc = DECT_FPC_FULL_SLOT |
>> +                     DECT_FPC_CO_SETUP_ON_DUMMY |
>> +                     DECT_FPC_CL_UPLINK |
>> +                     DECT_FPC_CL_DOWNLINK |
>> +                     DECT_FPC_BASIC_A_FIELD_SETUP |
>> +                     DECT_FPC_ADV_A_FIELD_SETUP |
>> +                     DECT_FPC_CF_MESSAGES |
>> +                     DECT_FPC_IN_MIN_DELAY |
>> +                     DECT_FPC_IN_NORM_DELAY |
>> +                     DECT_FPC_IP_ERROR_DETECTION |
>> +                     DECT_FPC_IP_ERROR_CORRECTION;
>> +       si->fpc.hlc = DECT_HLC_ADPCM_G721_VOICE |
>> +                     DECT_HLC_GAP_PAP_BASIC_SPEECH |
>> +                     DECT_HLC_CISS_SERVICE |
>> +                     DECT_HLC_CLMS_SERVICE |
>> +                     DECT_HLC_COMS_SERVICE |
>> +                     DECT_HLC_LOCATION_REGISTRATION |
>> +                     DECT_HLC_ACCESS_RIGHTS_REQUESTS |
>> +                     DECT_HLC_STANDARD_AUTHENTICATION |
>> +                     DECT_HLC_STANDARD_CIPHERING;
>> +}
>> +
>> +static int dect_cluster_init(struct dect_cluster *cl)
>> +{
>> +       spin_lock_init(&cl->lock);
>> +       INIT_LIST_HEAD(&cl->bmc.bcs);
>> +       INIT_LIST_HEAD(&cl->mbcs);
>> +       INIT_LIST_HEAD(&cl->cells);
>> +       INIT_LIST_HEAD(&cl->mac_connections);
>> +       dect_timer_base_init(cl->timer_base, DECT_TIMER_TX);
>> +       dect_timer_base_init(cl->timer_base, DECT_TIMER_RX);
>> +
>> +       if (cl->mode == DECT_MODE_FP)
>> +               dect_fp_init_si(cl);
>> +
>> +       cl->handle.ops = &dect_ccf_ops;
>> +       cl->handle.index = cl->index;
>> +
>> +       return dect_ccp_cluster_init(cl);
>> +}
>> +
>> +static void dect_cluster_shutdown(struct dect_cluster *cl)
>> +{
>> +       struct dect_cell_handle *ch, *ch_next;
>> +       struct dect_mbc *mbc, *mbc_next;
>> +
>> +       list_for_each_entry_safe(mbc, mbc_next, &cl->mbcs, list) {
>> +               dect_mac_dis_ind(cl, mbc->id.mcei, 
>> DECT_REASON_UNKNOWN);
>> +               dect_mbc_release(mbc);
>> +       }
>> +
>> +       list_for_each_entry_safe(ch, ch_next, &cl->cells, list)
>> +               dect_cluster_unbind_cell(&cl->handle, ch);
>> +
>> +       dect_ccp_cluster_shutdown(cl);
>> +}
>> +
>> +/*
>> + * LLME netlink interface
>> + */
>> +
>> +static struct sk_buff *dect_llme_fill(const struct dect_cluster *cl,
>> +                                     const struct dect_llme_req 
>> *lreq,
>> +                                     u8 op, u8 type,
>> +                                     int (*fill)(const struct 
>> dect_cluster *,
>> +                                                 struct sk_buff *, 
>> const void *),
>> +                                     const void *data);
>> +
>> +static void dect_llme_req_init(struct dect_llme_req *lreq,
>> +                              const struct nlmsghdr *nlh,
>> +                              const struct sk_buff *skb)
>> +{
>> +       memcpy(&lreq->nlh, nlh, sizeof(lreq->nlh));
>> +       lreq->nlpid = NETLINK_CB(skb).portid;
>> +}
>> +
>> +static int dect_fill_ari(struct sk_buff *skb, const struct dect_ari 
>> *ari, int attr)
>> +{
>> +       struct nlattr *nla;
>> +
>> +       nla = nla_nest_start(skb, attr);
>> +       if (nla == NULL)
>> +               goto nla_put_failure;
>> +
>> +       nla_put_u8(skb, DECTA_ARI_CLASS, ari->arc);
>> +       nla_put_u32(skb, DECTA_ARI_FPN, ari->fpn);
>> +
>> +       switch (ari->arc) {
>> +       case DECT_ARC_A:
>> +               nla_put_u16(skb, DECTA_ARI_EMC, ari->emc);
>> +               break;
>> +       case DECT_ARC_B:
>> +               nla_put_u16(skb, DECTA_ARI_EIC, ari->eic);
>> +               nla_put_u32(skb, DECTA_ARI_FPS, ari->fps);
>> +               break;
>> +       case DECT_ARC_C:
>> +               nla_put_u16(skb, DECTA_ARI_POC, ari->poc);
>> +               nla_put_u32(skb, DECTA_ARI_FPS, ari->fps);
>> +               break;
>> +       case DECT_ARC_D:
>> +               nla_put_u32(skb, DECTA_ARI_GOP, ari->gop);
>> +               break;
>> +       case DECT_ARC_E:
>> +               nla_put_u16(skb, DECTA_ARI_FIL, ari->fil);
>> +               break;
>> +       }
>> +       nla_nest_end(skb, nla);
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -1;
>> +}
>> +
>> +static const struct nla_policy dect_ari_policy[DECTA_ARI_MAX + 1] = {
>> +       [DECTA_ARI_CLASS]       = { .type = NLA_U8 },
>> +       [DECTA_ARI_FPN]         = { .type = NLA_U32 },
>> +       [DECTA_ARI_FPS]         = { .type = NLA_U32 },
>> +       [DECTA_ARI_EMC]         = { .type = NLA_U16 },
>> +       [DECTA_ARI_EIC]         = { .type = NLA_U16 },
>> +       [DECTA_ARI_POC]         = { .type = NLA_U16 },
>> +       [DECTA_ARI_GOP]         = { .type = NLA_U32 },
>> +       [DECTA_ARI_FIL]         = { .type = NLA_U32 },
>> +};
>> +
>> +static const u32 dect_ari_valid_attrs[] = {
>> +       [DECT_ARC_A]            = (1 << DECTA_ARI_EMC),
>> +       [DECT_ARC_B]            = (1 << DECTA_ARI_EIC) | (1 << 
>> DECTA_ARI_FPS),
>> +       [DECT_ARC_C]            = (1 << DECTA_ARI_POC) | (1 << 
>> DECTA_ARI_FPS),
>> +       [DECT_ARC_D]            = (1 << DECTA_ARI_GOP),
>> +       [DECT_ARC_E]            = (1 << DECTA_ARI_FIL),
>> +};
>> +
>> +static int dect_nla_parse_ari(struct dect_ari *ari, const struct 
>> nlattr *nla)
>> +{
>> +       struct nlattr *tb[DECTA_ARI_MAX + 1];
>> +       unsigned int attr;
>> +       int err;
>> +
>> +       err = nla_parse_nested(tb, DECTA_ARI_MAX, nla, 
>> dect_ari_policy);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       if (tb[DECTA_ARI_CLASS] == NULL)
>> +               return -EINVAL;
>> +
>> +       memset(ari, 0, sizeof(*ari));
>> +       ari->arc = nla_get_u8(tb[DECTA_ARI_CLASS]);
>> +       if (ari->arc > DECT_ARC_E)
>> +               return -EINVAL;
>> +
>> +       for (attr = DECTA_ARI_UNSPEC + 1; attr <= DECTA_ARI_MAX; 
>> attr++) {
>> +               if (tb[attr] == NULL)
>> +                       continue;
>> +
>> +               switch (attr) {
>> +               case DECTA_ARI_CLASS:
>> +               case DECTA_ARI_FPN:
>> +                       /* always valid */
>> +                       break;
>> +               default:
>> +                       if (!(dect_ari_valid_attrs[ari->arc] & (1 << 
>> attr)))
>> +                               return -EINVAL;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       if (tb[DECTA_ARI_FPN] != NULL)
>> +               ari->fpn = nla_get_u32(tb[DECTA_ARI_FPN]);
>> +       if (tb[DECTA_ARI_FPS] != NULL)
>> +               ari->fps = nla_get_u32(tb[DECTA_ARI_FPS]);
>> +
>> +       switch (ari->arc) {
>> +       case DECT_ARC_A:
>> +               if (tb[DECTA_ARI_EMC] != NULL)
>> +                       ari->emc = nla_get_u16(tb[DECTA_ARI_EMC]);
>> +               break;
>> +       case DECT_ARC_B:
>> +               if (tb[DECTA_ARI_EIC] != NULL)
>> +                       ari->eic = nla_get_u16(tb[DECTA_ARI_EIC]);
>> +               break;
>> +       case DECT_ARC_C:
>> +               if (tb[DECTA_ARI_POC] != NULL)
>> +                       ari->poc = nla_get_u16(tb[DECTA_ARI_POC]);
>> +               break;
>> +       case DECT_ARC_D:
>> +               if (tb[DECTA_ARI_GOP] != NULL)
>> +                       ari->gop = nla_get_u32(tb[DECTA_ARI_GOP]);
>> +               break;
>> +       case DECT_ARC_E:
>> +               if (tb[DECTA_ARI_FIL] != NULL)
>> +                       ari->fil = nla_get_u16(tb[DECTA_ARI_FIL]);
>> +               break;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int dect_fill_sari(struct sk_buff *skb, const struct dect_sari 
>> *sari,
>> +                         int attr)
>> +{
>> +       struct nlattr *nla;
>> +
>> +       nla = nla_nest_start(skb, attr);
>> +       if (nla == NULL)
>> +               goto nla_put_failure;
>> +       if (dect_fill_ari(skb, &sari->ari, DECTA_SARI_ARI) < 0)
>> +               goto nla_put_failure;
>> +       if (sari->black)
>> +               nla_put_flag(skb, DECTA_SARI_BLACK);
>> +       if (sari->tari)
>> +               nla_put_flag(skb, DECTA_SARI_TARI);
>> +       nla_nest_end(skb, nla);
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -1;
>> +}
>> +
>> +static int dect_llme_fill_mac_info(const struct dect_cluster *cl,
>> +                                  struct sk_buff *skb, const void 
>> *data)
>> +{
>> +       const struct dect_si *si = data;
>> +       struct nlattr *nla;
>> +       unsigned int i;
>> +
>> +       if (si->mask & (1 << DECT_TM_TYPE_SARI) && si->num_saris > 0) 
>> {
>> +               nla = nla_nest_start(skb, DECTA_MAC_INFO_SARI_LIST);
>> +               if (nla == NULL)
>> +                       goto nla_put_failure;
>> +               for (i = 0; i < si->num_saris; i++) {
>> +                       if (dect_fill_sari(skb, &si->sari[i],
>> +                                          DECTA_LIST_ELEM) < 0)
>> +                               goto nla_put_failure;
>> +               }
>> +               nla_nest_end(skb, nla);
>> +       }
>> +
>> +       nla_put_u8(skb, DECTA_MAC_INFO_RPN, cl->rpn);
>> +
>> +       if (si->mask & (1 << DECT_TM_TYPE_FPC)) {
>> +               nla_put_u32(skb, DECTA_MAC_INFO_FPC, si->fpc.fpc);
>> +               nla_put_u16(skb, DECTA_MAC_INFO_HLC, si->fpc.hlc);
>> +       }
>> +
>> +       if (si->mask & (1 << DECT_TM_TYPE_EFPC)) {
>> +               nla_put_u16(skb, DECTA_MAC_INFO_EFPC, si->efpc.fpc);
>> +               nla_put_u32(skb, DECTA_MAC_INFO_EHLC, si->efpc.hlc);
>> +       }
>> +
>> +       if (si->mask & (1 << DECT_TM_TYPE_EFPC2)) {
>> +               nla_put_u16(skb, DECTA_MAC_INFO_EFPC2, si->efpc2.fpc);
>> +               nla_put_u32(skb, DECTA_MAC_INFO_EHLC2, si->efpc2.hlc);
>> +       }
>> +
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -EMSGSIZE;
>> +}
>> +
>> +static int dect_llme_fill_scan_result(const struct dect_cluster *cl,
>> +                                     struct sk_buff *skb, const void 
>> *data)
>> +{
>> +       const struct dect_scan_result *res = data;
>> +       const struct dect_idi *idi = &res->idi;
>> +       const struct dect_si *si = &res->si;
>> +
>> +       nla_put_u8(skb, DECTA_MAC_INFO_RSSI, res->rssi >> 
>> DECT_RSSI_AVG_SCALE);
>> +
>> +       if (dect_fill_ari(skb, &idi->pari, DECTA_MAC_INFO_PARI) < 0)
>> +               goto nla_put_failure;
>> +       nla_put_u8(skb, DECTA_MAC_INFO_RPN, idi->rpn);
>> +
>> +       dect_llme_fill_mac_info(cl, skb, si);
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -EMSGSIZE;
>> +}
>> +
>> +static void dect_llme_scan_result_notify(const struct dect_cluster 
>> *cl,
>> +                                        const struct dect_scan_result 
>> *res)
>> +{
>> +       struct sk_buff *skb;
>> +       u32 pid = res->lreq.nlpid;
>> +       int err = 0;
>> +
>> +       skb = dect_llme_fill(cl, &res->lreq,
>> +                            DECT_LLME_INDICATE, DECT_LLME_MAC_INFO,
>> +                            dect_llme_fill_scan_result, res);
>> +       if (IS_ERR(skb)) {
>> +               err = PTR_ERR(skb);
>> +               goto err;
>> +       }
>> +       nlmsg_notify(dect_nlsk, skb, pid, DECTNLGRP_LLME, 1, 
>> GFP_ATOMIC);
>> +err:
>> +       if (err < 0)
>> +               netlink_set_err(dect_nlsk, pid, DECTNLGRP_LLME, err);
>> +}
>> +
>> +static void dect_llme_mac_info_ind(const struct dect_cluster *cl,
>> +                                  const struct dect_idi *idi,
>> +                                  const struct dect_si *si)
>> +{
>> +       struct sk_buff *skb;
>> +       int err = 0;
>> +
>> +       skb = dect_llme_fill(cl, NULL,
>> +                            DECT_LLME_INDICATE, DECT_LLME_MAC_INFO,
>> +                            dect_llme_fill_mac_info, si);
>> +       if (IS_ERR(skb)) {
>> +               err = PTR_ERR(skb);
>> +               goto err;
>> +       }
>> +       nlmsg_notify(dect_nlsk, skb, 0, DECTNLGRP_LLME, 0, 
>> GFP_ATOMIC);
>> +err:
>> +       if (err < 0)
>> +               netlink_set_err(dect_nlsk, 0, DECTNLGRP_LLME, err);
>> +}
>> +
>> +static int dect_llme_mac_info_req(struct dect_cluster *cl,
>> +                                 const struct sk_buff *skb_in,
>> +                                 const struct nlmsghdr *nlh,
>> +                                 const struct nlattr 
>> *tb[DECTA_MAC_INFO_MAX + 1])
>> +{
>> +       struct dect_llme_req lreq;
>> +       struct sk_buff *skb;
>> +
>> +       dect_llme_req_init(&lreq, nlh, skb_in);
>> +       skb = dect_llme_fill(cl, &lreq,
>> +                            DECT_LLME_INDICATE, DECT_LLME_MAC_INFO,
>> +                            dect_llme_fill_mac_info, &cl->si);
>> +       if (IS_ERR(skb))
>> +               return PTR_ERR(skb);
>> +
>> +       return nlmsg_unicast(dect_nlsk, skb, lreq.nlpid);
>> +}
>> +
>> +static int dect_llme_mac_info_res(struct dect_cluster *cl,
>> +                                 const struct sk_buff *skb_in,
>> +                                 const struct nlmsghdr *nlh,
>> +                                 const struct nlattr 
>> *tb[DECTA_MAC_INFO_MAX + 1])
>> +{
>> +       struct dect_cell_handle *ch;
>> +       struct dect_ari pari;
>> +       int err;
>> +
>> +       if (cl->mode != DECT_MODE_PP)
>> +               return -EOPNOTSUPP;
>> +
>> +       if (tb[DECTA_MAC_INFO_PARI] != NULL) {
>> +               err = dect_nla_parse_ari(&pari, 
>> tb[DECTA_MAC_INFO_PARI]);
>> +               if (err < 0)
>> +                       return err;
>> +       } else
>> +               return -EINVAL;
>> +
>> +       ch = dect_cluster_get_cell_by_rpn(cl, 0);
>> +       if (ch == NULL)
>> +               return -EHOSTUNREACH;
>> +
>> +       cl->pari = pari;
>> +       memset(&cl->si, 0, sizeof(cl->si));
>> +
>> +       return dect_cluster_enable_cell(cl, ch);
>> +}
>> +
>> +static const struct nla_policy 
>> dect_llme_mac_info_policy[DECTA_MAC_INFO_MAX + 1] =  {
>> +       [DECTA_MAC_INFO_PARI]           = { .type = NLA_NESTED },
>> +       [DECTA_MAC_INFO_RPN]            = { .type = NLA_U8 },
>> +       [DECTA_MAC_INFO_RSSI]           = { .type = NLA_U8 },
>> +       [DECTA_MAC_INFO_SARI_LIST]      = { .type = NLA_NESTED },
>> +       [DECTA_MAC_INFO_FPC]            = { .type = NLA_U32 },
>> +       [DECTA_MAC_INFO_HLC]            = { .type = NLA_U16 },
>> +       [DECTA_MAC_INFO_EFPC]           = { .type = NLA_U16 },
>> +       [DECTA_MAC_INFO_EHLC]           = { .type = NLA_U32 },
>> +       [DECTA_MAC_INFO_EFPC2]          = { .type = NLA_U16 },
>> +       [DECTA_MAC_INFO_EHLC2]          = { .type = NLA_U32 },
>> +};
>> +
>> +static int dect_llme_scan_request(struct dect_cluster *cl,
>> +                                 const struct sk_buff *skb,
>> +                                 const struct nlmsghdr *nlh,
>> +                                 const struct nlattr 
>> *tb[DECTA_MAC_INFO_MAX + 1])
>> +{
>> +       struct dect_llme_req lreq;
>> +       struct dect_ari pari, pari_mask;
>> +       int err;
>> +
>> +       if (tb[DECTA_MAC_INFO_PARI] != NULL) {
>> +               err = dect_nla_parse_ari(&pari, 
>> tb[DECTA_MAC_INFO_PARI]);
>> +               if (err < 0)
>> +                       return err;
>> +       } else
>> +               memset(&pari, 0, sizeof(pari));
>> +       memset(&pari_mask, 0, sizeof(pari_mask));
>> +
>> +       dect_llme_req_init(&lreq, nlh, skb);
>> +       return dect_cluster_scan(cl, &lreq, &pari, &pari_mask);
>> +}
>> +
>> +static int dect_llme_mac_rfp_preload(struct dect_cluster *cl,
>> +                                    const struct sk_buff *skb,
>> +                                    const struct nlmsghdr *nlh,
>> +                                    const struct nlattr 
>> *tb[DECTA_MAC_INFO_MAX + 1])
>> +{
>> +       struct dect_ari pari;
>> +       struct dect_si si;
>> +       int err = 0;
>> +       u32 num;
>> +
>> +       if (cl->mode != DECT_MODE_FP)
>> +               return -EINVAL;
>> +
>> +       if (tb[DECTA_MAC_INFO_PARI] != NULL) {
>> +               err = dect_nla_parse_ari(&pari, 
>> tb[DECTA_MAC_INFO_PARI]);
>> +               if (err < 0)
>> +                       return err;
>> +       } else
>> +               pari = cl->pari;
>> +
>> +       si = cl->si;
>> +       if (tb[DECTA_MAC_INFO_HLC])
>> +               si.fpc.hlc = nla_get_u16(tb[DECTA_MAC_INFO_HLC]);
>> +       if (tb[DECTA_MAC_INFO_EHLC])
>> +               si.efpc.hlc = nla_get_u32(tb[DECTA_MAC_INFO_EHLC]);
>> +       if (tb[DECTA_MAC_INFO_EHLC2])
>> +               si.efpc2.hlc = nla_get_u32(tb[DECTA_MAC_INFO_EHLC2]);
>> +
>> +       if (si.efpc2.fpc || si.efpc2.hlc)
>> +               si.efpc.fpc |= DECT_EFPC_EXTENDED_FP_INFO2;
>> +       else
>> +               si.efpc.fpc &= ~DECT_EFPC_EXTENDED_FP_INFO2;
>> +
>> +       if (si.efpc.fpc || si.efpc.hlc)
>> +               si.fpc.fpc |= DECT_FPC_EXTENDED_FP_INFO;
>> +       else
>> +               si.fpc.fpc &= ~DECT_FPC_EXTENDED_FP_INFO;
>> +
>> +        if (tb[DECTA_MAC_INFO_MFN]) {
>> +                num = nla_get_u32(tb[DECTA_MAC_INFO_MFN]);
>> +                if (num >= (1 << 24))
>> +                        return -EINVAL;
>> +                si.mfn.num = num;
>> +        }
>> +
>> +       return dect_cluster_preload(cl, &pari, &si);
>> +}
>> +
>> +static struct sk_buff *dect_llme_fill(const struct dect_cluster *cl,
>> +                                     const struct dect_llme_req 
>> *lreq,
>> +                                     u8 op, u8 type,
>> +                                     int (*fill)(const struct 
>> dect_cluster *,
>> +                                                 struct sk_buff *, 
>> const void *),
>> +                                     const void *data)
>> +{
>> +       struct sk_buff *skb;
>> +       struct nlmsghdr *nlh;
>> +       struct dectmsg *dm;
>> +       struct nlattr *nest;
>> +       u32 seq = lreq ? lreq->nlh.nlmsg_seq : 0;
>> +       int err = -ENOBUFS;
>> +
>> +       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               goto err1;
>> +
>> +       nlh = nlmsg_put(skb, 0, seq, DECT_LLME_MSG, sizeof(*dm), 
>> NLMSG_DONE);
>> +       if (nlh == NULL) {
>> +               err = -EMSGSIZE;
>> +               goto err2;
>> +       }
>> +
>> +       dm = nlmsg_data(nlh);
>> +       dm->dm_index = cl->index;
>> +
>> +       nla_put_u8(skb, DECTA_LLME_OP, op);
>> +       nla_put_u8(skb, DECTA_LLME_TYPE, type);
>> +       nest = nla_nest_start(skb, DECTA_LLME_DATA);
>> +       if (nest == NULL)
>> +               goto nla_put_failure;
>> +       if (fill(cl, skb, data) < 0)
>> +               goto nla_put_failure;
>> +       nla_nest_end(skb, nest);
>> +
>> +       nlmsg_end(skb, nlh);
>> +       return skb;
>> +
>> +nla_put_failure:
>> +err2:
>> +       kfree_skb(skb);
>> +err1:
>> +       return ERR_PTR(err);
>> +}
>> +
>> +static const struct dect_llme_link {
>> +       struct {
>> +               int (*doit)(struct dect_cluster *cl, const struct 
>> sk_buff *,
>> +                           const struct nlmsghdr *, const struct 
>> nlattr *[]);
>> +       } ops[DECT_LLME_MAX + 1];
>> +       const struct nla_policy *policy;
>> +       unsigned int maxtype;
>> +} dect_llme_dispatch[DECT_LLME_MAX + 1] = {
>> +       [DECT_LLME_SCAN]        = {
>> +               .policy         = dect_llme_mac_info_policy,
>> +               .maxtype        = DECTA_MAC_INFO_MAX,
>> +               .ops            = {
>> +                       [DECT_LLME_REQUEST].doit = 
>> dect_llme_scan_request,
>> +               },
>> +       },
>> +       [DECT_LLME_MAC_INFO] = {
>> +               .policy         = dect_llme_mac_info_policy,
>> +               .maxtype        = DECTA_MAC_INFO_MAX,
>> +               .ops            = {
>> +                       [DECT_LLME_REQUEST].doit = 
>> dect_llme_mac_info_req,
>> +                       [DECT_LLME_RESPONSE].doit = 
>> dect_llme_mac_info_res,
>> +               },
>> +       },
>> +       [DECT_LLME_MAC_RFP_PRELOAD] = {
>> +               .policy         = dect_llme_mac_info_policy,
>> +               .maxtype        = DECTA_MAC_INFO_MAX,
>> +               .ops            = {
>> +                       [DECT_LLME_REQUEST].doit = 
>> dect_llme_mac_rfp_preload,
>> +               },
>> +       },
>> +};
>> +
>> +static const struct nla_policy dect_llme_policy[DECTA_LLME_MAX + 1] = 
>> {
>> +       [DECTA_LLME_OP]         = { .type = NLA_U8 },
>> +       [DECTA_LLME_TYPE]       = { .type = NLA_U8 },
>> +       [DECTA_LLME_DATA]       = { .type = NLA_NESTED },
>> +};
>> +
>> +static int dect_llme_msg(const struct sk_buff *skb,
>> +                        const struct nlmsghdr *nlh,
>> +                        const struct nlattr *tb[DECTA_LLME_MAX + 1])
>> +{
>> +       const struct dect_llme_link *link;
>> +       struct dect_cluster *cl;
>> +       struct dectmsg *dm;
>> +       enum dect_llme_msg_types type;
>> +       enum dect_llme_ops op;
>> +       int err;
>> +
>> +       if (tb[DECTA_LLME_OP] == NULL ||
>> +           tb[DECTA_LLME_TYPE] == NULL ||
>> +           tb[DECTA_LLME_DATA] == NULL)
>> +               return -EINVAL;
>> +
>> +       dm = nlmsg_data(nlh);
>> +       cl = dect_cluster_get_by_index(dm->dm_index);
>> +       if (cl == NULL)
>> +               return -ENODEV;
>> +
>> +       type = nla_get_u8(tb[DECTA_LLME_TYPE]);
>> +       if (type > DECT_LLME_MAX)
>> +               return -EINVAL;
>> +       link = &dect_llme_dispatch[type];
>> +
>> +       op = nla_get_u8(tb[DECTA_LLME_OP]);
>> +       switch (op) {
>> +       case DECT_LLME_REQUEST:
>> +       case DECT_LLME_INDICATE:
>> +       case DECT_LLME_RESPONSE:
>> +       case DECT_LLME_CONFIRM:
>> +               if (link->ops[op].doit == NULL)
>> +                       return -EOPNOTSUPP;
>> +               break;
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (1) {
>> +               struct nlattr *nla[link->maxtype + 1];
>> +
>> +               err = nla_parse_nested(nla, link->maxtype, 
>> tb[DECTA_LLME_DATA],
>> +                                      link->policy);
>> +               if (err < 0)
>> +                       return err;
>> +               return link->ops[op].doit(cl, skb, nlh,
>> +                                         (const struct nlattr 
>> **)nla);
>> +       }
>> +}
>> +
>> +/*
>> + * Cluster netlink interface
>> + */
>> +
>> +static int dect_cluster_alloc_index(void)
>> +{
>> +       static int index;
>> +
>> +       for (;;) {
>> +               if (++index <= 0)
>> +                       index = 1;
>> +               if (!dect_cluster_get_by_index(index))
>> +                       return index;
>> +       }
>> +}
>> +
>> +static int dect_fill_tb(struct sk_buff *skb, const struct dect_tb 
>> *tb)
>> +{
>> +       struct nlattr *nest;
>> +
>> +       nest = nla_nest_start(skb, DECTA_LIST_ELEM);
>> +       if (nest == NULL)
>> +               goto nla_put_failure;
>> +       nla_put_u8(skb, DECTA_MBC_TB_LBN, tb->id.lbn);
>> +       nla_put_u8(skb, DECTA_MBC_TB_ECN, tb->id.ecn);
>> +       nla_put_u8(skb, DECTA_MBC_TB_CELL, tb->ch->rpn);
>> +       nla_put_u8(skb, DECTA_MBC_TB_RX_SLOT, tb->rx_slot);
>> +       nla_put_u8(skb, DECTA_MBC_TB_TX_SLOT, tb->tx_slot);
>> +       nla_nest_end(skb, nest);
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -EMSGSIZE;
>> +}
>> +
>> +static int dect_fill_mbc(struct sk_buff *skb, const struct dect_mbc 
>> *mbc)
>> +{
>> +       struct nlattr *nest, *stats, *tbs;
>> +       struct dect_tb *tb;
>> +       int err;
>> +
>> +       nest = nla_nest_start(skb, DECTA_LIST_ELEM);
>> +       if (nest == NULL)
>> +               goto nla_put_failure;
>> +       nla_put_u32(skb, DECTA_MBC_MCEI, mbc->id.mcei);
>> +       nla_put_u8(skb, DECTA_MBC_SERVICE, mbc->service);
>> +       nla_put_u8(skb, DECTA_MBC_STATE, mbc->state);
>> +       nla_put_u8(skb, DECTA_MBC_CIPHER_STATE, mbc->cipher_state);
>> +
>> +       stats = nla_nest_start(skb, DECTA_MBC_STATS);
>> +       if (stats == NULL)
>> +               goto nla_put_failure;
>> +       nla_put_u32(skb, DECTA_MBC_STATS_CS_RX_BYTES, 
>> mbc->stats.cs_rx_bytes);
>> +       nla_put_u32(skb, DECTA_MBC_STATS_CS_TX_BYTES, 
>> mbc->stats.cs_tx_bytes);
>> +       nla_put_u32(skb, DECTA_MBC_STATS_I_RX_BYTES, 
>> mbc->stats.i_rx_bytes);
>> +       nla_put_u32(skb, DECTA_MBC_STATS_I_TX_BYTES, 
>> mbc->stats.i_tx_bytes);
>> +       nla_put_u32(skb, DECTA_MBC_STATS_HANDOVERS, 
>> mbc->stats.handovers);
>> +       nla_nest_end(skb, stats);
>> +
>> +       tbs = nla_nest_start(skb, DECTA_MBC_TBS);
>> +       if (tbs == NULL)
>> +               goto nla_put_failure;
>> +       list_for_each_entry(tb, &mbc->tbs, list) {
>> +               err = dect_fill_tb(skb, tb);
>> +               if (err < 0)
>> +                       goto nla_put_failure;
>> +       }
>> +       nla_nest_end(skb, tbs);
>> +       nla_nest_end(skb, nest);
>> +       return 0;
>> +
>> +nla_put_failure:
>> +       return -EMSGSIZE;
>> +}
>> +
>> +static int dect_fill_cluster(struct sk_buff *skb,
>> +                            const struct dect_cluster *cl,
>> +                            u16 type, u32 pid, u32 seq, u16 flags)
>> +{
>> +       struct nlmsghdr *nlh;
>> +       struct dectmsg *dm;
>> +       struct nlattr *nest;
>> +       struct dect_cell_handle *ch;
>> +       struct dect_mbc *mbc;
>> +
>> +       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*dm), flags);
>> +       if (nlh == NULL)
>> +               return -EMSGSIZE;
>> +
>> +       dm = nlmsg_data(nlh);
>> +       dm->dm_index = cl->index;
>> +       nla_put_string(skb, DECTA_CLUSTER_NAME, cl->name);
>> +       nla_put_u8(skb, DECTA_CLUSTER_MODE, cl->mode);
>> +       if (dect_fill_ari(skb, &cl->pari, DECTA_CLUSTER_PARI) < 0)
>> +               goto nla_put_failure;
>> +
>> +       if (!list_empty(&cl->cells)) {
>> +               nest = nla_nest_start(skb, DECTA_CLUSTER_CELLS);
>> +               if (nest == NULL)
>> +                       goto nla_put_failure;
>> +               list_for_each_entry(ch, &cl->cells, list)
>> +                       nla_put_u8(skb, DECTA_LIST_ELEM, ch->rpn);
>> +               nla_nest_end(skb, nest);
>> +       }
>> +
>> +       if (!list_empty(&cl->mbcs)) {
>> +               nest = nla_nest_start(skb, DECTA_CLUSTER_MBCS);
>> +               if (nest == NULL)
>> +                       goto nla_put_failure;
>> +
>> +               list_for_each_entry(mbc, &cl->mbcs, list)
>> +                       if (dect_fill_mbc(skb, mbc) < 0)
>> +                               goto nla_put_failure;
>> +
>> +               nla_nest_end(skb, nest);
>> +       }
>> +
>> +       return nlmsg_end(skb, nlh);
>> +
>> +nla_put_failure:
>> +       nlmsg_cancel(skb, nlh);
>> +       return -EMSGSIZE;
>> +}
>> +
>> +static int dect_dump_cluster(struct sk_buff *skb,
>> +                            struct netlink_callback *cb)
>> +{
>> +       const struct dect_cluster *cl;
>> +       unsigned int idx, s_idx;
>> +
>> +       s_idx = cb->args[0];
>> +       idx = 0;
>> +       list_for_each_entry(cl, &dect_cluster_list, list) {
>> +               if (idx < s_idx)
>> +                       goto cont;
>> +               if (dect_fill_cluster(skb, cl, DECT_NEW_CLUSTER,
>> +                                     NETLINK_CB(cb->skb).portid,
>> +                                     cb->nlh->nlmsg_seq, NLM_F_MULTI) 
>> <= 0)
>> +                       break;
>> +cont:
>> +               idx++;
>> +       }
>> +       cb->args[0] = idx;
>> +
>> +       return skb->len;
>> +}
>> +
>> +static void dect_notify_cluster(u16 event, const struct dect_cluster 
>> *cl,
>> +                               const struct nlmsghdr *nlh, u32 pid)
>> +{
>> +       struct sk_buff *skb;
>> +       bool report = nlh ? nlmsg_report(nlh) : 0;
>> +       u32 seq = nlh ? nlh->nlmsg_seq : 0;
>> +       int err = -ENOBUFS;
>> +
>> +       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>> +       if (skb == NULL)
>> +               goto err;
>> +
>> +       err = dect_fill_cluster(skb, cl, event, pid, seq, NLMSG_DONE);
>> +       if (err < 0) {
>> +               WARN_ON(err == -EMSGSIZE);
>> +               kfree_skb(skb);
>> +               goto err;
>> +       }
>> +       nlmsg_notify(dect_nlsk, skb, pid, DECTNLGRP_CLUSTER, report, 
>> GFP_KERNEL);
>> +err:
>> +       if (err < 0)
>> +               netlink_set_err(dect_nlsk, pid, DECTNLGRP_CLUSTER, 
>> err);
>> +}
>> +
>> +static const struct nla_policy dect_cluster_policy[DECTA_CLUSTER_MAX 
>> + 1] = {
>> +       [DECTA_CLUSTER_NAME]            = { .type = NLA_STRING, .len = 
>> DECTNAMSIZ },
>> +       [DECTA_CLUSTER_MODE]            = { .type = NLA_U8 },
>> +       [DECTA_CLUSTER_PARI]            = { .len  = NLA_NESTED },
>> +};
>> +
>> +static int dect_new_cluster(const struct sk_buff *skb,
>> +                           const struct nlmsghdr *nlh,
>> +                           const struct nlattr *tb[DECTA_CLUSTER_MAX 
>> + 1])
>> +{
>> +       struct dect_cluster *cl;
>> +       struct dect_ari pari;
>> +       enum dect_cluster_modes uninitialized_var(mode);
>> +       int err;
>> +
>> +       if (tb[DECTA_CLUSTER_NAME] == NULL)
>> +               return -EINVAL;
>> +
>> +       if (tb[DECTA_CLUSTER_MODE] != NULL) {
>> +               mode = nla_get_u8(tb[DECTA_CLUSTER_MODE]);
>> +               switch (mode) {
>> +               case DECT_MODE_FP:
>> +               case DECT_MODE_PP:
>> +                       break;
>> +               default:
>> +                       return -EINVAL;
>> +               }
>> +       }
>> +
>> +       if (tb[DECTA_CLUSTER_PARI] != NULL) {
>> +               err = dect_nla_parse_ari(&pari, 
>> tb[DECTA_CLUSTER_PARI]);
>> +               if (err < 0)
>> +                       return err;
>> +       }
>> +
>> +       cl = dect_cluster_get_by_name(tb[DECTA_CLUSTER_NAME]);
>> +       if (cl != NULL) {
>> +               if (nlh->nlmsg_flags & NLM_F_EXCL)
>> +                       return -EEXIST;
>> +
>> +               return 0;
>> +       }
>> +
>> +       if (!(nlh->nlmsg_flags & NLM_F_CREATE))
>> +               return -ENOENT;
>> +
>> +       if (tb[DECTA_CLUSTER_MODE] == NULL)
>> +               return -EINVAL;
>> +
>> +       cl = kzalloc(sizeof(*cl), GFP_KERNEL);
>> +       if (cl == NULL)
>> +               return -ENOMEM;
>> +       nla_strlcpy(cl->name, tb[DECTA_CLUSTER_NAME], 
>> sizeof(cl->name));
>> +
>> +       memcpy(&cl->pari, &pari, sizeof(cl->pari));
>> +       cl->index = dect_cluster_alloc_index();
>> +       cl->mode  = mode;
>> +
>> +       err = dect_cluster_init(cl);
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       list_add_tail(&cl->list, &dect_cluster_list);
>> +       dect_notify_cluster(DECT_NEW_CLUSTER, cl, nlh, 
>> NETLINK_CB(skb).portid);
>> +       return 0;
>> +
>> +err1:
>> +       kfree(cl);
>> +       return err;
>> +}
>> +
>> +static int dect_del_cluster(const struct sk_buff *skb,
>> +                           const struct nlmsghdr *nlh,
>> +                           const struct nlattr *tb[DECTA_CLUSTER_MAX 
>> + 1])
>> +{
>> +       struct dect_cluster *cl;
>> +       struct dectmsg *dm;
>> +
>> +       dm = nlmsg_data(nlh);
>> +       if (dm->dm_index != 0)
>> +               cl = dect_cluster_get_by_index(dm->dm_index);
>> +       else if (tb[DECTA_CLUSTER_NAME] != NULL)
>> +               cl = dect_cluster_get_by_name(tb[DECTA_CLUSTER_NAME]);
>> +       else
>> +               return -EINVAL;
>> +       if (cl == NULL)
>> +               return -ENODEV;
>> +
>> +       dect_cluster_shutdown(cl);
>> +       list_del(&cl->list);
>> +
>> +       dect_notify_cluster(DECT_DEL_CLUSTER, cl, nlh, 
>> NETLINK_CB(skb).portid);
>> +       kfree(cl);
>> +       return 0;
>> +}
>> +
>> +static int dect_get_cluster(const struct sk_buff *in_skb,
>> +                           const struct nlmsghdr *nlh,
>> +                           const struct nlattr *tb[DECTA_CLUSTER_MAX 
>> + 1])
>> +{
>> +       u32 pid = NETLINK_CB(in_skb).portid;
>> +       const struct dect_cluster *cl;
>> +       struct dectmsg *dm;
>> +       struct sk_buff *skb;
>> +       int err;
>> +
>> +       dm = nlmsg_data(nlh);
>> +       if (dm->dm_index != 0)
>> +               cl = dect_cluster_get_by_index(dm->dm_index);
>> +       else if (tb[DECTA_CLUSTER_NAME] != NULL)
>> +               cl = dect_cluster_get_by_name(tb[DECTA_CLUSTER_NAME]);
>> +       else
>> +               return -EINVAL;
>> +       if (cl == NULL)
>> +               return -ENODEV;
>> +
>> +       skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +       err = dect_fill_cluster(skb, cl, DECT_NEW_CLUSTER, pid,
>> +                               nlh->nlmsg_seq, NLMSG_DONE);
>> +       if (err < 0)
>> +               goto err1;
>> +       return nlmsg_unicast(dect_nlsk, skb, pid);
>> +
>> +err1:
>> +       kfree_skb(skb);
>> +       return err;
>> +}
>> +
>> +static const struct dect_netlink_handler dect_cluster_handlers[] = {
>> +       {
>> +               /* DECT_NEW_CLUSTER */
>> +               .policy         = dect_cluster_policy,
>> +               .maxtype        = DECTA_CLUSTER_MAX,
>> +               .doit           = dect_new_cluster,
>> +       },
>> +       {
>> +               /* DECT_DEL_CLUSTER */
>> +               .policy         = dect_cluster_policy,
>> +               .maxtype        = DECTA_CLUSTER_MAX,
>> +               .doit           = dect_del_cluster,
>> +       },
>> +       {
>> +               /* DECT_GET_CLUSTER */
>> +               .policy         = dect_cluster_policy,
>> +               .maxtype        = DECTA_CLUSTER_MAX,
>> +               .doit           = dect_get_cluster,
>> +               .dump           = dect_dump_cluster,
>> +       },
>> +       {
>> +               /* DECT_LLME_MSG */
>> +               .policy         = dect_llme_policy,
>> +               .maxtype        = DECTA_LLME_MAX,
>> +               .doit           = dect_llme_msg,
>> +       },
>> +};
>> +
>> +static int __init dect_ccf_module_init(void)
>> +{
>> +       int err;
>> +
>> +       err = dect_bsap_module_init();
>> +       if (err < 0)
>> +               goto err1;
>> +
>> +       err = dect_ssap_module_init();
>> +       if (err < 0)
>> +               goto err2;
>> +
>> +       dect_netlink_register_handlers(dect_cluster_handlers, 
>> DECT_NEW_CLUSTER,
>> +                                      
>> ARRAY_SIZE(dect_cluster_handlers));
>> +
>> +       return 0;
>> +
>> +err2:
>> +       dect_bsap_module_exit();
>> +err1:
>> +       return err;
>> +}
>> +
>> +static void __exit dect_ccf_module_exit(void)
>> +{
>> +       dect_netlink_unregister_handlers(DECT_NEW_CLUSTER,
>> +                                        
>> ARRAY_SIZE(dect_cluster_handlers));
>> +       dect_bsap_module_exit();
>> +       dect_ssap_module_exit();
>> +}
>> +
>> +module_init(dect_ccf_module_init);
>> +module_exit(dect_ccf_module_exit);
>> diff --git a/target/linux/generic/files/net/dect/mac_csf.c 
>> b/target/linux/generic/files/net/dect/mac_csf.c
>> new file mode 100644
>> index 0000000..22be8a0
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/mac_csf.c
>> @@ -0,0 +1,5151 @@
>> +/*
>> + * DECT MAC Cell Site Functions
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <kaber at trash.net>
>> + *
>> + * This program is free software; you can redistribute it and/or 
>> modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifdef CONFIG_DECT_DEBUG
>> +#define DEBUG
>> +#endif
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/list.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/net.h>
>> +#include <linux/dect.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_csf.h>
>> +#include <net/dect/ccp.h>
>> +
>> +/* avoid <KERN_DEBUG> for continuation lines */
>> +#undef KERN_DEBUG
>> +#define KERN_DEBUG
>> +
>> +MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
>> +MODULE_DESCRIPTION("DECT MAC Cell Site Functions");
>> +MODULE_LICENSE("GPL");
>> +
>> +static void dect_notify_cell(u16 event, const struct dect_cell *cell,
>> +                            const struct nlmsghdr *nlh, u32 pid);
>> +static void dect_cell_schedule_page(struct dect_cell *cell, u32 
>> mask);
>> +
>> +static const u8 dect_fp_preamble[]     = { 0x55, 0x55, 0xe9, 0x8a};
>> +static const u8 dect_pp_preamble[]     = { 0xaa, 0xaa, 0x16, 0x75};
>> +
>> +static const u8 dect_b_field_sizes[] = {
>> +       [DECT_PACKET_P00]       = 0,
>> +       [DECT_PACKET_P32]       = 40,
>> +       [DECT_PACKET_P640j]     = 80,
>> +       [DECT_PACKET_P80]       = 100,
>> +};
>> +
>> +static u8 dect_b_field_size(const struct dect_channel_desc *chd)
>> +{
>> +       return dect_b_field_sizes[chd->pkt];
>> +}
>> +
>> +#define mac_debug(cell, base, fmt, args...) \
>> +       pr_debug("%s %u.%.2u.%.2u: " fmt, \
>> +                (base) == DECT_TIMER_TX ? "TX" : "RX", \
>> +                cell->timer_base[(base)].mfn, 
>> cell->timer_base[(base)].framenum, \
>> +                cell->timer_base[(base)].slot, ## args)
>> +
>> +#define rx_debug(cell, fmt, args...) \
>> +       mac_debug(cell, DECT_TIMER_RX, fmt, ## args)
>> +#define tx_debug(cell, fmt, args...) \
>> +       mac_debug(cell, DECT_TIMER_TX, fmt, ## args)
>> +
>> +static LIST_HEAD(dect_cell_list);
>> +
>> +struct dect_cell *dect_cell_get_by_index(u32 index)
>> +{
>> +       struct dect_cell *cell;
>> +
>> +       list_for_each_entry(cell, &dect_cell_list, list) {
>> +               if (cell->index == index)
>> +                       return cell;
>> +       }
>> +       return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_cell_get_by_index);
>> +
>> +static struct dect_cell *dect_cell_get_by_name(const struct nlattr 
>> *nla)
>> +{
>> +       struct dect_cell *cell;
>> +
>> +       list_for_each_entry(cell, &dect_cell_list, list) {
>> +               if (!nla_strcmp(nla, cell->name))
>> +                       return cell;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static struct dect_cell *dect_cell(const struct dect_cell_handle *ch)
>> +{
>> +       return container_of(ch, struct dect_cell, handle);
>> +}
>> +
>> +/*
>> + * MAC CSF layer timers
>> + */
>> +
>> +#if 0
>> +#define timer_debug(cell, base, fmt, args...) \
>> +       mac_debug(cell, base, fmt, ## args)
>> +#else
>> +#define timer_debug(cell, base, fmt, args...)
>> +#endif
>> +
>> +static u8 dect_slotnum(const struct dect_cell *cell, enum 
>> dect_timer_bases b)
>> +{
>> +       return __dect_slotnum(&cell->timer_base[b]);
>> +}
>> +
>> +static u8 dect_framenum(const struct dect_cell *cell, enum 
>> dect_timer_bases b)
>> +{
>> +       return __dect_framenum(&cell->timer_base[b]);
>> +}
>> +
>> +static u32 dect_mfn(const struct dect_cell *cell, enum 
>> dect_timer_bases b)
>> +{
>> +       return __dect_mfn(&cell->timer_base[b]);
>> +}
>> +
>> +/* Return whether the TX time is in the next frame relative to the RX 
>> time */
>> +static bool dect_tx_time_wrapped(const struct dect_cell *cell)
>> +{
>> +       return dect_slotnum(cell, DECT_TIMER_TX) <
>> +              dect_slotnum(cell, DECT_TIMER_RX);
>> +}
>> +
>> +/**
>> + * dect_timer_synchronize_framenum
>> + *
>> + * Synchronize the current frame number based on Q-channel reception.
>> + *
>> + * Q-channel information is transmitted only in frame 8 and serves as 
>> an
>> + * indirect indication. The TX frame number update needs to take the 
>> clock
>> + * difference into account.
>> + */
>> +static void dect_timer_synchronize_framenum(struct dect_cell *cell, 
>> u8 framenum)
>> +{
>> +       cell->timer_base[DECT_TIMER_RX].framenum = framenum;
>> +       if (dect_tx_time_wrapped(cell))
>> +               framenum++;
>> +       cell->timer_base[DECT_TIMER_TX].framenum = framenum;
>> +}
>> +
>> +static void dect_timer_synchronize_mfn(struct dect_cell *cell, u32 
>> mfn)
>> +{
>> +       cell->timer_base[DECT_TIMER_RX].mfn = mfn;
>> +       cell->timer_base[DECT_TIMER_TX].mfn = mfn;
>> +       cell->timer_sync_stamp = mfn;
>> +}
>> +
>> +static void dect_run_timers(struct dect_cell *cell, enum 
>> dect_timer_bases b)
>> +{
>> +       __dect_run_timers(cell->name, &cell->timer_base[b]);
>> +}
>> +
>> +static void dect_timer_base_update(struct dect_cell *cell,
>> +                                  enum dect_timer_bases b, u8 slot)
>> +{
>> +       struct dect_timer_base *base = &cell->timer_base[b];
>> +
>> +       base->slot = slot;
>> +       if (base->slot == 0) {
>> +               base->framenum = dect_next_framenum(base->framenum);
>> +               if (base->framenum == 0)
>> +                       base->mfn = dect_next_mfn(base->mfn);
>> +       }
>> +       timer_debug(cell, base, "update time base\n");
>> +}
>> +
>> +/**
>> + * dect_timer_add - (re)schedule a timer
>> + *
>> + * Frame numbers are relative to the current time, slot positions are 
>> absolute.
>> + * A timer scheduled for (1, 2) will expire in slot 2 in the next 
>> frame.
>> + *
>> + * A frame number of zero will expire at the next occurence of the 
>> slot, which
>> + * can be within the same frame in case the slot is not already in 
>> the past, or
>> + * in the next frame in case it is.
>> + */
>> +static void dect_timer_add(struct dect_cell *cell, struct dect_timer 
>> *timer,
>> +                          enum dect_timer_bases base, u32 frame, u8 
>> slot)
>> +{
>> +       timer->cell = cell;
>> +       __dect_timer_add(cell->name, &cell->timer_base[base], timer, 
>> frame, slot);
>> +}
>> +
>> +static void dect_timer_setup(struct dect_timer *timer,
>> +                            void (*func)(struct dect_cell *, void *),
>> +                            void *data)
>> +{
>> +       dect_timer_init(timer);
>> +       timer->cb.cell = func;
>> +       timer->data    = data;
>> +}
>> +
>> +/*
>> + * Basic Channel lists
>> + *
>> + * A channel list contains channel descriptions of all physical 
>> channels
>> + * able to carry the packet type, sorted into multiple bins based on 
>> the
>> + * maximum RSSI value of the TDD slot pair.
>> + *
>> + * At any time, only a single incomplete channel list exists that is 
>> updated
>> + * based on the RSSI measurements gathered by the individual IRC 
>> instances.
>> + * Once a list is complete, it is added to the list of active channel 
>> lists,
>> + * replacing the previous one for the same packet type, if any.
>> + */
>> +
>> +#if 1
>> +#define chl_debug(cell, chl, fmt, args...) \
>> +       rx_debug(cell, "channel-list %s (%u): " fmt, \
>> +                (chl)->pkt == DECT_PACKET_P00 ? "P00" : \
>> +                (chl)->pkt == DECT_PACKET_P08 ? "P08" : \
>> +                (chl)->pkt == DECT_PACKET_P32 ? "P32" : "?", \
>> +                (chl)->available, ## args)
>> +#else
>> +#define chl_debug(cell, chl, fmt, args...)
>> +#endif
>> +
>> +static int dect_chl_schedule_update(struct dect_cell *cell,
>> +                                   enum dect_packet_types pkt);
>> +
>> +static struct dect_channel_list *dect_chl_lookup(const struct 
>> dect_cell *cell,
>> +                                                enum 
>> dect_packet_types pkt)
>> +{
>> +       struct dect_channel_list *chl;
>> +
>> +       list_for_each_entry(chl, &cell->chanlists, list) {
>> +               if (chl->pkt == pkt)
>> +                       return chl;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static void dect_chl_timer(struct dect_cell *cell, void *data)
>> +{
>> +       struct dect_channel_list *chl = data;
>> +
>> +       if (dect_chl_schedule_update(cell, chl->pkt) < 0)
>> +               dect_timer_add(cell, &chl->timer, DECT_TIMER_RX, 1, 
>> 0);
>> +}
>> +
>> +static void dect_chl_release(struct dect_channel_list *chl)
>> +{
>> +       dect_timer_del(&chl->timer);
>> +       kfree(chl);
>> +}
>> +
>> +static struct dect_channel_list *dect_chl_init(struct dect_cell 
>> *cell,
>> +                                              enum dect_packet_types 
>> pkt)
>> +{
>> +       struct dect_channel_list *chl;
>> +       unsigned int entries, i;
>> +
>> +       entries = DECT_CARRIER_NUM * DECT_HALF_FRAME_SIZE;
>> +       chl = kzalloc(sizeof(*chl) + entries * 
>> sizeof(chl->entries[0]), GFP_ATOMIC);
>> +       if (chl == NULL)
>> +               return NULL;
>> +       chl->pkt = pkt;
>> +       dect_timer_setup(&chl->timer, dect_chl_timer, chl);
>> +       for (i = 0; i < ARRAY_SIZE(chl->bins); i++)
>> +               INIT_LIST_HEAD(&chl->bins[i]);
>> +       for (i = 0; i < entries; i++)
>> +               INIT_LIST_HEAD(&chl->entries[i].list);
>> +       return chl;
>> +}
>> +
>> +static int dect_chl_schedule_update(struct dect_cell *cell,
>> +                                   enum dect_packet_types pkt)
>> +{
>> +       struct dect_channel_list *chl;
>> +
>> +       list_for_each_entry(chl, &cell->chl_pending, list) {
>> +               if (chl->pkt == pkt)
>> +                       return 0;
>> +       }
>> +
>> +       chl = dect_chl_init(cell, pkt);
>> +       if (chl == NULL)
>> +               return -ENOMEM;
>> +       chl_debug(cell, chl, "schedule update\n");
>> +       list_add_tail(&chl->list, &cell->chl_pending);
>> +       return 0;
>> +}
>> +
>> +static struct dect_channel_list *dect_chl_get_pending(struct 
>> dect_cell *cell)
>> +{
>> +       struct dect_channel_list *chl;
>> +
>> +       if (list_empty(&cell->chl_pending))
>> +               return NULL;
>> +       chl = list_first_entry(&cell->chl_pending,
>> +                              struct dect_channel_list,
>> +                              list);
>> +       list_del(&chl->list);
>> +       return chl;
>> +}
>> +
>> +static void dect_chl_update(struct dect_cell *cell,
>> +                           struct dect_channel_list *chl,
>> +                           const struct dect_channel_desc *chd, u8 
>> rssi)
>> +{
>> +       struct dect_channel_list_entry *e;
>> +       u8 slot, bin;
>> +
>> +       if (rssi > dect_dbm_to_rssi(DECT_CHANNEL_LIST_MAX_DBM)) {
>> +               chl_debug(cell, chl, "carrier %u slot %u: too much 
>> noise: RSSI %u\n",
>> +                         chd->carrier, chd->slot, rssi);
>> +               return;
>> +       }
>> +
>> +       slot = chd->slot < 12 ? chd->slot : chd->slot - 12;
>> +       chl_debug(cell, chl, "update carrier %u slot %u pos %u RSSI 
>> %u\n",
>> +                 chd->carrier, chd->slot, slot, rssi);
>> +
>> +       e = &chl->entries[chd->carrier * DECT_HALF_FRAME_SIZE + slot];
>> +       if (!list_empty(&e->list))
>> +               return;
>> +
>> +       if (chd->slot < DECT_HALF_FRAME_SIZE) {
>> +               e->slot    = slot;
>> +               e->carrier = chd->carrier;
>> +               e->rssi    = rssi;
>> +       } else if (e->rssi != 0) {
>> +               e->rssi = max(e->rssi, rssi);
>> +               bin = rssi * ARRAY_SIZE(chl->bins) / (DECT_RSSI_RANGE 
>> + 1);
>> +
>> +               list_add_tail(&e->list, &chl->bins[bin]);
>> +               chl->available++;
>> +       }
>> +}
>> +
>> +static void dect_chl_update_carrier(struct dect_cell *cell, u8 
>> carrier)
>> +{
>> +       struct dect_channel_list *chl, *old;
>> +
>> +       chl = cell->chl;
>> +       chl_debug(cell, chl, "update status %llx rfcars %x carrier 
>> %u\n",
>> +                 (unsigned long long)chl->status, 
>> cell->si.ssi.rfcars, carrier);
>> +
>> +       chl->status |= 1ULL << carrier;
>> +       if (chl->status != cell->si.ssi.rfcars)
>> +               return;
>> +       cell->chl = NULL;
>> +
>> +       chl_debug(cell, chl, "complete %u entries\n", chl->available);
>> +       old = dect_chl_lookup(cell, chl->pkt);
>> +       if (old != NULL) {
>> +               list_del(&old->list);
>> +               dect_chl_release(old);
>> +       }
>> +
>> +       dect_timer_add(cell, &chl->timer, DECT_TIMER_RX,
>> +                      DECT_CHANNEL_LIST_MAX_AGE * 2 / 3 *
>> +                      DECT_FRAMES_PER_SECOND, 0);
>> +       list_add_tail(&chl->list, &cell->chanlists);
>> +}
>> +
>> +/**
>> + * dect_channel_delay - calculate delay in frames until a channel is 
>> accessible
>> + *
>> + * Calculate the delay in frames until one of the remote sides' scans 
>> is on the
>> + * specified carrier.
>> + *
>> + * A FP maintains one to three scans, which lag behind each other by 
>> three
>> + * carriers, a PP maintains zero or one (fast-setup) scan. The PP 
>> fast-
>> + * setup scan leads the FP primary scan by one carrier.
>> + *
>> + * Setup needs at least one full frame, therefore a scan reaching a 
>> carrier
>> + * earlier than that must be treated as reachable one cycle later.
>> + */
>> +static u8 dect_channel_delay(const struct dect_cell *cell,
>> +                            const struct dect_channel_desc *chd)
>> +{
>> +       u64 rfcars = cell->si.ssi.rfcars;
>> +       u8 i, txs, scn, frames;
>> +       s8 d;
>> +
>> +       if (cell->mode == DECT_MODE_FP) {
>> +               /* PP fast-setup scan */
>> +               scn = dect_next_carrier(rfcars, cell->si.ssi.pscn);
>> +               txs = 1;
>> +       } else {
>> +               /* FP primary scan */
>> +               scn = dect_prev_carrier(rfcars, cell->si.ssi.pscn);
>> +               txs = min(cell->si.ssi.txs + 1, 3);
>> +       }
>> +
>> +       frames = ~0;
>> +       for (i = 0; i < txs; i++) {
>> +               d = dect_carrier_distance(rfcars, scn, chd->carrier);
>> +#if 0
>> +               if (dect_slotnum(cell, DECT_TIMER_TX) >= chd->slot)
>> +                       d--;
>> +#endif
>> +               /* More than two frames in the future? */
>> +               if (d <= DECT_CHANNEL_MIN_DELAY)
>> +                       d += hweight64(rfcars);
>> +
>> +               frames = min_t(u8, frames, d);
>> +               pr_debug("rfcars %llx distance %u->%u slot %u: %u 
>> frames %u\n",
>> +                        (unsigned long long)rfcars, scn, 
>> chd->carrier,
>> +                        chd->slot, d, frames);
>> +
>> +               scn = dect_carrier_sub(rfcars, scn, 3);
>> +       }
>> +
>> +       return frames;
>> +}
>> +
>> +static void dect_update_blind_full_slots(struct dect_cell *cell)
>> +{
>> +       u16 bfs;
>> +
>> +       bfs = ~(cell->trg.blind_full_slots | 
>> (cell->trg.blind_full_slots >> 12));
>> +       cell->trg_blind_full_slots = bfs & ((1 << 
>> DECT_HALF_FRAME_SIZE) - 1);
>> +
>> +       dect_cell_schedule_page(cell, 1 << DECT_TM_TYPE_BFS);
>> +}
>> +
>> +/**
>> + * dect_channel_reserve - reserve a channel on a transceiver
>> + *
>> + * Reserve the specified transceiver and schedule a blind-full-slots
>> + * page message if the visibility state changed.
>> + */
>> +static void dect_channel_reserve(struct dect_cell *cell,
>> +                                struct dect_transceiver *trx,
>> +                                const struct dect_channel_desc *chd)
>> +{
>> +       if (!dect_transceiver_reserve(&cell->trg, trx, chd))
>> +               return;
>> +
>> +       dect_update_blind_full_slots(cell);
>> +}
>> +
>> +/**
>> + * dect_channel_release - release a channel on a transceiver
>> + *
>> + * Release the specified transceiver and schedule a blind-full-slots
>> + * page message if the visibility state changed.
>> + */
>> +static void dect_channel_release(struct dect_cell *cell,
>> +                                struct dect_transceiver *trx,
>> +                                const struct dect_channel_desc *chd)
>> +{
>> +       if (!dect_transceiver_release(&cell->trg, trx, chd))
>> +               return;
>> +
>> +       dect_update_blind_full_slots(cell);
>> +}
>> +
>> +/**
>> + * dect_select_transceiver - select a transceiver for placing a 
>> bearer
>> + *
>> + * Select the lowest order transceiver that is able to operate on a 
>> physical
>> + * channel.
>> + */
>> +static struct dect_transceiver *
>> +dect_select_transceiver(const struct dect_cell *cell,
>> +                       const struct dect_channel_desc *chd)
>> +{
>> +       struct dect_transceiver *trx;
>> +
>> +       dect_foreach_transceiver_reverse(trx, &cell->trg) {
>> +               if (trx->state != DECT_TRANSCEIVER_LOCKED)
>> +                       continue;
>> +               if (!dect_transceiver_channel_available(trx, chd))
>> +                       continue;
>> +               return trx;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +/**
>> + * dect_select_channel - select a physical channel for bearer setup
>> + *
>> + * @cell:      DECT cell
>> + * @trx:       selected transceiver
>> + * @chd:       channel description
>> + * @rssi:      last measure RSSI value of selected channel
>> + * @quick:     prefer quickly accessible channel
>> + *
>> + * This performs the common steps of channel selection based on 
>> channel lists.
>> + * In "quick" mode, the selected channel is the first channel 
>> accessible within
>> + * three TDMA frames from the lowest three available bands. When not 
>> in quick
>> + * mode or when no channel is accessible within three frames, the 
>> first
>> + * available channel from the lowest available band is selected.
>> + *
>> + * "quick" mode is used for setting up pilot bearers and for bearer 
>> handover.
>> + *
>> + * The returned channel description is within the normal transmit 
>> half
>> + * of the cell's mode.
>> + */
>> +static int dect_select_channel(struct dect_cell *cell,
>> +                              struct dect_transceiver **trxp,
>> +                              struct dect_channel_desc *chd, u8 
>> *rssi,
>> +                              bool quick)
>> +{
>> +       struct dect_channel_list_entry *e, *sel;
>> +       struct dect_channel_list *chl;
>> +       struct dect_transceiver *trx, *uninitialized_var(tsel);
>> +       u8 bin, first, last;
>> +
>> +       chl = dect_chl_lookup(cell, chd->pkt);
>> +       if (chl == NULL)
>> +               return -ENOENT;
>> +
>> +       /* Find first non-empty bin */
>> +       for (first = 0; first < ARRAY_SIZE(chl->bins); first++) {
>> +               if (!list_empty(&chl->bins[first]))
>> +                       break;
>> +       }
>> +       if (first == ARRAY_SIZE(chl->bins))
>> +               return -ENOSPC;
>> +
>> +       sel = NULL;
>> +retry:
>> +       last = max_t(u8, first + quick ? 3 : 1, 
>> ARRAY_SIZE(chl->bins));
>> +       for (bin = first; sel == NULL && bin < last; bin++) {
>> +               list_for_each_entry(e, &chl->bins[bin], list) {
>> +                       u8 n = DECT_HALF_FRAME_SIZE - 1 - e->slot;
>> +
>> +                       if (!(cell->trg_blind_full_slots & (1 << n)))
>> +                               continue;
>> +
>> +                       if (cell->mode == DECT_MODE_PP &&
>> +                           !(cell->blind_full_slots & (1 << n)))
>> +                               continue;
>> +
>> +                       chd->carrier = e->carrier;
>> +                       chd->slot = 
>> dect_normal_transmit_base(cell->mode) + e->slot;
>> +                       if (quick && dect_channel_delay(cell, chd) > 
>> 3)
>> +                               continue;
>> +
>> +                       trx = dect_select_transceiver(cell, chd);
>> +                       if (trx == NULL)
>> +                               continue;
>> +                       if (sel != NULL) {
>> +                               if (trx->index < tsel->index)
>> +                                       continue;
>> +                               if (sel->rssi < e->rssi)
>> +                                       continue;
>> +                       }
>> +
>> +                       sel  = e;
>> +                       tsel = trx;
>> +
>> +                       /* Stop searching if this is the best possible 
>> choice */
>> +                       if (tsel->index == 
>> hweight16(cell->trg.trxmask))
>> +                               break;
>> +               }
>> +       }
>> +
>> +       if (sel == NULL) {
>> +               /* Check the first band again without considering 
>> delay when
>> +                * no quickly accessible channel is available within 
>> the first
>> +                * three bands. */
>> +               if (quick) {
>> +                       quick = false;
>> +                       goto retry;
>> +               }
>> +               return -ENOSPC;
>> +       }
>> +
>> +       list_del_init(&sel->list);
>> +       chl->available--;
>> +       if (chl->available < DECT_CHANNEL_LIST_LOW_WATERMARK)
>> +               dect_chl_schedule_update(cell, chl->pkt);
>> +
>> +       chd->carrier = sel->carrier;
>> +       chd->slot = dect_normal_transmit_base(cell->mode) + sel->slot;
>> +       chl_debug(cell, chl, "select channel: carrier %u slot %u RSSI 
>> %u\n",
>> +                 chd->carrier, chd->slot, sel->rssi);
>> +
>> +       *rssi = sel->rssi;
>> +       *trxp = tsel;
>> +       return 0;
>> +}
>> +
>> +static struct dect_dbc *dect_dbc_get(const struct dect_cell *cell)
>> +{
>> +       if (list_empty(&cell->dbcs))
>> +               return NULL;
>> +       return list_first_entry(&cell->dbcs, struct dect_dbc, list);
>> +}
>> +
>> +
>> +/*
>> + * Tail message parsing/construction
>> + */
>> +
>> +static enum dect_tail_identifications dect_parse_tail(const struct 
>> sk_buff *skb)
>> +{
>> +       return skb->data[DECT_HDR_TA_OFF] & DECT_HDR_TA_MASK;
>> +}
>> +
>> +static enum dect_b_identifications dect_parse_b_id(const struct 
>> sk_buff *skb)
>> +{
>> +       return skb->data[DECT_HDR_TA_OFF] & DECT_HDR_BA_MASK;
>> +}
>> +
>> +static int dect_parse_identities_information(struct dect_tail_msg 
>> *tm, u64 t)
>> +{
>> +       struct dect_idi *idi = &tm->idi;
>> +       u8 ari_len, rpn_len;
>> +
>> +       ari_len = dect_parse_ari(&idi->pari, t << 
>> DECT_RFPI_ARI_SHIFT);
>> +       if (ari_len == 0)
>> +               return -1;
>> +       rpn_len = BITS_PER_BYTE * DECT_NT_ID_RFPI_LEN - 1 - ari_len;
>> +
>> +       idi->e   = (t & DECT_RFPI_E_FLAG);
>> +       idi->rpn = (t >> DECT_RFPI_RPN_SHIFT) & ((1 << rpn_len) - 1);
>> +       tm->type = DECT_TM_TYPE_ID;
>> +
>> +       pr_debug("identities information: e: %u class: %u emc: %.4x "
>> +                "fpn: %.5x rpn: %x\n", idi->e, idi->pari.arc,
>> +                idi->pari.emc, idi->pari.fpn, idi->rpn);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_identities_information(const struct dect_idi 
>> *idi)
>> +{
>> +       return dect_build_rfpi(idi);
>> +}
>> +
>> +static int dect_parse_static_system_information(struct dect_tail_msg 
>> *tm, u64 t)
>> +{
>> +       struct dect_ssi *ssi = &tm->ssi;
>> +
>> +       ssi->nr     = (t & DECT_QT_SSI_NR_FLAG);
>> +       ssi->sn     = (t & DECT_QT_SSI_SN_MASK) >> 
>> DECT_QT_SSI_SN_SHIFT;
>> +       ssi->sp     = (t & DECT_QT_SSI_SP_MASK) >> 
>> DECT_QT_SSI_SP_SHIFT;
>> +       ssi->txs    = (t & DECT_QT_SSI_TXS_MASK) >> 
>> DECT_QT_SSI_TXS_SHIFT;
>> +       ssi->mc     = (t & DECT_QT_SSI_MC_FLAG);
>> +       ssi->rfcars = (t & DECT_QT_SSI_RFCARS_MASK) >> 
>> DECT_QT_SSI_RFCARS_SHIFT;
>> +       ssi->cn     = (t & DECT_QT_SSI_CN_MASK) >> 
>> DECT_QT_SSI_CN_SHIFT;
>> +       ssi->pscn   = (t & DECT_QT_SSI_PSCN_MASK) >> 
>> DECT_QT_SSI_PSCN_SHIFT;
>> +
>> +       if (ssi->sn > 11 || ssi->cn > 9 || ssi->pscn > 9 || 
>> ssi->rfcars == 0)
>> +               return -1;
>> +       tm->type = DECT_TM_TYPE_SSI;
>> +
>> +       pr_debug("static system information: nr: %u sn: %u cn: %u 
>> pscn: %u\n",
>> +                ssi->nr, ssi->sn, ssi->cn, ssi->pscn);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_static_system_information(const struct dect_ssi 
>> *ssi)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= ssi->nr ? DECT_QT_SSI_NR_FLAG : 0;
>> +       t |= (u64)ssi->sn << DECT_QT_SSI_SN_SHIFT;
>> +       t |= (u64)ssi->sp << DECT_QT_SSI_SP_SHIFT;
>> +       t |= (u64)ssi->txs << DECT_QT_SSI_TXS_SHIFT;
>> +       t |= (u64)ssi->cn << DECT_QT_SSI_CN_SHIFT;
>> +       t |= ssi->mc ? DECT_QT_SSI_MC_FLAG : 0;
>> +       t |= (u64)ssi->rfcars << DECT_QT_SSI_RFCARS_SHIFT;
>> +       t |= (u64)ssi->pscn << DECT_QT_SSI_PSCN_SHIFT;
>> +       t |= DECT_QT_SI_SSI;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_extended_rf_carrier_information(struct 
>> dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_erfc *erfc = &tm->erfc;
>> +
>> +       erfc->rfcars     = (t & DECT_QT_ERFC_RFCARS_MASK) >>
>> +                          DECT_QT_ERFC_RFCARS_SHIFT;
>> +       erfc->band       = (t & DECT_QT_ERFC_RFBAND_MASK) >>
>> +                          DECT_QT_ERFC_RFBAND_SHIFT;
>> +       erfc->num_rfcars = (t & DECT_QT_ERFC_NUM_RFCARS_MASK) >
>> +                          DECT_QT_ERFC_NUM_RFCARS_SHIFT;
>> +       tm->type = DECT_TM_TYPE_ERFC;
>> +
>> +       pr_debug("extended rf carrier information: rfcars %.6x band %u 
>> num %u\n",
>> +                erfc->rfcars, erfc->band, erfc->num_rfcars);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_extended_rf_carrier_information(const struct 
>> dect_erfc *erfc)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)erfc->rfcars << DECT_QT_ERFC_RFCARS_SHIFT;
>> +       t |= (u64)erfc->band << DECT_QT_ERFC_RFBAND_SHIFT;
>> +       t |= (u64)erfc->num_rfcars << DECT_QT_ERFC_NUM_RFCARS_SHIFT;
>> +       t |= DECT_QT_SI_ERFC;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_fixed_part_capabilities(struct dect_tail_msg 
>> *tm, u64 t)
>> +{
>> +       struct dect_fpc *fpc = &tm->fpc;
>> +
>> +       fpc->fpc = (t & DECT_QT_FPC_CAPABILITY_MASK) >>
>> +                  DECT_QT_FPC_CAPABILITY_SHIFT;
>> +       fpc->hlc = (t & DECT_QT_FPC_HLC_MASK) >> 
>> DECT_QT_FPC_HLC_SHIFT;
>> +       tm->type = DECT_TM_TYPE_FPC;
>> +
>> +       pr_debug("fixed part capabilities: fpc: %.5x hlc: %.4x\n",
>> +                fpc->fpc, fpc->hlc);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_fixed_part_capabilities(const struct dect_fpc 
>> *fpc)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)fpc->fpc << DECT_QT_FPC_CAPABILITY_SHIFT;
>> +       t |= (u64)fpc->hlc << DECT_QT_FPC_HLC_SHIFT;
>> +       t |= DECT_QT_SI_FPC;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_extended_fixed_part_capabilities(struct 
>> dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_efpc *efpc = &tm->efpc;
>> +
>> +       efpc->fpc = (t & DECT_QT_EFPC_EFPC_MASK) >> 
>> DECT_QT_EFPC_EFPC_SHIFT;
>> +       efpc->hlc = (t & DECT_QT_EFPC_EHLC_MASK) >> 
>> DECT_QT_EFPC_EHLC_SHIFT;
>> +       tm->type  = DECT_TM_TYPE_EFPC;
>> +
>> +       pr_debug("extended fixed part capabilities: fpc: %.5x hlc: 
>> %.6x\n",
>> +                efpc->fpc, efpc->hlc);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_extended_fixed_part_capabilities(const struct 
>> dect_efpc *efpc)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)efpc->fpc << DECT_QT_EFPC_EFPC_SHIFT;
>> +       t |= (u64)efpc->hlc << DECT_QT_EFPC_EHLC_SHIFT;
>> +       t |= DECT_QT_SI_EFPC;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_extended_fixed_part_capabilities2(struct 
>> dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_efpc2 *efpc2 = &tm->efpc2;
>> +
>> +       efpc2->fpc = (t & DECT_QT_EFPC2_FPC_MASK) >> 
>> DECT_QT_EFPC2_FPC_SHIFT;
>> +       efpc2->hlc = (t & DECT_QT_EFPC2_HLC_MASK) >> 
>> DECT_QT_EFPC2_HLC_SHIFT;
>> +       tm->type   = DECT_TM_TYPE_EFPC2;
>> +
>> +       pr_debug("extended fixed part capabilities2: fpc: %x hlc: 
>> %x\n",
>> +                efpc2->fpc, efpc2->hlc);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_extended_fixed_part_capabilities2(const struct 
>> dect_efpc2 *efpc2)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)efpc2->fpc << DECT_QT_EFPC2_FPC_SHIFT;
>> +       t |= (u64)efpc2->hlc << DECT_QT_EFPC2_HLC_SHIFT;
>> +       t |= DECT_QT_SI_EFPC2;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_sari(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_sari *sari = &tm->sari;
>> +
>> +       sari->list_cycle = (((t & DECT_QT_SARI_LIST_CYCLE_MASK) >>
>> +                            DECT_QT_SARI_LIST_CYCLE_SHIFT) + 1) * 2;
>> +       sari->tari  = (t & DECT_QT_SARI_TARI_FLAG);
>> +       sari->black = (t & DECT_QT_SARI_BLACK_FLAG);
>> +       dect_parse_ari(&sari->ari, t << DECT_QT_SARI_ARI_SHIFT);
>> +       tm->type = DECT_TM_TYPE_SARI;
>> +
>> +       pr_debug("sari: cycle %u tari: %u black: %u\n",
>> +                sari->list_cycle, sari->tari, sari->black);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_sari(const struct dect_sari *sari)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= sari->tari ? DECT_QT_SARI_TARI_FLAG : 0;
>> +       t |= sari->black ? DECT_QT_SARI_BLACK_FLAG : 0;
>> +       t |= dect_build_ari(&sari->ari) >> DECT_QT_SARI_ARI_SHIFT;
>> +       t |= DECT_QT_SI_SARI;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_multiframe_number(struct dect_tail_msg *tm, u64 
>> t)
>> +{
>> +       tm->mfn.num = (t & DECT_QT_MFN_MASK) >> DECT_QT_MFN_SHIFT;
>> +       tm->type = DECT_TM_TYPE_MFN;
>> +
>> +       pr_debug("multi-frame number: %u\n", tm->mfn.num);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_multiframe_number(const struct dect_mfn *mfn)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)mfn->num << DECT_QT_MFN_SHIFT;
>> +       t |= DECT_QT_SI_MFN;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_system_information(struct dect_tail_msg *tm, 
>> u64 t)
>> +{
>> +       /* clear of memcmp */
>> +       memset(((void *)tm) + offsetof(struct dect_tail_msg, ssi), 0,
>> +              sizeof(*tm) - offsetof(struct dect_tail_msg, ssi));
>> +
>> +       switch (t & DECT_QT_H_MASK) {
>> +       case DECT_QT_SI_SSI:
>> +       case DECT_QT_SI_SSI2:
>> +               return dect_parse_static_system_information(tm, t);
>> +       case DECT_QT_SI_ERFC:
>> +               return dect_parse_extended_rf_carrier_information(tm, 
>> t);
>> +       case DECT_QT_SI_FPC:
>> +               return dect_parse_fixed_part_capabilities(tm, t);
>> +       case DECT_QT_SI_EFPC:
>> +               return dect_parse_extended_fixed_part_capabilities(tm, 
>> t);
>> +       case DECT_QT_SI_EFPC2:
>> +               return 
>> dect_parse_extended_fixed_part_capabilities2(tm, t);
>> +       case DECT_QT_SI_SARI:
>> +               return dect_parse_sari(tm, t);
>> +       case DECT_QT_SI_MFN:
>> +               return dect_parse_multiframe_number(tm, t);
>> +       default:
>> +               pr_debug("unknown system information type %llx\n",
>> +                        (unsigned long long)t & DECT_QT_H_MASK);
>> +               return -1;
>> +       }
>> +}
>> +
>> +static int dect_parse_blind_full_slots(struct dect_tail_msg *tm, u64 
>> t)
>> +{
>> +       struct dect_bfs *bfs = &tm->bfs;
>> +
>> +       bfs->mask = (t & DECT_PT_BFS_MASK) >> DECT_PT_BFS_SHIFT;
>> +       tm->type = DECT_TM_TYPE_BFS;
>> +
>> +       pr_debug("page: RFPI: %.3x blind full slots: %.3x\n",
>> +                tm->page.rfpi, bfs->mask);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_blind_full_slots(const struct dect_bfs *bfs)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)bfs->mask << DECT_PT_BFS_SHIFT;
>> +       t |= DECT_PT_IT_BLIND_FULL_SLOT;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_bearer_description(struct dect_tail_msg *tm, 
>> u64 t)
>> +{
>> +       struct dect_bearer_desc *bd = &tm->bd;
>> +
>> +       bd->bt = (t & DECT_PT_INFO_TYPE_MASK);
>> +       bd->sn = (t & DECT_PT_BEARER_SN_MASK) >> 
>> DECT_PT_BEARER_SN_SHIFT;
>> +       bd->sp = (t & DECT_PT_BEARER_SP_MASK) >> 
>> DECT_PT_BEARER_SP_SHIFT;
>> +       bd->cn = (t & DECT_PT_BEARER_CN_MASK) >> 
>> DECT_PT_BEARER_CN_SHIFT;
>> +       if (bd->sn >= DECT_HALF_FRAME_SIZE)
>> +               return -1;
>> +       tm->type = DECT_TM_TYPE_BD;
>> +
>> +       pr_debug("page: RFPI: %.3x bearer description: bt: %llx sn: %u 
>> sp: %u cn: %u\n",
>> +                tm->page.rfpi, (unsigned long long)bd->bt, bd->sn, 
>> bd->sp, bd->cn);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_bearer_description(const struct 
>> dect_bearer_desc *bd)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)bd->sn << DECT_PT_BEARER_SN_SHIFT;
>> +       t |= (u64)bd->sp << DECT_PT_BEARER_SP_SHIFT;
>> +       t |= (u64)bd->cn << DECT_PT_BEARER_CN_SHIFT;
>> +       t |= bd->bt;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_rfp_identity(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_rfp_id *id = &tm->rfp_id;
>> +
>> +       id->id = (t & DECT_PT_RFP_ID_MASK) >> DECT_PT_RFP_ID_SHIFT;
>> +       tm->type = DECT_TM_TYPE_RFP_ID;
>> +
>> +       pr_debug("page: RFPI: %.3x RFP identity: %.3x\n",
>> +                tm->page.rfpi, id->id);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_rfp_identity(const struct dect_rfp_id *id)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)id->id << DECT_PT_RFP_ID_SHIFT;
>> +       t |= DECT_PT_IT_RFP_IDENTITY;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_rfp_status(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_rfp_status *st = &tm->rfp_status;
>> +
>> +       st->rfp_busy = t & DECT_PT_RFPS_RFP_BUSY_FLAG;
>> +       st->sys_busy = t & DECT_PT_RFPS_SYS_BUSY_FLAG;
>> +       tm->type = DECT_TM_TYPE_RFP_STATUS;
>> +
>> +       pr_debug("page: RFPI: %.3x RFP status: rfp_busy: %d sys_busy: 
>> %d\n",
>> +                tm->page.rfpi, st->rfp_busy, st->sys_busy);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_rfp_status(const struct dect_rfp_status *st)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= st->rfp_busy ? DECT_PT_RFPS_RFP_BUSY_FLAG : 0;
>> +       t |= st->sys_busy ? DECT_PT_RFPS_SYS_BUSY_FLAG : 0;
>> +       t |= DECT_PT_IT_RFP_STATUS;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_active_carriers(struct dect_tail_msg *tm, u64 
>> t)
>> +{
>> +       struct dect_active_carriers *ac = &tm->active_carriers;
>> +
>> +       ac->active = (t & DECT_PT_ACTIVE_CARRIERS_MASK) >>
>> +                    DECT_PT_ACTIVE_CARRIERS_SHIFT;
>> +       tm->type = DECT_TM_TYPE_ACTIVE_CARRIERS;
>> +
>> +       pr_debug("page: RFPI: %.3x active carriers: %.3x\n",
>> +                tm->page.rfpi, ac->active);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_active_carriers(const struct 
>> dect_active_carriers *ac)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)ac->active << DECT_PT_ACTIVE_CARRIERS_SHIFT;
>> +       t |= DECT_PT_IT_ACTIVE_CARRIERS;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_paging_info(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       switch (t & DECT_PT_INFO_TYPE_MASK) {
>> +       case DECT_PT_IT_BLIND_FULL_SLOT:
>> +               return dect_parse_blind_full_slots(tm, t);
>> +       case DECT_PT_IT_OTHER_BEARER:
>> +       case DECT_PT_IT_RECOMMENDED_OTHER_BEARER:
>> +       case DECT_PT_IT_GOOD_RFP_BEARER:
>> +       case DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION:
>> +       case DECT_PT_IT_CL_BEARER_POSITION:
>> +               return dect_parse_bearer_description(tm, t);
>> +       case DECT_PT_IT_RFP_IDENTITY:
>> +               return dect_parse_rfp_identity(tm, t);
>> +       case DECT_PT_IT_DUMMY_OR_CL_BEARER_MARKER:
>> +               pr_debug("dummy or cl bearer marker\n");
>> +               return 0;
>> +       case DECT_PT_IT_RFP_STATUS:
>> +               return dect_parse_rfp_status(tm, t);
>> +       case DECT_PT_IT_ACTIVE_CARRIERS:
>> +               return dect_parse_active_carriers(tm, t);
>> +       default:
>> +               pr_debug("unknown MAC page info %llx\n",
>> +                        (unsigned long long)t & 
>> DECT_PT_INFO_TYPE_MASK);
>> +               return -1;
>> +       }
>> +}
>> +
>> +static int dect_parse_paging_msg(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       tm->page.extend = t & DECT_PT_HDR_EXTEND_FLAG;
>> +       tm->page.length = t & DECT_PT_HDR_LENGTH_MASK;
>> +
>> +       switch (tm->page.length) {
>> +       case DECT_PT_ZERO_PAGE:
>> +               tm->page.rfpi = (t & DECT_PT_ZP_RFPI_MASK) >>
>> +                               DECT_PT_ZP_RFPI_SHIFT;
>> +
>> +               return dect_parse_paging_info(tm, t);
>> +       case DECT_PT_SHORT_PAGE:
>> +               tm->page.rfpi = 0;
>> +               return dect_parse_paging_info(tm, t);
>> +       case DECT_PT_FULL_PAGE:
>> +       case DECT_PT_LONG_PAGE:
>> +       case DECT_PT_LONG_PAGE_FIRST:
>> +       case DECT_PT_LONG_PAGE_LAST:
>> +       case DECT_PT_LONG_PAGE_ALL:
>> +               tm->type = DECT_TM_TYPE_PAGE;
>> +               pr_debug("full/long page: extend: %u length: %llx\n",
>> +                        tm->page.extend, (unsigned long 
>> long)tm->page.length);
>> +               return 0;
>> +       default:
>> +               pr_debug("invalid page length %llx\n",
>> +                        (unsigned long long)tm->page.length);
>> +               return -1;
>> +       }
>> +}
>> +
>> +static int dect_parse_cctrl_common(struct dect_cctrl *cctl, u64 t)
>> +{
>> +       cctl->fmid = (t & DECT_CCTRL_FMID_MASK) >> 
>> DECT_CCTRL_FMID_SHIFT;
>> +       cctl->pmid = (t & DECT_CCTRL_PMID_MASK) >> 
>> DECT_CCTRL_PMID_SHIFT;
>> +
>> +       pr_debug("cctrl: cmd: %llx fmid: %.3x pmid: %.5x\n",
>> +                (unsigned long long)cctl->cmd, cctl->fmid, 
>> cctl->pmid);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_cctrl_common(const struct dect_cctrl *cctl)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= cctl->cmd;
>> +       t |= (u64)cctl->fmid << DECT_CCTRL_FMID_SHIFT;
>> +       t |= (u64)cctl->pmid << DECT_CCTRL_PMID_SHIFT;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_cctrl_attr(struct dect_cctrl *cctl, u64 t)
>> +{
>> +       cctl->ecn        = (t & DECT_CCTRL_ATTR_ECN_MASK) >> 
>> DECT_CCTRL_ATTR_ECN_SHIFT;
>> +       cctl->lbn        = (t & DECT_CCTRL_ATTR_LBN_MASK) >> 
>> DECT_CCTRL_ATTR_LBN_SHIFT;
>> +       cctl->type       = (t & DECT_CCTRL_ATTR_TYPE_MASK) >> 
>> DECT_CCTRL_ATTR_TYPE_SHIFT;
>> +       cctl->service    = (t & DECT_CCTRL_ATTR_SERVICE_MASK) >> 
>> DECT_CCTRL_ATTR_SERVICE_SHIFT;
>> +       cctl->slot       = (t & DECT_CCTRL_ATTR_SLOT_MASK) >> 
>> DECT_CCTRL_ATTR_SLOT_SHIFT;
>> +       cctl->cf         = (t & DECT_CCTRL_ATTR_CF_FLAG);
>> +       cctl->a_mod      = (t & DECT_CCTRL_ATTR_A_MOD_MASK) >> 
>> DECT_CCTRL_ATTR_A_MOD_SHIFT;
>> +       cctl->bz_mod     = (t & DECT_CCTRL_ATTR_BZ_MOD_MASK) >> 
>> DECT_CCTRL_ATTR_BZ_MOD_SHIFT;
>> +       cctl->bz_ext_mod = (t & DECT_CCTRL_ATTR_BZ_EXT_MOD_MASK) >> 
>> DECT_CCTRL_ATTR_BZ_EXT_MOD_SHIFT;
>> +       cctl->acr        = (t & DECT_CCTRL_ATTR_ACR_MASK) >> 
>> DECT_CCTRL_ATTR_ACR_SHIFT;
>> +
>> +       pr_debug("cctrl: cmd: %llx ecn: %x lbn: %x type: %x "
>> +                "service: %x slot: %x cf %d a_mod %x bz_mod %x 
>> bz_ext_mod %x acr %x\n",
>> +                (unsigned long long)cctl->cmd, cctl->ecn, cctl->lbn,
>> +                cctl->type, cctl->service, cctl->slot, cctl->cf,
>> +                cctl->a_mod, cctl->bz_mod, cctl->bz_ext_mod, 
>> cctl->acr);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_cctrl_attr(const struct dect_cctrl *cctl)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= cctl->cmd;
>> +       t |= (u64)cctl->ecn << DECT_CCTRL_ATTR_ECN_SHIFT;
>> +       t |= (u64)cctl->lbn << DECT_CCTRL_ATTR_LBN_SHIFT;
>> +       t |= (u64)cctl->type << DECT_CCTRL_ATTR_TYPE_SHIFT;
>> +       t |= (u64)cctl->service << DECT_CCTRL_ATTR_SERVICE_SHIFT;
>> +       t |= (u64)cctl->slot << DECT_CCTRL_ATTR_SLOT_SHIFT;
>> +       t |= cctl->cf ? DECT_CCTRL_ATTR_CF_FLAG : 0;
>> +       t |= (u64)cctl->a_mod << DECT_CCTRL_ATTR_A_MOD_SHIFT;
>> +       t |= (u64)cctl->bz_mod << DECT_CCTRL_ATTR_BZ_MOD_SHIFT;
>> +       t |= (u64)cctl->bz_ext_mod << 
>> DECT_CCTRL_ATTR_BZ_EXT_MOD_SHIFT;
>> +       t |= (u64)cctl->acr << DECT_CCTRL_ATTR_ACR_SHIFT;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_cctrl_release(struct dect_cctrl *cctl, u64 t)
>> +{
>> +       cctl->lbn    = (t & DECT_CCTRL_RELEASE_LBN_MASK) >>
>> +                      DECT_CCTRL_RELEASE_LBN_SHIFT;
>> +       cctl->reason = (t & DECT_CCTRL_RELEASE_REASON_MASK) >>
>> +                      DECT_CCTRL_RELEASE_REASON_SHIFT;
>> +       cctl->pmid   = (t & DECT_CCTRL_RELEASE_PMID_MASK) >>
>> +                      DECT_CCTRL_RELEASE_PMID_SHIFT;
>> +
>> +       pr_debug("cctrl: release: pmid: %.5x lbn: %x reason: %x\n",
>> +                cctl->pmid, cctl->lbn, cctl->reason);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_cctrl_release(const struct dect_cctrl *cctl)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= cctl->cmd;
>> +       t |= (u64)cctl->lbn << DECT_CCTRL_RELEASE_LBN_SHIFT;
>> +       t |= (u64)cctl->reason << DECT_CCTRL_RELEASE_REASON_SHIFT;
>> +       t |= (u64)cctl->pmid << DECT_CCTRL_RELEASE_PMID_SHIFT;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_basic_cctrl(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_cctrl *cctl = &tm->cctl;
>> +
>> +       cctl->cmd = t & DECT_MT_CMD_MASK;
>> +       switch (cctl->cmd) {
>> +       case DECT_CCTRL_ACCESS_REQ:
>> +       case DECT_CCTRL_BEARER_HANDOVER_REQ:
>> +       case DECT_CCTRL_CONNECTION_HANDOVER_REQ:
>> +       case DECT_CCTRL_UNCONFIRMED_ACCESS_REQ:
>> +       case DECT_CCTRL_BEARER_CONFIRM:
>> +       case DECT_CCTRL_WAIT:
>> +               return dect_parse_cctrl_common(cctl, t);
>> +       case DECT_CCTRL_ATTRIBUTES_T_REQUEST:
>> +       case DECT_CCTRL_ATTRIBUTES_T_CONFIRM:
>> +               return dect_parse_cctrl_attr(cctl, t);
>> +       case DECT_CCTRL_RELEASE:
>> +               return dect_parse_cctrl_release(cctl, t);
>> +       default:
>> +               pr_debug("unknown cctrl command: %llx\n",
>> +                        (unsigned long long)cctl->cmd);
>> +               return -1;
>> +       }
>> +}
>> +
>> +static int dect_parse_advanced_cctrl(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       struct dect_cctrl *cctl = &tm->cctl;
>> +
>> +       cctl->cmd = t & DECT_MT_CMD_MASK;
>> +       switch (cctl->cmd) {
>> +       case DECT_CCTRL_UNCONFIRMED_DUMMY:
>> +       case DECT_CCTRL_UNCONFIRMED_HANDOVER:
>> +               return dect_parse_cctrl_common(cctl, t);
>> +       case DECT_CCTRL_BANDWIDTH_T_REQUEST:
>> +       case DECT_CCTRL_BANDWIDTH_T_CONFIRM:
>> +               return -1;
>> +       default:
>> +               return dect_parse_basic_cctrl(tm, t);
>> +       }
>> +}
>> +
>> +static int dect_parse_encryption_ctrl(struct dect_tail_msg *tm, u64 
>> t)
>> +{
>> +       struct dect_encctrl *ectl = &tm->encctl;
>> +
>> +       ectl->cmd  = (t & DECT_ENCCTRL_CMD_MASK) >> 
>> DECT_ENCCTRL_CMD_SHIFT;
>> +       ectl->fmid = (t & DECT_ENCCTRL_FMID_MASK) >> 
>> DECT_ENCCTRL_FMID_SHIFT;
>> +       ectl->pmid = (t & DECT_ENCCTRL_PMID_MASK) >> 
>> DECT_ENCCTRL_PMID_SHIFT;
>> +       pr_debug("encctrl: cmd: %x fmid: %.4x pmid: %.5x\n",
>> +                ectl->cmd, ectl->fmid, ectl->pmid);
>> +       return 0;
>> +}
>> +
>> +static u64 dect_build_encryption_ctrl(const struct dect_encctrl 
>> *ectl)
>> +{
>> +       u64 t = 0;
>> +
>> +       t |= (u64)DECT_ENCCTRL_FILL_MASK;
>> +       t |= (u64)ectl->cmd << DECT_ENCCTRL_CMD_SHIFT;
>> +       t |= (u64)ectl->fmid << DECT_ENCCTRL_FMID_SHIFT;
>> +       t |= (u64)ectl->pmid << DECT_ENCCTRL_PMID_SHIFT;
>> +       return t;
>> +}
>> +
>> +static int dect_parse_mac_ctrl(struct dect_tail_msg *tm, u64 t)
>> +{
>> +       switch (t & DECT_MT_HDR_MASK) {
>> +       case DECT_MT_BASIC_CCTRL:
>> +               if (dect_parse_basic_cctrl(tm, t) < 0)
>> +                       return -1;
>> +               tm->type = DECT_TM_TYPE_BCCTRL;
>> +               return 0;
>> +       case DECT_MT_ADV_CCTRL:
>> +               if (dect_parse_advanced_cctrl(tm, t) < 0)
>> +                       return -1;
>> +               tm->type = DECT_TM_TYPE_ACCTRL;
>> +               return 0;
>> +       case DECT_MT_ENC_CTRL:
>> +               if (dect_parse_encryption_ctrl(tm, t) < 0)
>> +                       return -1;
>> +               tm->type = DECT_TM_TYPE_ENCCTRL;
>> +               return 0;
>> +       default:
>> +               pr_debug("Unknown MAC control %llx\n",
>> +                        (unsigned long long)t & DECT_MT_HDR_MASK);
>> +               return -1;
>> +       }
>> +}
>> +
>> +static u64 dect_build_cctrl(const struct dect_cctrl *cctl)
>> +{
>> +       switch (cctl->cmd) {
>> +       case DECT_CCTRL_ACCESS_REQ:
>> +       case DECT_CCTRL_BEARER_HANDOVER_REQ:
>> +       case DECT_CCTRL_CONNECTION_HANDOVER_REQ:
>> +       case DECT_CCTRL_UNCONFIRMED_ACCESS_REQ:
>> +       case DECT_CCTRL_BEARER_CONFIRM:
>> +       case DECT_CCTRL_WAIT:
>> +       case DECT_CCTRL_UNCONFIRMED_DUMMY:
>> +       case DECT_CCTRL_UNCONFIRMED_HANDOVER:
>> +               return dect_build_cctrl_common(cctl);
>> +       case DECT_CCTRL_ATTRIBUTES_T_REQUEST:
>> +       case DECT_CCTRL_ATTRIBUTES_T_CONFIRM:
>> +               return dect_build_cctrl_attr(cctl);
>> +       case DECT_CCTRL_BANDWIDTH_T_REQUEST:
>> +       case DECT_CCTRL_BANDWIDTH_T_CONFIRM:
>> +       case DECT_CCTRL_CHANNEL_LIST:
>> +               return 0;
>> +       case DECT_CCTRL_RELEASE:
>> +               return dect_build_cctrl_release(cctl);
>> +       default:
>> +               return 0;
>> +       }
>> +}
>> +
>> +static int dect_parse_ct_data(struct dect_tail_msg *tm, u64 t, u8 
>> seq)
>> +{
>> +       struct dect_ct_data *ctd = &tm->ctd;
>> +
>> +       ctd->seq = seq;
>> +       tm->type = DECT_TM_TYPE_CT;
>> +       pr_debug("C_S tail sequence number %u\n", seq);
>> +       return 0;
>> +}
>> +
>> +static int dect_parse_tail_msg(struct dect_tail_msg *tm,
>> +                              const struct sk_buff *skb)
>> +{
>> +       u64 t;
>> +
>> +       tm->type = DECT_TM_TYPE_INVALID;
>> +       WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 
>> __alignof__(u64)));
>> +       t = be64_to_cpu(*(__be64 *)skb->data);
>> +
>> +       switch (dect_parse_tail(skb)) {
>> +       case DECT_TI_CT_PKT_0:
>> +               return dect_parse_ct_data(tm, t, 0);
>> +       case DECT_TI_CT_PKT_1:
>> +               return dect_parse_ct_data(tm, t, 1);
>> +       case DECT_TI_NT_CL:
>> +               pr_debug("connectionless: ");
>> +       case DECT_TI_NT:
>> +               return dect_parse_identities_information(tm, t);
>> +       case DECT_TI_QT:
>> +               return dect_parse_system_information(tm, t);
>> +       case DECT_TI_PT:
>> +               /* Paging tail in direction FP->PP, MAC control 
>> otherwise */
>> +               if (DECT_TRX_CB(skb)->slot < 12)
>> +                       return dect_parse_paging_msg(tm, t);
>> +       case DECT_TI_MT:
>> +               return dect_parse_mac_ctrl(tm, t);
>> +       default:
>> +               pr_debug("unknown tail %x\n", dect_parse_tail(skb));
>> +               return -1;
>> +       }
>> +}
>> +
>> +static struct sk_buff *dect_build_tail_msg(struct sk_buff *skb,
>> +                                          enum dect_tail_msg_types 
>> type,
>> +                                          const void *data)
>> +{
>> +       enum dect_tail_identifications ti;
>> +       unsigned int i;
>> +       u64 t;
>> +
>> +       switch (type) {
>> +       case DECT_TM_TYPE_ID:
>> +               t = dect_build_identities_information(data);
>> +               ti = DECT_TI_NT;
>> +               break;
>> +       case DECT_TM_TYPE_SSI:
>> +               t = dect_build_static_system_information(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_ERFC:
>> +               t = dect_build_extended_rf_carrier_information(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_FPC:
>> +               t = dect_build_fixed_part_capabilities(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_EFPC:
>> +               t = dect_build_extended_fixed_part_capabilities(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_EFPC2:
>> +               t = 
>> dect_build_extended_fixed_part_capabilities2(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_SARI:
>> +               t = dect_build_sari(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_MFN:
>> +               t = dect_build_multiframe_number(data);
>> +               ti = DECT_TI_QT;
>> +               break;
>> +       case DECT_TM_TYPE_BCCTRL:
>> +               t = dect_build_cctrl(data) | DECT_MT_BASIC_CCTRL;
>> +               ti = DECT_TI_MT;
>> +               break;
>> +       case DECT_TM_TYPE_ACCTRL:
>> +               t = dect_build_cctrl(data) | DECT_MT_ADV_CCTRL;
>> +               ti = DECT_TI_MT;
>> +               break;
>> +       case DECT_TM_TYPE_ENCCTRL:
>> +               t = dect_build_encryption_ctrl(data);
>> +               ti = DECT_TI_MT;
>> +               break;
>> +       default:
>> +               BUG();
>> +       }
>> +
>> +       skb_put(skb, DECT_T_FIELD_SIZE);
>> +       for (i = 0; i < DECT_T_FIELD_SIZE; i++)
>> +               skb->data[i] = t >> ((sizeof(t) - i - 2) * 
>> BITS_PER_BYTE);
>> +
>> +       DECT_A_CB(skb)->id = ti;
>> +       return skb;
>> +}
>> +
>> +/**
>> + * dect_t_skb_alloc - allocate a socket buffer for the T-Field
>> + *
>> + */
>> +static struct sk_buff *dect_t_skb_alloc(void)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = alloc_skb(DECT_PREAMBLE_SIZE + DECT_A_FIELD_SIZE, 
>> GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       /* Reserve space for preamble */
>> +       skb_reset_mac_header(skb);
>> +       skb_reserve(skb, DECT_PREAMBLE_SIZE);
>> +
>> +       skb_reset_network_header(skb);
>> +
>> +       /* Reserve space for Header Field */
>> +       skb_reserve(skb, DECT_HDR_FIELD_SIZE);
>> +       return skb;
>> +}
>> +
>> +/*
>> + * MAC Bearers
>> + */
>> +
>> +static void dect_bearer_enable(struct dect_bearer *bearer)
>> +{
>> +       switch (bearer->mode) {
>> +       case DECT_BEARER_RX:
>> +               dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_RX);
>> +               break;
>> +       case DECT_BEARER_TX:
>> +               dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_TX);
>> +               break;
>> +       };
>> +       dect_set_carrier(bearer->trx, bearer->chd.slot, 
>> bearer->chd.carrier);
>> +       bearer->state = DECT_BEARER_ENABLED;
>> +}
>> +
>> +static void dect_bearer_disable(struct dect_bearer *bearer)
>> +{
>> +       dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_IDLE);
>> +       bearer->trx->slots[bearer->chd.slot].bearer = NULL;
>> +}
>> +
>> +static void dect_bearer_timer_add(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer,
>> +                                 struct dect_timer *timer,
>> +                                 unsigned int frames)
>> +{
>> +       u8 slot = bearer->chd.slot;
>> +
>> +       switch (bearer->mode) {
>> +       case DECT_BEARER_RX:
>> +               dect_timer_add(cell, timer, DECT_TIMER_RX, frames, 
>> slot);
>> +               break;
>> +       case DECT_BEARER_TX:
>> +               dect_timer_add(cell, timer, DECT_TIMER_TX, frames, 
>> slot);
>> +               break;
>> +       }
>> +}
>> +
>> +/**
>> + * dect_bearer_release - release a MAC bearer
>> + *
>> + * Release a MAC bearer that is no longer used. The unused slot 
>> position is
>> + * given to IRC and converted to a scan bearer.
>> + */
>> +static void dect_scan_bearer_enable(struct dect_transceiver *trx,
>> +                                   const struct dect_channel_desc 
>> *chd);
>> +
>> +static void dect_bearer_release(struct dect_cell *cell,
>> +                               struct dect_bearer *bearer)
>> +{
>> +       struct dect_transceiver *trx = bearer->trx;
>> +       u8 slot = bearer->chd.slot;
>> +
>> +       __skb_queue_purge(&bearer->m_tx_queue);
>> +       dect_timer_del(&bearer->tx_timer);
>> +       dect_bearer_disable(bearer);
>> +       dect_disable_cipher(trx, bearer->chd.slot);
>> +
>> +       if (trx->index < 3 &&
>> +           ((slot >= dect_normal_receive_base(cell->mode) &&
>> +             slot <= dect_normal_receive_end(cell->mode)) ||
>> +            (cell->flags & DECT_CELL_MONITOR)))
>> +               dect_scan_bearer_enable(trx, &bearer->chd);
>> +}
>> +
>> +static void dect_bearer_init(struct dect_cell *cell, struct 
>> dect_bearer *bearer,
>> +                            const struct dect_bearer_ops *ops,
>> +                            struct dect_transceiver *trx,
>> +                            const struct dect_channel_desc *chd,
>> +                            enum dect_bearer_modes mode, void *data)
>> +{
>> +       pr_debug("init bearer: mode: %s slot: %u carrier: %u\n",
>> +                mode == DECT_BEARER_RX ? "RX" : "TX" , chd->slot, 
>> chd->carrier);
>> +
>> +       bearer->ops   = ops;
>> +       bearer->trx   = trx;
>> +       bearer->chd   = *chd;
>> +       bearer->mode  = mode;
>> +       bearer->state = DECT_BEARER_INACTIVE;
>> +       dect_timer_setup(&bearer->tx_timer, NULL, NULL);
>> +       skb_queue_head_init(&bearer->m_tx_queue);
>> +       bearer->data  = data;
>> +
>> +       trx->slots[chd->slot].bearer = bearer;
>> +       dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_IDLE);
>> +}
>> +
>> +/*
>> + * TX bearer activation:
>> + *
>> + * The first transmission of an outgoing traffic or connectionless 
>> bearer is
>> + * scheduled for the frame in which the remote sides' scan is on the 
>> desired
>> + * carrier.
>> + *
>> + * The noise value of the physical channel must be confirmed not to 
>> be more
>> + * than 12dBm stronger than the RSSI measurement obtained from the 
>> channel
>> + * list when selecting the channel within two frames before the first
>> + * transmission.
>> + *
>> + * Dummy bearers are activated immediately after confirming the RSSI.
>> + */
>> +
>> +static void dect_tx_bearer_report_rssi(struct dect_cell *cell,
>> +                                      struct dect_bearer *bearer,
>> +                                      u8 rssi)
>> +{
>> +       rx_debug(cell, "RSSI confirm: last: %u new: %u\n", 
>> bearer->rssi, rssi);
>> +       if (rssi > bearer->rssi + dect_dbm_to_rssi_rel(12))
>> +               pr_debug("RSSI: too much noise\n");
>> +       bearer->state = DECT_BEARER_RSSI_CONFIRMED;
>> +}
>> +
>> +static void dect_tx_bearer_enable_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       struct dect_bearer *bearer = data;
>> +
>> +       switch ((int)bearer->state) {
>> +       case DECT_BEARER_SCHEDULED:
>> +               tx_debug(cell, "confirm RSSI carrier %u\n", 
>> bearer->chd.carrier);
>> +               dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_RX);
>> +               dect_set_carrier(bearer->trx, bearer->chd.slot, 
>> bearer->chd.carrier);
>> +               dect_bearer_timer_add(cell, bearer, &bearer->tx_timer, 
>> 2);
>> +               bearer->state = DECT_BEARER_RSSI_CONFIRM;
>> +               break;
>> +       case DECT_BEARER_RSSI_CONFIRMED:
>> +               tx_debug(cell, "enable bearer\n");
>> +               if (bearer->ops->enable != NULL)
>> +                       bearer->ops->enable(cell, bearer);
>> +               else
>> +                       dect_bearer_enable(bearer);
>> +               break;
>> +       }
>> +}
>> +
>> +static void dect_tx_bearer_schedule(struct dect_cell *cell,
>> +                                   struct dect_bearer *bearer, u8 
>> rssi)
>> +{
>> +       u8 delay = 0;
>> +
>> +       dect_timer_setup(&bearer->tx_timer, 
>> dect_tx_bearer_enable_timer, bearer);
>> +       if (bearer->ops->state != DECT_DUMMY_BEARER)
>> +               delay = dect_channel_delay(cell, &bearer->chd) - 2;
>> +
>> +       bearer->state = DECT_BEARER_SCHEDULED;
>> +       bearer->rssi  = rssi;
>> +
>> +       if (delay == 0)
>> +               dect_tx_bearer_enable_timer(cell, bearer);
>> +       else {
>> +               dect_bearer_timer_add(cell, bearer, &bearer->tx_timer, 
>> delay);
>> +               tx_debug(cell, "scheduled bearer: delay %u carrier %u 
>> pscn %u\n",
>> +                        delay, bearer->chd.carrier, 
>> cell->si.ssi.pscn);
>> +       }
>> +}
>> +
>> +/*
>> + * Broadcast Message Control - decentralized components
>> + */
>> +
>> +/* Paging:
>> + *
>> + * The following rules apply to page message transmission:
>> + *
>> + * - Fast pages may be transmitted in any frame and have priority 
>> over normal
>> + *   pages.
>> + *
>> + * - Normal short and full pages, as well as the first segment of a 
>> normal long
>> + *   page, may only be transmitted in frame 0, or a frame up to 12 if 
>> the page
>> + *   transmitted in the previously allowed frame had the extend bit 
>> bit set.
>> + *
>> + * - Normal pages must be repeated three times in the frames 
>> following their
>> + *   first transmission for page detection in low duty idle mode.
>> + *
>> + * - Fast pages may be repeated up to three times following their 
>> first
>> + *   transmission. New page message have priority over repetitions.
>> + *
>> + * FIXME: fast pages should not interrupt repetitions
>> + */
>> +
>> +static void dect_page_timer_schedule(struct dect_cell *cell)
>> +{
>> +       u8 framenum = dect_framenum(cell, DECT_TIMER_TX);
>> +       u8 frames;
>> +
>> +       if ((framenum & 0x1) == 1)
>> +               frames = 1;
>> +        else
>> +               frames = 2;
>> +       framenum = dect_framenum_add(framenum, frames);
>> +
>> +       if (framenum == 8 || framenum == 14)
>> +               frames += 2;
>> +
>> +       tx_debug(cell, "page timer: schedule in %u frames\n", frames);
>> +       dect_timer_add(cell, &cell->page_timer, DECT_TIMER_TX, frames, 
>> 0);
>> +}
>> +
>> +/**
>> + * dect_queue_page - Add a paging message to the appropriate queue
>> + *
>> + * The first transmission of a page is added to the end of the normal 
>> or
>> + * fast queue. The first three repetitions of normal pages have 
>> priority
>> + * over first transmissions.
>> + */
>> +static void dect_queue_page(struct dect_cell *cell, struct sk_buff 
>> *skb)
>> +{
>> +       u8 repetitions = DECT_BMC_CB(skb)->repetitions;
>> +       bool fast = DECT_BMC_CB(skb)->fast_page;
>> +       struct sk_buff_head *page_queue;
>> +
>> +       page_queue = fast ? &cell->page_fast_queue : 
>> &cell->page_queue;
>> +       if (!fast && repetitions > 0)
>> +               skb_queue_head(page_queue, skb);
>> +       else
>> +               skb_queue_tail(page_queue, skb);
>> +
>> +       dect_page_timer_schedule(cell);
>> +}
>> +
>> +/**
>> + * dect_queue_page_segments - perform segmentation and queue the page 
>> segments
>> + *
>> + * Segment a page message into B_S channel sized segments and add 
>> them
>> + * to the TX queue.
>> + */
>> +static void dect_queue_page_segments(struct sk_buff_head *list,
>> +                                    struct sk_buff *skb)
>> +{
>> +       unsigned int len = skb->len;
>> +       struct sk_buff *seg;
>> +       u64 t;
>> +
>> +       while (skb->len > DECT_PT_LFP_BS_DATA_SIZE) {
>> +               seg = skb_clone(skb, GFP_ATOMIC);
>> +               if (seg == NULL)
>> +                       goto err;
>> +               skb_trim(seg, DECT_PT_LFP_BS_DATA_SIZE);
>> +
>> +               if (skb_queue_empty(list))
>> +                       t = DECT_PT_LONG_PAGE_FIRST;
>> +               else
>> +                       t = DECT_PT_LONG_PAGE;
>> +
>> +               seg->data[0] &= 0x0f;
>> +               seg->data[0] |= t >> 48;
>> +               pr_debug("queue page segment len %u hdr %x\n",
>> +                        seg->len, seg->data[0] & 0xf0);
>> +               __skb_queue_tail(list, seg);
>> +
>> +               skb_pull(skb, DECT_PT_LFP_BS_DATA_SIZE);
>> +       }
>> +
>> +       /* Short and full pages have the extend bit set in order to 
>> reduce
>> +        * the delay for new pages arriving while a page is already 
>> active.
>> +        */
>> +       if (skb->len == DECT_PT_SP_BS_DATA_SIZE)
>> +               t = DECT_PT_SHORT_PAGE | DECT_PT_HDR_EXTEND_FLAG;
>> +       else if (!DECT_BMC_CB(skb)->long_page)
>> +               t = DECT_PT_FULL_PAGE | DECT_PT_HDR_EXTEND_FLAG;
>> +       else if (len == DECT_PT_LFP_BS_DATA_SIZE)
>> +               t = DECT_PT_LONG_PAGE_ALL;
>> +       else
>> +               t = DECT_PT_LONG_PAGE_LAST;
>> +
>> +       skb->data[0] &= 0x0f;
>> +       skb->data[0] |= t >> 48;
>> +       pr_debug("queue page segment len %u hdr %x\n",
>> +                skb->len, skb->data[0] & 0xf0);
>> +       __skb_queue_tail(list, skb);
>> +       return;
>> +
>> +err:
>> +       __skb_queue_purge(list);
>> +       kfree_skb(skb);
>> +}
>> +
>> +/**
>> + * dect_page_timer - page message transmission timer
>> + *
>> + * This timer performs maintenance of the page transmit queue. While 
>> the queue
>> + * is active, it is advanced by one segment per frame. When a page 
>> message has
>> + * been fully transmitted, the next message is selected for 
>> transmission,
>> + * segmented into appropriate units and queued to the transmit queue.
>> + */
>> +static void dect_page_tx_timer(struct dect_cell *cell, void *data)
>> +{
>> +       u32 timeout, mfn = dect_mfn(cell, DECT_TIMER_TX);
>> +       u8 framenum = dect_framenum(cell, DECT_TIMER_TX);
>> +       struct sk_buff *skb, *last;
>> +
>> +       tx_debug(cell, "page timer\n");
>> +
>> +       /* Advance the transmit queue by one segment per allowed tail. 
>> */
>> +       if (!skb_queue_empty(&cell->page_tx_queue)) {
>> +               tx_debug(cell, "advance queue\n");
>> +               kfree_skb(__skb_dequeue(&cell->page_tx_queue));
>> +               if (!skb_queue_empty(&cell->page_tx_queue)) {
>> +                       dect_page_timer_schedule(cell);
>> +                       return;
>> +               }
>> +       }
>> +
>> +       /* Add the last page back to the queue unless its lifetime 
>> expired. */
>> +       last = cell->page_sdu;
>> +       if (last != NULL) {
>> +               cell->page_sdu = NULL;
>> +
>> +               DECT_BMC_CB(last)->repetitions++;
>> +               timeout = dect_mfn_add(DECT_BMC_CB(last)->stamp, 
>> DECT_PAGE_LIFETIME);
>> +               if (dect_mfn_before(mfn, timeout))
>> +                       dect_queue_page(cell, last);
>> +               else
>> +                       kfree_skb(last);
>> +       }
>> +
>> +       /* Get the next page message */
>> +       while (1) {
>> +               skb = skb_dequeue(&cell->page_fast_queue);
>> +               tx_debug(cell, "fast page: %p\n", skb);
>> +               if (skb == NULL && 
>> !skb_queue_empty(&cell->page_queue)) {
>> +                       if (framenum == 0 || (last != NULL && framenum 
>> <= 12))
>> +                               skb = skb_dequeue(&cell->page_queue);
>> +                       tx_debug(cell, "normal page: %p\n", skb);
>> +               }
>> +               if (skb == NULL)
>> +                       goto out;
>> +
>> +               timeout = dect_mfn_add(DECT_BMC_CB(skb)->stamp, 
>> DECT_PAGE_LIFETIME);
>> +               if (dect_mfn_before(mfn, timeout))
>> +                       break;
>> +               else
>> +                       kfree_skb(skb);
>> +       }
>> +
>> +       /* Save a copy of short and full pages for repetitions. */
>> +       if (!DECT_BMC_CB(skb)->long_page &&
>> +           DECT_BMC_CB(skb)->repetitions < 3)
>> +               cell->page_sdu = skb_clone(skb, GFP_ATOMIC);
>> +
>> +       /* Segment page message and queue segments to tx queue */
>> +       dect_queue_page_segments(&cell->page_tx_queue, skb);
>> +out:
>> +       if (skb != NULL || !skb_queue_empty(&cell->page_queue))
>> +               dect_page_timer_schedule(cell);
>> +}
>> +
>> +static void dect_cell_schedule_page(struct dect_cell *cell, u32 mask)
>> +{
>> +       struct dect_bc *bc;
>> +
>> +       list_for_each_entry(bc, &cell->bcs, list)
>> +               bc->p_tx_mask |= mask;
>> +}
>> +
>> +static void dect_cell_bmc_init(struct dect_cell *cell)
>> +{
>> +       skb_queue_head_init(&cell->page_queue);
>> +       skb_queue_head_init(&cell->page_fast_queue);
>> +       skb_queue_head_init(&cell->page_tx_queue);
>> +       dect_timer_setup(&cell->page_timer, dect_page_tx_timer, NULL);
>> +}
>> +
>> +static void dect_cell_bmc_disable(struct dect_cell *cell)
>> +{
>> +       dect_timer_del(&cell->page_timer);
>> +       __skb_queue_purge(&cell->page_tx_queue);
>> +       __skb_queue_purge(&cell->page_fast_queue);
>> +       __skb_queue_purge(&cell->page_queue);
>> +}
>> +
>> +/*
>> + * Broadcast Control
>> + */
>> +
>> +static void dect_cell_mac_info_ind(struct dect_cell *cell)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +
>> +       clh->ops->mac_info_ind(clh, &cell->idi, &cell->si);
>> +}
>> +
>> +static u32 dect_build_page_rfpi(const struct dect_cell *cell)
>> +{
>> +       return (dect_build_rfpi(&cell->idi) >> 24) & ((1 << 20) - 1);
>> +}
>> +
>> +static void dect_bc_release(struct dect_bc *bc)
>> +{
>> +       kfree_skb(bc->p_rx_skb);
>> +       list_del(&bc->list);
>> +}
>> +
>> +static void dect_bc_init(struct dect_cell *cell, struct dect_bc *bc)
>> +{
>> +       INIT_LIST_HEAD(&bc->list);
>> +       bc->p_rx_skb = NULL;
>> +       list_add_tail(&bc->list, &cell->bcs);
>> +}
>> +
>> +static const enum dect_mac_system_information_types dect_bc_q_cycle[] 
>> = {
>> +       DECT_QT_SI_SSI,
>> +       DECT_QT_SI_ERFC,
>> +       DECT_QT_SI_SARI,
>> +       DECT_QT_SI_FPC,
>> +       DECT_QT_SI_EFPC,
>> +       DECT_QT_SI_EFPC2,
>> +       DECT_QT_SI_MFN,
>> +};
>> +
>> +static struct sk_buff *dect_bc_q_dequeue(struct dect_cell *cell,
>> +                                        struct dect_bearer *bearer)
>> +{
>> +       const struct dect_si *si = &cell->si;
>> +       struct dect_ssi ssi;
>> +       struct dect_mfn mfn;
>> +       struct sk_buff *skb;
>> +       unsigned int index;
>> +
>> +       skb = dect_t_skb_alloc();
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       while (1) {
>> +               index = cell->si_idx++;
>> +               if (cell->si_idx == ARRAY_SIZE(dect_bc_q_cycle))
>> +                       cell->si_idx = 0;
>> +
>> +               switch (dect_bc_q_cycle[index]) {
>> +               case DECT_QT_SI_SSI:
>> +                       memcpy(&ssi, &si->ssi, sizeof(ssi));
>> +                       ssi.sn = bearer->chd.slot;
>> +                       ssi.cn = bearer->chd.carrier;
>> +                       ssi.sp = 0;
>> +                       ssi.pscn = dect_next_carrier(ssi.rfcars, 
>> ssi.pscn);
>> +
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_SSI, &ssi);
>> +               case DECT_QT_SI_ERFC:
>> +                       if (!si->ssi.mc)
>> +                               continue;
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_ERFC,
>> +                                                  &si->erfc);
>> +               case DECT_QT_SI_SARI:
>> +                       break;
>> +               case DECT_QT_SI_FPC:
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_FPC,
>> +                                                  &si->fpc);
>> +               case DECT_QT_SI_EFPC:
>> +                       if (!(si->fpc.fpc & 
>> DECT_FPC_EXTENDED_FP_INFO))
>> +                               continue;
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_EFPC,
>> +                                                  &si->efpc);
>> +               case DECT_QT_SI_EFPC2:
>> +                       if (!(si->efpc.fpc & 
>> DECT_EFPC_EXTENDED_FP_INFO2))
>> +                               continue;
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_EFPC2,
>> +                                                  &si->efpc2);
>> +               case DECT_QT_SI_MFN:
>> +                       mfn.num = dect_mfn(cell, DECT_TIMER_TX);
>> +                       return dect_build_tail_msg(skb, 
>> DECT_TM_TYPE_MFN, &mfn);
>> +               default:
>> +                       BUG();
>> +               }
>> +       }
>> +}
>> +
>> +static void dect_page_add_mac_info(struct dect_cell *cell, struct 
>> dect_bc *bc,
>> +                                  struct sk_buff *skb)
>> +{
>> +       struct dect_tail_msg tm;
>> +       struct dect_dbc *dbc;
>> +       u64 t;
>> +       u8 *it;
>> +
>> +       memset(&tm, 0, sizeof(tm));
>> +       if (bc->p_tx_mask & (1 << DECT_TM_TYPE_BFS))
>> +               tm.type = DECT_TM_TYPE_BFS;
>> +       else if (bc->p_tx_mask & (1 << DECT_TM_TYPE_BD))
>> +               tm.type = DECT_TM_TYPE_BD;
>> +       else
>> +               tm.type = DECT_TM_TYPE_ACTIVE_CARRIERS;
>> +
>> +       switch (tm.type) {
>> +       case DECT_TM_TYPE_BFS:
>> +               tm.bfs.mask = cell->trg_blind_full_slots;
>> +               t = dect_build_blind_full_slots(&tm.bfs);
>> +               break;
>> +       case DECT_TM_TYPE_BD:
>> +               dbc = dect_dbc_get(cell);
>> +               if (dbc == NULL)
>> +                       goto out;
>> +               tm.bd.bt = DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION;
>> +               tm.bd.sn = dbc->bearer.chd.slot;
>> +               tm.bd.sp = 0;
>> +               tm.bd.cn = dbc->bearer.chd.carrier;
>> +               t = dect_build_bearer_description(&tm.bd);
>> +               break;
>> +       case DECT_TM_TYPE_RFP_ID:
>> +               t = dect_build_rfp_identity(&tm.rfp_id);
>> +               break;
>> +       case DECT_TM_TYPE_RFP_STATUS:
>> +               t = dect_build_rfp_status(&tm.rfp_status);
>> +               break;
>> +       case DECT_TM_TYPE_ACTIVE_CARRIERS:
>> +       default:
>> +               t = dect_build_active_carriers(&tm.active_carriers);
>> +               break;
>> +       }
>> +
>> +       it = skb_put(skb, DECT_PT_INFO_TYPE_SIZE);
>> +       it[0] = t >> 24;
>> +       it[1] = t >> 16;
>> +out:
>> +       bc->p_tx_mask &= ~(1 << tm.type);
>> +}
>> +
>> +static struct sk_buff *dect_bc_p_dequeue(struct dect_cell *cell,
>> +                                        struct dect_bearer *bearer,
>> +                                        struct dect_bc *bc)
>> +{
>> +       unsigned int headroom, tailroom = 0;
>> +       struct sk_buff *skb;
>> +       u8 *hdr;
>> +       u64 t;
>> +
>> +       /* Send higher layer page messages if present */
>> +       skb = skb_peek(&cell->page_tx_queue);
>> +       if (skb != NULL) {
>> +               /* The frame needs headroom for the preamble and 
>> hdr-field.
>> +                * Short pages need additional tailroom for the MAC 
>> Layer
>> +                * Information. */
>> +               headroom = DECT_PREAMBLE_SIZE + DECT_HDR_FIELD_SIZE;
>> +               if (skb->len == DECT_PT_SP_BS_DATA_SIZE)
>> +                       tailroom = DECT_PT_INFO_TYPE_SIZE;
>> +
>> +               skb = skb_copy_expand(skb, headroom, tailroom, 
>> GFP_ATOMIC);
>> +               if (skb == NULL)
>> +                       return NULL;
>> +               /* Reserve space for preamble */
>> +               skb_set_mac_header(skb, -headroom);
>> +       } else {
>> +               /* Send zero-length page if required */
>> +               if (dect_framenum(cell, DECT_TIMER_TX) == 0 ||
>> +                   bc->p_tx_mask == 0)
>> +                       return NULL;
>> +
>> +               skb = dect_t_skb_alloc();
>> +               if (skb == NULL)
>> +                       return NULL;
>> +
>> +               t  = DECT_PT_ZERO_PAGE | DECT_PT_HDR_EXTEND_FLAG;
>> +               t |= (u64)dect_build_page_rfpi(cell) << 
>> DECT_PT_ZP_RFPI_SHIFT;
>> +
>> +               hdr = skb_put(skb, 3);
>> +               hdr[0] = t >> 48;
>> +               hdr[1] = t >> 40;
>> +               hdr[2] = t >> 32;
>> +
>> +               tailroom = DECT_PT_INFO_TYPE_SIZE;
>> +       }
>> +
>> +       DECT_A_CB(skb)->id = DECT_TI_PT;
>> +       if (tailroom > 0)
>> +               dect_page_add_mac_info(cell, bc, skb);
>> +
>> +       return skb;
>> +}
>> +
>> +static struct sk_buff *dect_bc_dequeue(struct dect_cell *cell,
>> +                                      struct dect_bearer *bearer,
>> +                                      struct dect_bc *bc,
>> +                                      enum dect_mac_channels chan)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       switch (chan) {
>> +       case DECT_MC_P:
>> +               return dect_bc_p_dequeue(cell, bearer, bc);
>> +       case DECT_MC_Q:
>> +               return dect_bc_q_dequeue(cell, bearer);
>> +       case DECT_MC_N:
>> +               skb = dect_t_skb_alloc();
>> +               if (skb == NULL)
>> +                       return NULL;
>> +               return dect_build_tail_msg(skb, DECT_TM_TYPE_ID, 
>> &cell->idi);
>> +       default:
>> +               BUG();
>> +       }
>> +}
>> +
>> +/**
>> + * dect_bc_queue_bs_data - queue a page message to the broadcast 
>> controller for
>> + *                        reassembly and delivery to broadcast 
>> message control.
>> + *
>> + * @cell:      DECT cell
>> + * @bc:                broadcast controller
>> + * @skb_in:    DECT frame
>> + * @page:      page message
>> + */
>> +static void dect_bc_queue_bs_data(struct dect_cell *cell, struct 
>> dect_bc *bc,
>> +                                 struct sk_buff *skb_in, const struct 
>> dect_page *page)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +       struct sk_buff *skb, *head;
>> +
>> +       if (page->length == DECT_PT_ZERO_PAGE)
>> +               return;
>> +
>> +       skb = skb_clone(skb_in, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return;
>> +       skb_pull(skb, DECT_T_FIELD_OFF);
>> +       DECT_BMC_CB(skb)->long_page = false;
>> +
>> +       head = bc->p_rx_skb;
>> +       switch (page->length) {
>> +       case DECT_PT_SHORT_PAGE:
>> +               skb_trim(skb, DECT_PT_SP_BS_DATA_SIZE);
>> +               break;
>> +       case DECT_PT_LONG_PAGE_ALL:
>> +               DECT_BMC_CB(skb)->long_page = true;
>> +               /* fall through */
>> +       case DECT_PT_FULL_PAGE:
>> +               skb_trim(skb, DECT_PT_LFP_BS_DATA_SIZE);
>> +               break;
>> +       case DECT_PT_LONG_PAGE_FIRST:
>> +               if (head != NULL)
>> +                       goto err_free;
>> +               DECT_BMC_CB(skb)->long_page = true;
>> +               skb_trim(skb, DECT_PT_LFP_BS_DATA_SIZE);
>> +               bc->p_rx_skb = skb;
>> +               return;
>> +       case DECT_PT_LONG_PAGE:
>> +               if (head == NULL)
>> +                       goto err_free;
>> +               skb_trim(skb, DECT_PT_LFP_BS_DATA_SIZE);
>> +               skb_append_frag(head, skb);
>> +               if (head->len >= 30)
>> +                       goto err;
>> +               return;
>> +       case DECT_PT_LONG_PAGE_LAST:
>> +               if (head == NULL)
>> +                       goto err_free;
>> +               skb_trim(skb, DECT_PT_LFP_BS_DATA_SIZE);
>> +               skb = skb_append_frag(head, skb);
>> +               bc->p_rx_skb = NULL;
>> +               break;
>> +       default:
>> +               BUG();
>> +       }
>> +
>> +       return clh->ops->bmc_page_ind(clh, skb);
>> +
>> +err_free:
>> +       kfree_skb(skb);
>> +err:
>> +       kfree_skb(bc->p_rx_skb);
>> +       bc->p_rx_skb = NULL;
>> +}
>> +
>> +static bool dect_bc_update_si(struct dect_si *si,
>> +                             const struct dect_tail_msg *tm)
>> +{
>> +       bool notify = false;
>> +       unsigned int i;
>> +
>> +       switch (tm->type) {
>> +       case DECT_TM_TYPE_SSI:
>> +               if (memcmp(&si->ssi, &tm->ssi, sizeof(si->ssi)))
>> +                       memcpy(&si->ssi, &tm->ssi, sizeof(si->ssi));
>> +               break;
>> +       case DECT_TM_TYPE_ERFC:
>> +               if (memcmp(&si->erfc, &tm->erfc, sizeof(si->erfc)))
>> +                       memcpy(&si->erfc, &tm->erfc, 
>> sizeof(si->erfc));
>> +               break;
>> +       case DECT_TM_TYPE_FPC:
>> +               if (memcmp(&si->fpc, &tm->fpc, sizeof(si->fpc))) {
>> +                       memcpy(&si->fpc, &tm->fpc, sizeof(si->fpc));
>> +                       notify = true;
>> +               }
>> +               break;
>> +       case DECT_TM_TYPE_EFPC:
>> +               if (memcmp(&si->efpc, &tm->efpc, sizeof(si->efpc))) {
>> +                       memcpy(&si->efpc, &tm->efpc, 
>> sizeof(si->efpc));
>> +                       notify = true;
>> +               }
>> +               break;
>> +       case DECT_TM_TYPE_EFPC2:
>> +               if (memcmp(&si->efpc2, &tm->efpc2, sizeof(si->efpc2))) 
>> {
>> +                       memcpy(&si->efpc2, &tm->efpc2, 
>> sizeof(si->efpc2));
>> +                       notify = true;
>> +               }
>> +               break;
>> +       case DECT_TM_TYPE_SARI:
>> +               if (si->num_saris == ARRAY_SIZE(si->sari))
>> +                       break;
>> +
>> +               for (i = 0; i < si->num_saris; i++) {
>> +                       if (!dect_ari_cmp(&tm->sari.ari, 
>> &si->sari[i].ari))
>> +                               break;
>> +               }
>> +               if (i < si->num_saris)
>> +                       break;
>> +
>> +               memcpy(&si->sari[si->num_saris++], &tm->sari,
>> +                      sizeof(si->sari[i]));
>> +               notify = true;
>> +               break;
>> +       case DECT_TM_TYPE_MFN:
>> +               memcpy(&si->mfn, &tm->mfn, sizeof(si->mfn));
>> +               break;
>> +       default:
>> +               return false;
>> +       }
>> +
>> +       si->mask |= 1 << tm->type;
>> +       return notify;
>> +}
>> +
>> +static bool dect_bc_si_cycle_complete(struct dect_idi *idi,
>> +                                     const struct dect_si *si)
>> +{
>> +       if (!(si->mask & (1 << DECT_TM_TYPE_SSI))) {
>> +               pr_debug("incomplete: SSI\n");
>> +               return false;
>> +       }
>> +       if (si->ssi.mc &&
>> +           !(si->mask & (1 << DECT_TM_TYPE_ERFC))) {
>> +               pr_debug("incomplete: ERFC\n");
>> +               return false;
>> +       }
>> +
>> +       if (!(si->mask & (1 << DECT_TM_TYPE_FPC))) {
>> +               pr_debug("incomplete: FPC\n");
>> +               return false;
>> +       }
>> +       if (si->fpc.fpc & DECT_FPC_EXTENDED_FP_INFO &&
>> +           !(si->mask & (1 << DECT_TM_TYPE_EFPC))) {
>> +               pr_debug("incomplete: EFPC\n");
>> +               return false;
>> +       }
>> +
>> +       if (si->mask & (1 << DECT_TM_TYPE_EFPC) &&
>> +           si->efpc.fpc & DECT_EFPC_EXTENDED_FP_INFO2 &&
>> +           !(si->mask & (1 << DECT_TM_TYPE_EFPC2))) {
>> +               pr_debug("incomplete: EFPC2\n");
>> +               return false;
>> +       }
>> +
>> +       if (idi->e &&
>> +           (!(si->mask & (1 << DECT_TM_TYPE_SARI)) ||
>> +            si->num_saris != si->sari[0].list_cycle)) {
>> +               pr_debug("incomplete: SARI\n");
>> +               return false;
>> +       }
>> +
>> +       pr_debug("complete\n");
>> +       return true;
>> +}
>> +
>> +static void dect_bc_rcv(struct dect_cell *cell, struct dect_bc *bc,
>> +                       struct sk_buff *skb, const struct 
>> dect_tail_msg *tm)
>> +{
>> +       enum dect_tail_identifications ti;
>> +       bool notify;
>> +
>> +       if (cell->mode != DECT_MODE_PP)
>> +               return;
>> +
>> +       ti = dect_parse_tail(skb);
>> +       if (ti == DECT_TI_QT) {
>> +               /* Q-channel information is broadcast in frame 8 */
>> +               dect_timer_synchronize_framenum(cell, 
>> DECT_Q_CHANNEL_FRAME);
>> +               if (tm->type == DECT_TM_TYPE_MFN)
>> +                       dect_timer_synchronize_mfn(cell, tm->mfn.num);
>> +
>> +               notify = dect_bc_update_si(&cell->si, tm);
>> +               if (dect_bc_si_cycle_complete(&cell->idi, &cell->si) 
>> && notify)
>> +                       dect_cell_mac_info_ind(cell);
>> +       } else if (ti == DECT_TI_PT) {
>> +               if (tm->page.length == DECT_PT_ZERO_PAGE &&
>> +                   tm->page.rfpi != dect_build_page_rfpi(cell))
>> +                       pr_debug("RFPI mismatch %.3x %.3x\n",
>> +                                tm->page.rfpi, 
>> dect_build_page_rfpi(cell));
>> +       }
>> +
>> +       switch (tm->type) {
>> +       case DECT_TM_TYPE_BFS:
>> +               cell->blind_full_slots = tm->bfs.mask;
>> +       case DECT_TM_TYPE_BD:
>> +       case DECT_TM_TYPE_RFP_ID:
>> +       case DECT_TM_TYPE_RFP_STATUS:
>> +       case DECT_TM_TYPE_ACTIVE_CARRIERS:
>> +       case DECT_TM_TYPE_PAGE:
>> +               dect_bc_queue_bs_data(cell, bc, skb, &tm->page);
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +}
>> +
>> +/*
>> + * Traffic Bearer Control (TBC)
>> + */
>> +
>> +#define tbc_debug(tbc, fmt, args...) \
>> +       pr_debug("TBC (TBEI %u/%s): PMID: %s %x FMID: %.3x: " fmt, \
>> +                (tbc)->id.tbei, tbc_states[(tbc)->state], \
>> +                (tbc)->id.pmid.type == DECT_PMID_DEFAULT ? "default" 
>> : \
>> +                (tbc)->id.pmid.type == DECT_PMID_ASSIGNED ? 
>> "assigned" : \
>> +                (tbc)->id.pmid.type == DECT_PMID_EMERGENCY ? 
>> "emergency" : "?", \
>> +                (tbc)->id.pmid.tpui, (tbc)->cell->fmid, ## args);
>> +
>> +static const char *tbc_states[] = {
>> +       [DECT_TBC_NONE]                 = "NONE",
>> +       [DECT_TBC_REQ_SENT]             = "REQ_SENT",
>> +       [DECT_TBC_WAIT_RCVD]            = "WAIT_RCVD",
>> +       [DECT_TBC_REQ_RCVD]             = "REQ_RCVD",
>> +       [DECT_TBC_RESPONSE_SENT]        = "RESPONSE_SENT",
>> +       [DECT_TBC_OTHER_WAIT]           = "OTHER_WAIT",
>> +       [DECT_TBC_ESTABLISHED]          = "ESTABLISHED",
>> +       [DECT_TBC_RELEASING]            = "RELEASING",
>> +       [DECT_TBC_RELEASED]             = "RELEASED",
>> +};
>> +
>> +static struct dect_tbc *dect_tbc_get_by_tbei(const struct dect_cell 
>> *cell, u32 tbei)
>> +{
>> +       struct dect_tbc *tbc;
>> +
>> +       list_for_each_entry(tbc, &cell->tbcs, list) {
>> +               if (tbc->id.tbei == tbei)
>> +                       return tbc;
>> +       }
>> +       return NULL;
>> +}
>> +
>> +static u32 dect_tbc_alloc_tbei(struct dect_cell *cell)
>> +{
>> +       u32 tbei;
>> +
>> +       while (1) {
>> +               tbei = ++cell->tbei_rover;
>> +               if (tbei == 0)
>> +                       continue;
>> +               if (dect_tbc_get_by_tbei(cell, tbei))
>> +                       continue;
>> +               return tbei;
>> +       }
>> +}
>> +
>> +static void dect_tbc_queue_mac_control(struct dect_tbc *tbc, struct 
>> sk_buff *skb)
>> +{
>> +       skb_queue_tail(&tbc->txb.m_tx_queue, skb);
>> +}
>> +
>> +static struct sk_buff *dect_tbc_build_cctrl(const struct dect_tbc 
>> *tbc,
>> +                                           enum dect_cctrl_cmds cmd)
>> +{
>> +       struct dect_cctrl cctl;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_t_skb_alloc();
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       cctl.fmid = tbc->cell->fmid;
>> +       cctl.pmid = dect_build_pmid(&tbc->id.pmid);
>> +       cctl.cmd  = cmd;
>> +
>> +       if (tbc->type == DECT_MAC_CONN_BASIC)
>> +               return dect_build_tail_msg(skb, DECT_TM_TYPE_BCCTRL, 
>> &cctl);
>> +       else
>> +               return dect_build_tail_msg(skb, DECT_TM_TYPE_ACCTRL, 
>> &cctl);
>> +}
>> +
>> +static struct sk_buff *dect_tbc_build_encctrl(const struct dect_tbc 
>> *tbc,
>> +                                             enum dect_encctrl_cmds 
>> cmd)
>> +{
>> +       struct dect_encctrl ectl;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_t_skb_alloc();
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       ectl.fmid = tbc->cell->fmid;
>> +       ectl.pmid = dect_build_pmid(&tbc->id.pmid);
>> +       ectl.cmd  = cmd;
>> +
>> +       return dect_build_tail_msg(skb, DECT_TM_TYPE_ENCCTRL, &ectl);
>> +}
>> +
>> +static int dect_tbc_send_confirm(struct dect_tbc *tbc)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       tbc_debug(tbc, "TX CONFIRM\n");
>> +       skb = dect_tbc_build_cctrl(tbc, DECT_CCTRL_BEARER_CONFIRM);
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +
>> +       /* The first response is permitted in any frame */
>> +       if (tbc->state == DECT_TBC_REQ_RCVD)
>> +               skb->priority = DECT_MT_HIGH_PRIORITY;
>> +       dect_tbc_queue_mac_control(tbc, skb);
>> +       return 0;
>> +}
>> +
>> +static int dect_tbc_send_attributes_confirm(struct dect_tbc *tbc)
>> +{
>> +       struct dect_cctrl cctl;
>> +       struct sk_buff *skb;
>> +
>> +       tbc_debug(tbc, "TX ATTRIBUTES_T_CONFIRM\n");
>> +       skb = dect_t_skb_alloc();
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +
>> +       cctl.cmd     = DECT_CCTRL_ATTRIBUTES_T_CONFIRM;
>> +       cctl.ecn     = tbc->id.ecn;
>> +       cctl.lbn     = tbc->id.lbn;
>> +       cctl.type    = DECT_CCTRL_TYPE_SYMETRIC_BEARER;
>> +       cctl.service = tbc->service;
>> +       cctl.cf      = false;
>> +
>> +       cctl.slot   = DECT_FULL_SLOT;
>> +       cctl.a_mod  = DECT_MODULATION_2_LEVEL;
>> +       cctl.bz_mod = DECT_MODULATION_2_LEVEL;
>> +       cctl.bz_ext_mod = 7;
>> +       cctl.acr    = 0;
>> +
>> +       if (tbc->type == DECT_MAC_CONN_BASIC)
>> +               dect_build_tail_msg(skb, DECT_TM_TYPE_BCCTRL, &cctl);
>> +       else
>> +               dect_build_tail_msg(skb, DECT_TM_TYPE_ACCTRL, &cctl);
>> +
>> +       dect_tbc_queue_mac_control(tbc, skb);
>> +       return 0;
>> +}
>> +
>> +static int dect_tbc_send_release(struct dect_tbc *tbc,
>> +                                enum dect_release_reasons reason)
>> +{
>> +       struct dect_cctrl cctl;
>> +       struct sk_buff *skb;
>> +
>> +       tbc_debug(tbc, "TX RELEASE: reason: %x\n", reason);
>> +       skb = dect_t_skb_alloc();
>> +       if (skb == NULL)
>> +               return -ENOMEM;
>> +
>> +       cctl.cmd     = DECT_CCTRL_RELEASE;
>> +       cctl.pmid    = dect_build_pmid(&tbc->id.pmid);
>> +       cctl.reason  = reason;
>> +
>> +       if (tbc->type == DECT_MAC_CONN_BASIC)
>> +               dect_build_tail_msg(skb, DECT_TM_TYPE_BCCTRL, &cctl);
>> +       else
>> +               dect_build_tail_msg(skb, DECT_TM_TYPE_ACCTRL, &cctl);
>> +
>> +       /* RELEASE messages may appear in any frame */
>> +       skb->priority = DECT_MT_HIGH_PRIORITY;
>> +       dect_tbc_queue_mac_control(tbc, skb);
>> +       return 0;
>> +}
>> +
>> +static void dect_tbc_state_change(struct dect_tbc *tbc, enum 
>> dect_tbc_state state)
>> +{
>> +       struct dect_cell *cell = tbc->cell;
>> +
>> +       tbc_debug(tbc, "state change: %s (%u) -> %s (%u)\n",
>> +                 tbc_states[tbc->state], tbc->state, 
>> tbc_states[state], state);
>> +
>> +       if (tbc->state == DECT_TBC_ESTABLISHED) {
>> +               cell->tbc_num_est--;
>> +               cell->tbc_last_chd = tbc->rxb.chd;
>> +       } else if (state == DECT_TBC_ESTABLISHED)
>> +               cell->tbc_num_est++;
>> +
>> +       tbc->state = state;
>> +}
>> +
>> +static int dect_tbc_event(const struct dect_tbc *tbc, enum 
>> dect_tbc_event event)
>> +{
>> +       const struct dect_cluster_handle *clh = tbc->cell->handle.clh;
>> +
>> +       return clh->ops->tbc_event_ind(clh, &tbc->id, event);
>> +}
>> +
>> +static int dect_tbc_establish_cfm(const struct dect_tbc *tbc, bool 
>> success)
>> +{
>> +       const struct dect_cluster_handle *clh = tbc->cell->handle.clh;
>> +
>> +       return clh->ops->tbc_establish_cfm(clh, &tbc->id, success,
>> +                                          tbc->rxb.chd.slot);
>> +}
>> +
>> +static void dect_tbc_release_notify(const struct dect_tbc *tbc,
>> +                                   enum dect_release_reasons reason)
>> +{
>> +       const struct dect_cluster_handle *clh = tbc->cell->handle.clh;
>> +
>> +       clh->ops->tbc_dis_ind(clh, &tbc->id, reason);
>> +}
>> +
>> +static void dect_tdd_channel_desc(struct dect_channel_desc *dst,
>> +                                 const struct dect_channel_desc *chd)
>> +{
>> +       dst->pkt     = chd->pkt;
>> +       dst->b_fmt   = chd->b_fmt;
>> +       dst->carrier = chd->carrier;
>> +       dst->slot    = dect_tdd_slot(chd->slot);
>> +}
>> +
>> +static void dect_tbc_destroy(struct dect_cell *cell, struct dect_tbc 
>> *tbc)
>> +{
>> +       tbc_debug(tbc, "destroy\n");
>> +       dect_tbc_state_change(tbc, DECT_TBC_NONE);
>> +
>> +       dect_timer_del(&tbc->wd_timer);
>> +       dect_timer_del(&tbc->wait_timer);
>> +       dect_timer_del(&tbc->release_timer);
>> +       dect_timer_del(&tbc->enc_timer);
>> +       dect_bc_release(&tbc->bc);
>> +
>> +       dect_channel_release(cell, tbc->txb.trx, &tbc->txb.chd);
>> +       dect_bearer_release(cell, &tbc->txb);
>> +
>> +       dect_channel_release(cell, tbc->rxb.trx, &tbc->rxb.chd);
>> +       dect_bearer_release(cell, &tbc->rxb);
>> +
>> +       list_del(&tbc->list);
>> +       kfree_skb(tbc->cs_tx_skb);
>> +       kfree(tbc);
>> +}
>> +
>> +static void dect_tbc_release_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       struct dect_tbc *tbc = data;
>> +
>> +       switch (tbc->state) {
>> +       default:
>> +               dect_tbc_state_change(tbc, DECT_TBC_RELEASING);
>> +               break;
>> +       case DECT_TBC_RELEASING:
>> +               dect_tbc_state_change(tbc, DECT_TBC_RELEASED);
>> +               break;
>> +       case DECT_TBC_NONE:
>> +       case DECT_TBC_REQ_SENT:
>> +       case DECT_TBC_RELEASED:
>> +               return dect_tbc_destroy(cell, tbc);
>> +       }
>> +
>> +       dect_tbc_send_release(tbc, tbc->release_reason);
>> +       dect_bearer_timer_add(tbc->cell, &tbc->txb, 
>> &tbc->release_timer,
>> +                             DECT_MT_FRAME_RATE);
>> +}
>> +
>> +static void dect_tbc_begin_release(struct dect_cell *cell, struct 
>> dect_tbc *tbc,
>> +                                  enum dect_release_reasons reason)
>> +{
>> +       tbc->release_reason = reason;
>> +       dect_tbc_release_timer(cell, tbc);
>> +}
>> +
>> +static void dect_tbc_dis_req(const struct dect_cell_handle *ch,
>> +                            const struct dect_tbc_id *id,
>> +                            enum dect_release_reasons reason)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               return;
>> +       tbc_debug(tbc, "TBC_DIS-req: reason: %u\n", reason);
>> +       dect_tbc_begin_release(cell, tbc, reason);
>> +}
>> +
>> +static int dect_tbc_establish(struct dect_cell *cell, struct dect_tbc 
>> *tbc)
>> +{
>> +       dect_tbc_state_change(tbc, DECT_TBC_ESTABLISHED);
>> +       if (dect_tbc_establish_cfm(tbc, true) < 0)
>> +               return -1;
>> +       return 0;
>> +}
>> +
>> +/**
>> + * dect_watchdog_timer - connection watchdog timer
>> + *
>> + * The watchdog timer is forwarded when an expected event occurs, on 
>> expiry
>> + * it will release the TBC. The relevant event depends on the TBC's 
>> state:
>> + *
>> + * Until ESTABLISHED state, P_T tails must be sent in every allowed 
>> frame.
>> + * The timer is forwarded when receiving a P_T tail in an allowed 
>> frame.
>> + *
>> + * In ESTABLISHED state, an RFPI handshake must be received at least
>> + * every T201 (5) seconds. The timer is forwarded when receiving an 
>> N_T
>> + * tail containing a matching RFPI.
>> + */
>> +static void dect_tbc_watchdog_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       struct dect_tbc *tbc = data;
>> +
>> +       tbc_debug(tbc, "watchdog expire\n");
>> +       if (tbc->state != DECT_TBC_ESTABLISHED) {
>> +               dect_tbc_establish_cfm(tbc, false);
>> +               dect_tbc_begin_release(cell, tbc, 
>> DECT_REASON_BEARER_SETUP_OR_HANDOVER_FAILED);
>> +       } else {
>> +               dect_tbc_release_notify(tbc, 
>> DECT_REASON_TIMEOUT_LOST_HANDSHAKE);
>> +               dect_tbc_begin_release(cell, tbc, 
>> DECT_REASON_TIMEOUT_LOST_HANDSHAKE);
>> +       }
>> +}
>> +
>> +static void dect_tbc_watchdog_reschedule(struct dect_cell *cell,
>> +                                        struct dect_tbc *tbc)
>> +{
>> +       u16 timeout;
>> +
>> +       if (tbc->state == DECT_TBC_ESTABLISHED)
>> +               timeout = DECT_TBC_RFPI_TIMEOUT;
>> +       else
>> +               timeout = DECT_MT_FRAME_RATE;
>> +
>> +       tbc_debug(tbc, "watchdog reschedule timeout: %u\n", timeout);
>> +       dect_bearer_timer_add(cell, &tbc->rxb, &tbc->wd_timer, 
>> timeout);
>> +}
>> +
>> +static int dect_tbc_check_attributes(struct dect_cell *cell, struct 
>> dect_tbc *tbc,
>> +                                    const struct dect_cctrl *cctl)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +
>> +       tbc_debug(tbc, "RX ATTRIBUTES_T_REQUEST\n");
>> +       tbc->id.ecn  = cctl->ecn;
>> +       tbc->id.lbn  = cctl->lbn;
>> +       tbc->service = cctl->service;
>> +
>> +       if (clh->ops->tbc_establish_ind(clh, &cell->handle, &tbc->id,
>> +                                       tbc->service, tbc->handover) < 
>> 0)
>> +               return -1;
>> +       return 0;
>> +}
>> +
>> +/**
>> + * dect_tbc_state_process - connection setup and maintenance state 
>> proccesing
>> + *
>> + * Process all messages before ESTABLISHED state, as well as all 
>> connection
>> + * control messages in ESTABLISHED state.
>> + */
>> +static int dect_tbc_state_process(struct dect_cell *cell, struct 
>> dect_tbc *tbc,
>> +                                 const struct dect_tail_msg *tm)
>> +{
>> +       const struct dect_cctrl *cctl = &tm->cctl;
>> +       struct sk_buff *m_skb;
>> +       u8 framenum;
>> +
>> +       if (tbc->state == DECT_TBC_OTHER_WAIT) {
>> +               tbc_debug(tbc, "RX in OTHER_WAIT\n");
>> +               /* Any message except RELEASE switches the bearer to
>> +                * ESTABLISHED state.
>> +                */
>> +               if ((tm->type == DECT_TM_TYPE_BCCTRL ||
>> +                    tm->type == DECT_TM_TYPE_ACCTRL) &&
>> +                   (cctl->fmid != cell->fmid ||
>> +                    cctl->pmid != dect_build_pmid(&tbc->id.pmid) ||
>> +                    cctl->cmd == DECT_CCTRL_RELEASE))
>> +                       goto release;
>> +
>> +               if (dect_tbc_establish(cell, tbc) < 0)
>> +                       goto release;
>> +               goto out;
>> +       }
>> +
>> +       /* Before OTHER_WAIT state, M_T tails must be received in 
>> every allowed
>> +        * frame. FPs may send M_T tails in uneven frames, PTs in even 
>> frames.
>> +        * Additionally FPs may transmit responses to BEARER_REQUEST 
>> messages in
>> +        * every frame.
>> +        */
>> +       framenum = dect_framenum(cell, DECT_TIMER_RX);
>> +       if (cell->mode == DECT_MODE_FP) {
>> +               if ((framenum & 0x1) == 1)
>> +                       return 1;
>> +       } else {
>> +               if ((framenum & 0x1) == 0 && tbc->state != 
>> DECT_TBC_REQ_SENT)
>> +                       return 1;
>> +       }
>> +
>> +       if (tm->type != DECT_TM_TYPE_BCCTRL && tm->type != 
>> DECT_TM_TYPE_ACCTRL)
>> +               goto release;
>> +
>> +       switch (cctl->cmd) {
>> +       case DECT_CCTRL_ATTRIBUTES_T_REQUEST:
>> +       case DECT_CCTRL_ATTRIBUTES_T_CONFIRM:
>> +       case DECT_CCTRL_BANDWIDTH_T_REQUEST:
>> +       case DECT_CCTRL_BANDWIDTH_T_CONFIRM:
>> +       case DECT_CCTRL_CHANNEL_LIST:
>> +               break;
>> +       default:
>> +               if (cctl->fmid != cell->fmid)
>> +                       goto release;
>> +               /* fall through */
>> +       case DECT_CCTRL_RELEASE:
>> +               if (cctl->pmid != dect_build_pmid(&tbc->id.pmid))
>> +                       goto release;
>> +       }
>> +
>> +       switch ((int)tbc->state) {
>> +       case DECT_TBC_NONE:
>> +               /*
>> +                * Receiving side, initial request.
>> +                */
>> +               dect_tbc_state_change(tbc, DECT_TBC_REQ_RCVD);
>> +               break;
>> +
>> +       case DECT_TBC_REQ_RCVD:
>> +       case DECT_TBC_RESPONSE_SENT:
>> +               /*
>> +                * Receiving side: waiting for LLME to create MBC. 
>> Only "WAIT"
>> +                * messages are valid in both directions.
>> +                */
>> +               tbc_debug(tbc, "RX in REQ_RCVD: %llx\n",
>> +                         (unsigned long long)cctl->cmd);
>> +
>> +               if (tbc->type == DECT_MAC_CONN_ADVANCED &&
>> +                   cctl->cmd == DECT_CCTRL_ATTRIBUTES_T_REQUEST)
>> +                       dect_tbc_check_attributes(cell, tbc, cctl);
>> +               else if (cctl->cmd != DECT_CCTRL_WAIT)
>> +                       goto release;
>> +
>> +               m_skb = dect_tbc_build_cctrl(tbc, DECT_CCTRL_WAIT);
>> +               if (m_skb == NULL)
>> +                       goto release;
>> +               dect_tbc_queue_mac_control(tbc, m_skb);
>> +               break;
>> +
>> +       case DECT_TBC_REQ_SENT:
>> +       case DECT_TBC_WAIT_RCVD:
>> +               /*
>> +                * Initiator: request was sent, waiting for confirm. 
>> "WAIT"
>> +                * messages must be responded to with another "WAIT" 
>> message.
>> +                */
>> +               tbc_debug(tbc, "Reply in REQ_SENT %u\n", tm->type);
>> +               if (cctl->cmd != DECT_CCTRL_BEARER_CONFIRM) {
>> +                       if (cctl->cmd != DECT_CCTRL_WAIT)
>> +                               goto release;
>> +
>> +                       m_skb = dect_tbc_build_cctrl(tbc, 
>> DECT_CCTRL_WAIT);
>> +                       if (m_skb == NULL)
>> +                               goto release;
>> +                       dect_tbc_queue_mac_control(tbc, m_skb);
>> +
>> +                       dect_tbc_state_change(tbc, 
>> DECT_TBC_WAIT_RCVD);
>> +               } else {
>> +                       tbc_debug(tbc, "Confirmed\n");
>> +                       m_skb = dect_tbc_build_cctrl(tbc, 
>> DECT_CCTRL_WAIT);
>> +                       if (m_skb == NULL)
>> +                               goto release;
>> +                       dect_tbc_queue_mac_control(tbc, m_skb);
>> +
>> +                       dect_tbc_state_change(tbc, 
>> DECT_TBC_OTHER_WAIT);
>> +               }
>> +               break;
>> +
>> +       case DECT_TBC_ESTABLISHED:
>> +               if (cctl->cmd != DECT_CCTRL_RELEASE)
>> +                       break;
>> +               /* Immediate release */
>> +               dect_tbc_release_notify(tbc, 
>> DECT_REASON_BEARER_RELEASE);
>> +               dect_tbc_destroy(cell, tbc);
>> +               return 0;
>> +
>> +       case DECT_TBC_RELEASING:
>> +               /*
>> +                * Unacknowledged release procedure in progress, 
>> ignore the
>> +                * packet unless its a release message, in which case 
>> the
>> +                * bearer can be destroyed immediately (crossed bearer 
>> release
>> +                * procedure).
>> +                */
>> +               if (cctl->cmd == DECT_CCTRL_RELEASE)
>> +                       dect_tbc_destroy(cell, tbc);
>> +
>> +       case DECT_TBC_RELEASED:
>> +               return 0;
>> +       }
>> +
>> +out:
>> +       dect_tbc_watchdog_reschedule(cell, tbc);
>> +       return 1;
>> +
>> +release:
>> +       dect_tbc_establish_cfm(tbc, false);
>> +       dect_tbc_begin_release(cell, tbc, DECT_REASON_UNKNOWN);
>> +       return 0;
>> +}
>> +
>> +static void dect_tbc_enc_timer(struct dect_cell *cell, void *data)
>> +{
>> +       struct dect_tbc *tbc = data;
>> +       enum dect_encctrl_cmds cmd;
>> +       struct sk_buff *skb;
>> +
>> +       tbc_debug(tbc, "encryption timer: state: %u cnt: %u\n",
>> +                 tbc->enc_state, tbc->enc_msg_cnt);
>> +
>> +       if (++tbc->enc_msg_cnt > 5) {
>> +               dect_tbc_release_notify(tbc, 
>> DECT_REASON_BEARER_RELEASE);
>> +               return dect_tbc_begin_release(cell, tbc, 
>> DECT_REASON_BEARER_RELEASE);
>> +       }
>> +
>> +       dect_bearer_timer_add(cell, &tbc->txb, &tbc->enc_timer, 2);
>> +
>> +       switch (tbc->enc_state) {
>> +       case DECT_TBC_ENC_START_REQ_RCVD:
>> +               tbc_debug(tbc, "TX encryption enabled\n");
>> +               dect_enable_cipher(tbc->txb.trx, tbc->txb.chd.slot, 
>> tbc->ck);
>> +               /* fall through */
>> +       case DECT_TBC_ENC_START_CFM_SENT:
>> +               tbc->enc_state = DECT_TBC_ENC_START_CFM_SENT;
>> +               cmd = DECT_ENCCTRL_START_CONFIRM;
>> +               break;
>> +       case DECT_TBC_ENC_START_REQ_SENT:
>> +               cmd = DECT_ENCCTRL_START_REQUEST;
>> +               break;
>> +       default:
>> +               return;
>> +       }
>> +
>> +       skb = dect_tbc_build_encctrl(tbc, cmd);
>> +       if (skb != NULL)
>> +               dect_tbc_queue_mac_control(tbc, skb);
>> +}
>> +
>> +static int dect_tbc_enc_state_process(struct dect_cell *cell,
>> +                                     struct dect_tbc *tbc,
>> +                                     const struct dect_tail_msg *tm)
>> +{
>> +       const struct dect_encctrl *ectl = &tm->encctl;
>> +       struct sk_buff *skb;
>> +
>> +       if (ectl->fmid != cell->fmid ||
>> +           ectl->pmid != dect_build_pmid(&tbc->id.pmid))
>> +               return 0;
>> +
>> +       switch (ectl->cmd) {
>> +       case DECT_ENCCTRL_START_REQUEST:
>> +               if (tbc->enc_state != DECT_TBC_ENC_DISABLED ||
>> +                   cell->mode != DECT_MODE_FP)
>> +                       break;
>> +               tbc->enc_state = DECT_TBC_ENC_START_REQ_RCVD;
>> +               tbc->enc_msg_cnt = 0;
>> +
>> +               dect_bearer_timer_add(cell, &tbc->txb, 
>> &tbc->enc_timer, 0);
>> +               break;
>> +       case DECT_ENCCTRL_START_CONFIRM:
>> +               if (tbc->enc_state == DECT_TBC_ENC_START_REQ_SENT) {
>> +                       tbc->enc_state = DECT_TBC_ENC_START_CFM_RCVD;
>> +                       tbc->enc_msg_cnt = 0;
>> +
>> +                       dect_timer_del(&tbc->enc_timer);
>> +                       tbc_debug(tbc, "TX encryption enabled\n");
>> +                       dect_enable_cipher(tbc->txb.trx, 
>> tbc->txb.chd.slot,
>> +                                          tbc->ck);
>> +               }
>> +               if (tbc->enc_state == DECT_TBC_ENC_START_CFM_RCVD) {
>> +                       skb = dect_tbc_build_encctrl(tbc, 
>> DECT_ENCCTRL_START_GRANT);
>> +                       if (skb != NULL)
>> +                               dect_tbc_queue_mac_control(tbc, skb);
>> +               }
>> +               break;
>> +       case DECT_ENCCTRL_START_GRANT:
>> +               if (tbc->enc_state != DECT_TBC_ENC_START_CFM_SENT)
>> +                       break;
>> +               tbc->enc_state = DECT_TBC_ENC_ENABLED;
>> +
>> +               dect_timer_del(&tbc->enc_timer);
>> +               tbc_debug(tbc, "RX encryption enabled\n");
>> +               dect_enable_cipher(tbc->rxb.trx, tbc->rxb.chd.slot, 
>> tbc->ck);
>> +               dect_tbc_event(tbc, DECT_TBC_CIPHER_ENABLED);
>> +               break;
>> +       case DECT_ENCCTRL_STOP_REQUEST:
>> +               break;
>> +       case DECT_ENCCTRL_STOP_CONFIRM:
>> +               break;
>> +       case DECT_ENCCTRL_STOP_GRANT:
>> +               break;
>> +       default:
>> +               return 0;
>> +       }
>> +       return 1;
>> +}
>> +
>> +static void dect_tbc_queue_cs_data(struct dect_cell *cell, struct 
>> dect_tbc *tbc,
>> +                                  struct sk_buff *skb,
>> +                                  const struct dect_tail_msg *tm)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +
>> +       skb = skb_clone(skb, GFP_ATOMIC);
>> +       if (skb == NULL)
>> +               return;
>> +       skb_pull(skb, DECT_T_FIELD_OFF);
>> +       skb_trim(skb, DECT_C_S_SDU_SIZE);
>> +
>> +       DECT_CS_CB(skb)->seq = tm->ctd.seq;
>> +       clh->ops->tbc_data_ind(clh, &tbc->id, DECT_MC_C_S, skb);
>> +}
>> +
>> +static void dect_tbc_update_handover_state(struct dect_tbc *tbc, bool 
>> ok)
>> +{
>> +       const struct dect_cluster_handle *clh = tbc->cell->handle.clh;
>> +
>> +       if (ok) {
>> +               tbc->handover_tokens += DECT_TBC_HO_TOKENS_OK;
>> +               if (tbc->handover_tokens > DECT_TBC_HO_TOKENS_MAX)
>> +                       tbc->handover_tokens = DECT_TBC_HO_TOKENS_MAX;
>> +       } else {
>> +               tbc->handover_tokens -= DECT_TBC_HO_TOKENS_ERROR;
>> +               if (tbc->handover_tokens < 0)
>> +                       tbc->handover_tokens = 0;
>> +       }
>> +
>> +       tbc_debug(tbc, "handover: ok: %u tokens: %d\n", ok, 
>> tbc->handover_tokens);
>> +       if (tbc->handover_tokens == 0)
>> +               clh->ops->tbc_handover_req(clh, &tbc->id);
>> +}
>> +
>> +static void dect_tbc_report_rssi(struct dect_cell *cell,
>> +                                struct dect_bearer *bearer,
>> +                                u8 slot, u8 rssi)
>> +{
>> +       struct dect_tbc *tbc = bearer->tbc;
>> +
>> +       /* A RSSI report implies an In-Sync error */
>> +       if (cell->mode == DECT_MODE_PP)
>> +               dect_tbc_update_handover_state(tbc, false);
>> +}
>> +
>> +#define DECT_CHECKSUM_ALL \
>> +       (DECT_CHECKSUM_A_CRC_OK | DECT_CHECKSUM_X_CRC_OK | 
>> DECT_CHECKSUM_Z_CRC_OK)
>> +
>> +static bool dect_tbc_checksum_ok(const struct sk_buff *skb)
>> +{
>> +       return (DECT_TRX_CB(skb)->csum & DECT_CHECKSUM_ALL) == 
>> DECT_CHECKSUM_ALL;
>> +}
>> +
>> +static void dect_tbc_rcv(struct dect_cell *cell, struct dect_bearer 
>> *bearer,
>> +                        struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +       struct dect_tbc *tbc = bearer->tbc;
>> +       struct dect_tail_msg _tm, *tm = &_tm;
>> +       bool a_crc_ok, collision;
>> +       bool q1, q2;
>> +
>> +       dect_raw_rcv(skb);
>> +
>> +       if (cell->mode == DECT_MODE_PP)
>> +               dect_tbc_update_handover_state(tbc, 
>> dect_tbc_checksum_ok(skb));
>> +
>> +       /* Verify A-field checksum. Sucessful reception of the A-field 
>> is
>> +        * indicated by transmitting the Q2 bit in the reverse 
>> direction
>> +        * or the Q1 bit in the direction FP->PP when Q1 is set to 0.
>> +        */
>> +       if (DECT_TRX_CB(skb)->csum & DECT_CHECKSUM_A_CRC_OK)
>> +               tbc->txb.q = DECT_HDR_Q2_FLAG;
>> +       else
>> +               goto rcv_b_field;
>> +
>> +       /* Q1 and Q2 bit settings for MAC service IN as per section 
>> 10.8.1.3.1 */
>> +       q1 = skb->data[DECT_HDR_Q1_OFF] & DECT_HDR_Q1_FLAG;
>> +       q2 = skb->data[DECT_HDR_Q2_OFF] & DECT_HDR_Q2_FLAG;
>> +
>> +       if (cell->mode == DECT_MODE_FP)
>> +               a_crc_ok = q2;
>> +       else {
>> +               if (q2) {
>> +                       a_crc_ok  = true;
>> +                       collision = q1;
>> +                       /* ignore collision indications for now as the
>> +                        * transceiver firmware seems to improperly 
>> transmit
>> +                        * the Z-Field.
>> +                        */
>> +                       collision = false;
>> +               } else {
>> +                       a_crc_ok  = q1;
>> +                       collision = false;
>> +               }
>> +
>> +               dect_tbc_update_handover_state(tbc, a_crc_ok && 
>> !collision);
>> +       }
>> +
>> +       if (tbc->cs_tx_ok) {
>> +               if (a_crc_ok) {
>> +                       tbc_debug(tbc, "ARQ acknowledgement\n");
>> +                       dect_tbc_event(tbc, DECT_TBC_ACK_RECEIVED);
>> +               } else
>> +                       tbc_debug(tbc, "C-channel data lost\n");
>> +       }
>> +
>> +       if (dect_parse_tail_msg(tm, skb) < 0)
>> +               goto err;
>> +
>> +       if (tbc->state != DECT_TBC_ESTABLISHED ||
>> +           tm->type == DECT_TM_TYPE_BCCTRL ||
>> +           tm->type == DECT_TM_TYPE_ACCTRL) {
>> +               if (!dect_tbc_state_process(cell, tbc, tm))
>> +                       goto err;
>> +       }
>> +
>> +       tbc_debug(tbc, "receive\n");
>> +
>> +       /* Reschedule watchdog on successful RFPI handshake. */
>> +       if (tm->type == DECT_TM_TYPE_ID && !dect_rfpi_cmp(&tm->idi, 
>> &cell->idi))
>> +               dect_tbc_watchdog_reschedule(cell, tbc);
>> +
>> +       if (tm->type == DECT_TM_TYPE_ENCCTRL) {
>> +               if (!dect_tbc_enc_state_process(cell, tbc, tm))
>> +                       goto err;
>> +       }
>> +
>> +       dect_bc_rcv(cell, &tbc->bc, skb, tm);
>> +
>> +       switch (tbc->enc_state) {
>> +       case DECT_TBC_ENC_START_REQ_SENT:
>> +       case DECT_TBC_ENC_START_CFM_SENT:
>> +               goto err;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       if (tbc->state != DECT_TBC_REQ_RCVD &&
>> +           tbc->state != DECT_TBC_RESPONSE_SENT) {
>> +               if (tm->type == DECT_TM_TYPE_CT)
>> +                       dect_tbc_queue_cs_data(cell, tbc, skb, tm);
>> +       }
>> +
>> +rcv_b_field:
>> +       switch (dect_parse_b_id(skb)) {
>> +       case DECT_BI_UTYPE_0:
>> +       case DECT_BI_UTYPE_1:
>> +               break;
>> +       default:
>> +               goto err;
>> +       }
>> +
>> +       skb_pull(skb, DECT_A_FIELD_SIZE);
>> +       skb_trim(skb, dect_b_field_size(&bearer->chd));
>> +       clh->ops->tbc_data_ind(clh, &tbc->id, DECT_MC_I_N, skb);
>> +       return;
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_tbc_data_req(const struct dect_cell_handle *ch,
>> +                             const struct dect_tbc_id *id,
>> +                             enum dect_data_channels chan,
>> +                             struct sk_buff *skb)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               goto err;
>> +       tbc_debug(tbc, "TBC_DATA-req: chan: %u len: %u\n", chan, 
>> skb->len);
>> +
>> +       switch (chan) {
>> +       case DECT_MC_C_S:
>> +               DECT_A_CB(skb)->id = DECT_CS_CB(skb)->seq ? 
>> DECT_TI_CT_PKT_1 :
>> +                                                           
>> DECT_TI_CT_PKT_0;
>> +               tbc->cs_tx_skb = skb;
>> +               break;
>> +       case DECT_MC_I_N:
>> +               tbc->b_tx_skb = skb;
>> +               break;
>> +       default:
>> +               goto err;
>> +       }
>> +       return;
>> +
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static int dect_tbc_enc_req(const struct dect_cell_handle *ch,
>> +                           const struct dect_tbc_id *id, u64 ck)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               return -ENOENT;
>> +
>> +       tbc_debug(tbc, "RX/TX encryption enabled: ck: %.16llx\n",
>> +                 (unsigned long long)ck);
>> +
>> +       tbc->ck = ck;
>> +       dect_enable_cipher(tbc->rxb.trx, tbc->rxb.chd.slot, tbc->ck);
>> +       dect_enable_cipher(tbc->txb.trx, tbc->txb.chd.slot, tbc->ck);
>> +       return 0;
>> +}
>> +
>> +static int dect_tbc_enc_eks_req(const struct dect_cell_handle *ch,
>> +                               const struct dect_tbc_id *id,
>> +                               enum dect_cipher_states status)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +       struct sk_buff *skb;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               return -ENOENT;
>> +
>> +       tbc_debug(tbc, "TBC_ENC_EKS-req: status: %u\n", status);
>> +       skb = dect_tbc_build_encctrl(tbc, DECT_ENCCTRL_START_REQUEST);
>> +       if (skb != NULL)
>> +               dect_tbc_queue_mac_control(tbc, skb);
>> +
>> +       tbc->enc_state = DECT_TBC_ENC_START_REQ_SENT;
>> +       tbc->enc_msg_cnt = 0;
>> +       dect_bearer_timer_add(cell, &tbc->txb, &tbc->enc_timer, 0);
>> +
>> +       tbc_debug(tbc, "RX encryption enabled\n");
>> +       dect_enable_cipher(tbc->rxb.trx, tbc->rxb.chd.slot, tbc->ck);
>> +       return 0;
>> +}
>> +
>> +static int dect_tbc_enc_key_req(const struct dect_cell_handle *ch,
>> +                               const struct dect_tbc_id *id, u64 ck)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               return -ENOENT;
>> +
>> +       tbc_debug(tbc, "TBC_ENC_KEY-req: key: %.16llx\n", (unsigned 
>> long long)ck);
>> +       tbc->ck = ck;
>> +       return 0;
>> +}
>> +
>> +static void dect_tbc_enable(struct dect_cell *cell, struct dect_tbc 
>> *tbc)
>> +{
>> +       dect_bearer_enable(&tbc->rxb);
>> +       dect_bearer_enable(&tbc->txb);
>> +       dect_bc_init(cell, &tbc->bc);
>> +}
>> +
>> +/*
>> + * Activation timer: enable the bearer once the TX channel is 
>> accessible,
>> + * which is defined by the receivers scanning sequence.
>> + */
>> +static void dect_tbc_enable_timer(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer)
>> +{
>> +       struct dect_tbc *tbc = bearer->tbc;
>> +       struct sk_buff *skb;
>> +       enum dect_cctrl_cmds cmd;
>> +
>> +       tbc_debug(tbc, "TX ACCESS_REQUEST\n");
>> +       if (tbc->handover)
>> +               cmd = DECT_CCTRL_BEARER_HANDOVER_REQ;
>> +       else
>> +               cmd = DECT_CCTRL_ACCESS_REQ;
>> +
>> +       skb = dect_tbc_build_cctrl(tbc, cmd);
>> +       if (skb == NULL)
>> +               return;
>> +
>> +       /* The packet overrides the T-MUX rules. PPs use a special 
>> tail
>> +        * coding for the first transmission. */
>> +       skb->priority = DECT_MT_HIGH_PRIORITY;
>> +       if (cell->mode == DECT_MODE_FP)
>> +               DECT_A_CB(skb)->id = DECT_TI_MT;
>> +       else
>> +               DECT_A_CB(skb)->id = DECT_TI_MT_PKT_0;
>> +
>> +       dect_tbc_enable(cell, tbc);
>> +       dect_tbc_queue_mac_control(tbc, skb);
>> +       dect_tbc_state_change(tbc, DECT_TBC_REQ_SENT);
>> +
>> +       /* Start watchdog */
>> +       dect_bearer_timer_add(cell, &tbc->rxb, &tbc->wd_timer, 1);
>> +}
>> +
>> +static const struct dect_bearer_ops dect_tbc_ops = {
>> +       .state          = DECT_TRAFFIC_BEARER,
>> +       .enable         = dect_tbc_enable_timer,
>> +       .rcv            = dect_tbc_rcv,
>> +       .report_rssi    = dect_tbc_report_rssi,
>> +};
>> +
>> +/**
>> + * dect_tbc_init - initialise a traffic bearer control instance
>> + *
>> + * @cell:      DECT cell
>> + * @id:                MBC ID
>> + * @rchd:      RX channel description
>> + * @tchd:      TX channel description
>> + */
>> +static struct dect_tbc *dect_tbc_init(struct dect_cell *cell,
>> +                                     const struct dect_tbc_id *id,
>> +                                     struct dect_transceiver *rtrx,
>> +                                     struct dect_transceiver *ttrx,
>> +                                     const struct dect_channel_desc 
>> *rchd,
>> +                                     const struct dect_channel_desc 
>> *tchd)
>> +
>> +{
>> +       struct dect_tbc *tbc;
>> +
>> +       tbc = kzalloc(sizeof(*tbc), GFP_ATOMIC);
>> +       if (tbc == NULL)
>> +               return NULL;
>> +
>> +       tbc->cell            = cell;
>> +       tbc->id              = *id;
>> +       tbc->handover_tokens = DECT_TBC_HO_TOKENS_INITIAL;
>> +
>> +       INIT_LIST_HEAD(&tbc->bc.list);
>> +       dect_timer_init(&tbc->wait_timer);
>> +       dect_timer_setup(&tbc->wd_timer, dect_tbc_watchdog_timer, 
>> tbc);
>> +       dect_timer_setup(&tbc->release_timer, dect_tbc_release_timer, 
>> tbc);
>> +       dect_timer_setup(&tbc->enc_timer, dect_tbc_enc_timer, tbc);
>> +
>> +       dect_bearer_init(cell, &tbc->rxb, &dect_tbc_ops,
>> +                        rtrx, rchd, DECT_BEARER_RX, tbc);
>> +       dect_bearer_init(cell, &tbc->txb, &dect_tbc_ops,
>> +                        ttrx, tchd, DECT_BEARER_TX, tbc);
>> +
>> +       list_add_tail(&tbc->list, &cell->tbcs);
>> +       return tbc;
>> +}
>> +
>> +static int dect_tbc_establish_req(const struct dect_cell_handle *ch,
>> +                                 const struct dect_tbc_id *id,
>> +                                 const struct dect_channel_desc *chd,
>> +                                 enum dect_mac_service_types service,
>> +                                 bool handover)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_transceiver *ttrx, *rtrx;
>> +       struct dect_channel_desc tchd, rchd;
>> +       struct dect_tbc *tbc;
>> +       u8 rssi;
>> +       int err;
>> +
>> +       /* Select TDD slot pair and reserve transceiver resources */
>> +       tchd.pkt   = chd->pkt;
>> +       tchd.b_fmt = chd->b_fmt;
>> +       err = dect_select_channel(cell, &ttrx, &tchd, &rssi, true);
>> +       if (err < 0)
>> +               goto err1;
>> +       dect_channel_reserve(cell, ttrx, &tchd);
>> +
>> +       err = -ENOSPC;
>> +       dect_tdd_channel_desc(&rchd, &tchd);
>> +       rtrx = dect_select_transceiver(cell, &rchd);
>> +       if (rtrx == NULL)
>> +               goto err2;
>> +       dect_channel_reserve(cell, rtrx, &rchd);
>> +
>> +       err = -ENOMEM;
>> +       tbc = dect_tbc_init(cell, id, rtrx, ttrx, &rchd, &tchd);
>> +       if (tbc == NULL)
>> +               goto err3;
>> +       tbc->id.tbei  = dect_tbc_alloc_tbei(cell);
>> +       tbc->service  = service;
>> +       tbc->handover = handover;
>> +
>> +       tbc_debug(tbc, "TBC_ESTABLISH-req: handover: %d\n", handover);
>> +       dect_tx_bearer_schedule(cell, &tbc->txb, rssi);
>> +       return 0;
>> +
>> +err3:
>> +       dect_channel_release(cell, rtrx, &rchd);
>> +err2:
>> +       dect_channel_release(cell, ttrx, &tchd);
>> +err1:
>> +       return err;
>> +}
>> +
>> +/* TBC establishment confirmation from CCF */
>> +static int dect_tbc_establish_res(const struct dect_cell_handle *ch,
>> +                                 const struct dect_tbc_id *id)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_tbc *tbc;
>> +       int err;
>> +
>> +       tbc = dect_tbc_get_by_tbei(cell, id->tbei);
>> +       if (tbc == NULL)
>> +               return -ENOENT;
>> +       tbc_debug(tbc, "TBC_ESTABLISH-res\n");
>> +       WARN_ON(tbc->state != DECT_TBC_REQ_RCVD);
>> +
>> +       /* Stop wait timer and send CONFIRM */
>> +       dect_timer_del(&tbc->wait_timer);
>> +       if (tbc->type == DECT_MAC_CONN_BASIC)
>> +               err = dect_tbc_send_confirm(tbc);
>> +       else
>> +               err = dect_tbc_send_attributes_confirm(tbc);
>> +       if (err < 0)
>> +               return err;
>> +
>> +       dect_tbc_state_change(tbc, DECT_TBC_OTHER_WAIT);
>> +       return 0;
>> +}
>> +
>> +static void dect_tbc_wait_timer(struct dect_cell *cell, void *data)
>> +{
>> +       struct dect_tbc *tbc = data;
>> +       struct sk_buff *skb;
>> +
>> +       tbc_debug(tbc, "wait timer\n");
>> +       skb = dect_tbc_build_cctrl(tbc, DECT_CCTRL_WAIT);
>> +       if (skb == NULL)
>> +               return;
>> +
>> +       /* The first response is permitted in any frame */
>> +       if (tbc->state == DECT_TBC_REQ_RCVD)
>> +               skb->priority = DECT_MT_HIGH_PRIORITY;
>> +       dect_tbc_queue_mac_control(tbc, skb);
>> +
>> +       dect_tbc_state_change(tbc, DECT_TBC_RESPONSE_SENT);
>> +}
>> +
>> +/**
>> + * dect_tbc_rcv_request - handle incoming connection setup attempts
>> + *
>> + *
>> + */
>> +static void dect_tbc_rcv_request(struct dect_cell *cell,
>> +                                const struct dect_transceiver_slot 
>> *ts,
>> +                                const struct dect_tail_msg *tm,
>> +                                struct sk_buff *skb)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +       struct dect_transceiver *rtrx, *ttrx;
>> +       struct dect_channel_desc rchd, tchd;
>> +       struct dect_tbc_id id;
>> +       struct dect_tbc *tbc;
>> +       bool handover = false;
>> +
>> +       if (tm->cctl.fmid != cell->fmid)
>> +               goto err1;
>> +       dect_raw_rcv(skb);
>> +
>> +       switch (tm->cctl.cmd) {
>> +       case DECT_CCTRL_ACCESS_REQ:
>> +               break;
>> +       case DECT_CCTRL_BEARER_HANDOVER_REQ:
>> +       case DECT_CCTRL_CONNECTION_HANDOVER_REQ:
>> +               /* Handover can only be initiated by the PP */
>> +               if (cell->mode == DECT_MODE_FP) {
>> +                       handover = true;
>> +                       break;
>> +               }
>> +       default:
>> +               rx_debug(cell, "unhandled TBC request: %llu\n",
>> +                        (unsigned long long)tm->cctl.cmd);
>> +               goto err1;
>> +       }
>> +
>> +       /* Select transceivers for RX/TX and reserve resources */
>> +       memcpy(&rchd, &ts->chd, sizeof(rchd));
>> +       rchd.pkt   = DECT_PACKET_P32;
>> +       rchd.b_fmt = DECT_B_UNPROTECTED;
>> +       rtrx = dect_select_transceiver(cell, &rchd);
>> +       if (rtrx == NULL)
>> +               goto err1;
>> +       dect_channel_reserve(cell, rtrx, &rchd);
>> +
>> +       dect_tdd_channel_desc(&tchd, &rchd);
>> +       ttrx = dect_select_transceiver(cell, &tchd);
>> +       if (ttrx == NULL)
>> +               goto err2;
>> +       dect_channel_reserve(cell, ttrx, &tchd);
>> +
>> +       memset(&id, 0, sizeof(id));
>> +       memcpy(&id.ari, &cell->idi.pari, sizeof(id.ari));
>> +       dect_parse_pmid(&id.pmid, tm->cctl.pmid);
>> +       id.lbn  = 0xf;
>> +       id.ecn  = 0;
>> +       id.tbei = dect_tbc_alloc_tbei(cell);
>> +
>> +       /* Initialize TBC */
>> +       tbc = dect_tbc_init(cell, &id, rtrx, ttrx, &rchd, &tchd);
>> +       if (tbc == NULL)
>> +               goto err3;
>> +
>> +       tbc->handover = handover;
>> +
>> +       if (tm->type == DECT_TM_TYPE_BCCTRL) {
>> +               /* Basic MAC connections only support the 
>> I_N_minimal_delay service */
>> +               tbc->type    = DECT_MAC_CONN_BASIC;
>> +               tbc->service = DECT_SERVICE_IN_MIN_DELAY;
>> +       } else {
>> +               /* Service is unknown at this time */
>> +               tbc->type    = DECT_MAC_CONN_ADVANCED;
>> +               tbc->service = DECT_SERVICE_UNKNOWN;
>> +       }
>> +
>> +       dect_tbc_state_change(tbc, DECT_TBC_REQ_RCVD);
>> +       tbc_debug(tbc, "RCV ACCESS_REQUEST\n");
>> +
>> +       /* Set Q2 bit on first response */
>> +       tbc->txb.q = DECT_HDR_Q2_FLAG;
>> +
>> +       /* Start the WAIT transmit timer */
>> +       dect_timer_setup(&tbc->wait_timer, dect_tbc_wait_timer, tbc);
>> +       dect_bearer_timer_add(cell, &tbc->txb, &tbc->wait_timer, 1);
>> +
>> +       /* Start watchdog timer: until ESTABLISHED state, the remote 
>> side
>> +        * must transmit a M-tail in every allowed frame. */
>> +       dect_tbc_watchdog_reschedule(cell, tbc);
>> +       dect_tbc_enable(cell, tbc);
>> +
>> +       if (tbc->type == DECT_MAC_CONN_BASIC) {
>> +               if (clh->ops->tbc_establish_ind(clh, &cell->handle, 
>> &tbc->id,
>> +                                               tbc->service, 
>> tbc->handover) < 0)
>> +                       goto err4;
>> +       } else {
>> +               if (dect_tbc_send_confirm(tbc) < 0)
>> +                       goto err4;
>> +               dect_tbc_state_change(tbc, DECT_TBC_RESPONSE_SENT);
>> +       }
>> +
>> +       kfree_skb(skb);
>> +       return;
>> +
>> +err4:
>> +       dect_tbc_destroy(cell, tbc);
>> +err3:
>> +       dect_channel_release(cell, ttrx, &tchd);
>> +err2:
>> +       dect_channel_release(cell, rtrx, &rchd);
>> +err1:
>> +       kfree_skb(skb);
>> +}
>> +
>> +#if 0
>> +/*
>> + * Connectionless Bearer Control (CBC)
>> + */
>> +
>> +static void dect_cbc_rcv(struct dect_cell *cell, struct dect_bearer 
>> *bearer,
>> +                        struct sk_buff *skb)
>> +{
>> +       struct dect_cbc *cbc = bearer->cbc;
>> +       struct dect_tail_msg tm;
>> +
>> +       dect_parse_tail_msg(&tm, skb);
>> +       dect_bc_rcv(cell, &cbc->bc, skb, &tm);
>> +       kfree_skb(skb);
>> +}
>> +
>> +static const struct dect_bearer_ops dect_cbc_ops = {
>> +       .state          = DECT_CL_BEARER,
>> +       .rcv            = dect_cbc_rcv,
>> +};
>> +
>> +/**
>> + * dect_cbc_init - Initialise a connectionless bearer control
>> + *
>> + * @cell:      DECT cell
>> + * @chd:       channel description
>> + */
>> +static struct dect_cbc *dect_cbc_init(struct dect_cell *cell,
>> +                                     struct dect_channel_desc *chd)
>> +{
>> +       struct dect_bearer *bearer;
>> +       enum dect_slot_states mode;
>> +       struct dect_cbc *cbc = NULL;
>> +
>> +       bearer = dect_bearer_init(cell, &dect_cbc_ops, 
>> DECT_SIMPLEX_BEARER,
>> +                                 NULL, chd, mode, cbc);
>> +       if (bearer == NULL)
>> +               return NULL;
>> +       cbc->dl_bearer = bearer;
>> +
>> +       dect_bc_init(cell, &cbc->bc);
>> +       return cbc;
>> +}
>> +#endif
>> +
>> +/*
>> + * Dummy Bearer Control (DBC)
>> + */
>> +
>> +#define dbc_debug(dbc, fmt, args...) \
>> +       pr_debug("DBC slot %u carrier %u: " fmt, \
>> +                (dbc)->bearer.chd.slot, (dbc)->bearer.chd.carrier, ## 
>> args)
>> +
>> +static void dect_dbc_rcv(struct dect_cell *cell, struct dect_bearer 
>> *bearer,
>> +                        struct sk_buff *skb)
>> +{
>> +       struct dect_dbc *dbc = bearer->dbc;
>> +       struct dect_tail_msg tm;
>> +
>> +       /* Update A-field receive time stamp (A-field CRC is always 
>> correct) */
>> +       if (dect_framenum(cell, DECT_TIMER_RX) == 0)
>> +               cell->a_rcv_stamp = jiffies;
>> +
>> +       dect_raw_rcv(skb);
>> +
>> +       if (dect_parse_tail_msg(&tm, skb) < 0)
>> +               goto err;
>> +
>> +       /* Update Nt receive stamp if PARI matches */
>> +       if (tm.type == DECT_TM_TYPE_ID && !dect_rfpi_cmp(&tm.idi, 
>> &cell->idi))
>> +               cell->nt_rcv_stamp = jiffies;
>> +
>> +       dect_bc_rcv(cell, &dbc->bc, skb, &tm);
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_dbc_report_rssi(struct dect_cell *cell,
>> +                                struct dect_bearer *bearer,
>> +                                u8 slot, u8 rssi)
>> +{
>> +       dbc_debug(bearer->dbc, "RSSI: selection: %u now: %u\n", 
>> bearer->rssi, rssi);
>> +}
>> +
>> +static void dect_dbc_quality_control_timer(struct dect_cell *cell, 
>> void *data)
>> +{
>> +       struct dect_dbc *dbc = data;
>> +       struct dect_bearer *bearer = &dbc->bearer;
>> +
>> +       switch (dbc->qctrl) {
>> +       case DECT_BEARER_QCTRL_WAIT:
>> +               dbc_debug(dbc, "quality control: confirm quality\n");
>> +               dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_RX);
>> +               dect_set_carrier(bearer->trx, bearer->chd.slot, 
>> bearer->chd.carrier);
>> +               dbc->qctrl = DECT_BEARER_QCTRL_CONFIRM;
>> +               dect_timer_add(cell, &dbc->qctrl_timer, DECT_TIMER_TX,
>> +                              1, bearer->chd.slot);
>> +               break;
>> +       case DECT_BEARER_QCTRL_CONFIRM:
>> +               dbc_debug(dbc, "quality control: wait\n");
>> +               dect_set_channel_mode(bearer->trx, &bearer->chd, 
>> DECT_SLOT_TX);
>> +               dect_set_carrier(bearer->trx, bearer->chd.slot, 
>> bearer->chd.carrier);
>> +               dbc->qctrl = DECT_BEARER_QCTRL_WAIT;
>> +               dect_timer_add(cell, &dbc->qctrl_timer, DECT_TIMER_TX,
>> +                              DECT_BEARER_QCTRL_PERIOD - 1, 
>> bearer->chd.slot);
>> +               break;
>> +       }
>> +}
>> +
>> +static void dect_dbc_enable(struct dect_cell *cell, struct 
>> dect_bearer *bearer)
>> +{
>> +       struct dect_dbc *dbc = bearer->dbc;
>> +       u8 framenum = dect_framenum(cell, DECT_TIMER_TX);
>> +       u8 extra;
>> +
>> +       extra = DECT_BEARER_QCTRL_FRAMENUM - framenum;
>> +       dbc->qctrl = DECT_BEARER_QCTRL_WAIT;
>> +       dect_timer_add(cell, &dbc->qctrl_timer, DECT_TIMER_TX,
>> +                      DECT_BEARER_QCTRL_PERIOD + extra, 
>> bearer->chd.slot);
>> +
>> +       dect_bearer_enable(bearer);
>> +}
>> +
>> +static const struct dect_bearer_ops dect_dbc_ops = {
>> +       .state          = DECT_DUMMY_BEARER,
>> +       .enable         = dect_dbc_enable,
>> +       .report_rssi    = dect_dbc_report_rssi,
>> +       .rcv            = dect_dbc_rcv,
>> +};
>> +
>> +static void dect_dbc_release(struct dect_dbc *dbc)
>> +{
>> +       struct dect_cell *cell = dbc->cell;
>> +
>> +       dect_channel_release(cell, dbc->bearer.trx, &dbc->bearer.chd);
>> +       dect_bearer_release(cell, &dbc->bearer);
>> +
>> +       dect_timer_del(&dbc->qctrl_timer);
>> +       dect_bc_release(&dbc->bc);
>> +       list_del(&dbc->list);
>> +       kfree(dbc);
>> +}
>> +
>> +/**
>> + * dect_dbc_init - initialise dummy bearer control
>> + *
>> + * @cell:      DECT cell
>> + * @chd:       channel description (PP only)
>> + */
>> +static struct dect_dbc *dect_dbc_init(struct dect_cell *cell,
>> +                                     const struct dect_channel_desc 
>> *chd)
>> +{
>> +       struct dect_channel_desc tchd;
>> +       struct dect_transceiver *trx;
>> +       enum dect_bearer_modes mode;
>> +       struct dect_dbc *dbc;
>> +       u8 uninitialized_var(rssi);
>> +
>> +       /* Transmission is always in direction FP -> PP */
>> +       if (cell->mode == DECT_MODE_FP) {
>> +               tchd.pkt   = DECT_PACKET_P00;
>> +               tchd.b_fmt = DECT_B_NONE;
>> +               if (dect_select_channel(cell, &trx, &tchd, &rssi, 
>> false) < 0)
>> +                       goto err1;
>> +               chd = &tchd;
>> +
>> +               mode = DECT_BEARER_TX;
>> +       } else {
>> +               trx = dect_select_transceiver(cell, chd);
>> +               if (trx == NULL)
>> +                       goto err1;
>> +               mode = DECT_BEARER_RX;
>> +       }
>> +
>> +       dect_channel_reserve(cell, trx, chd);
>> +
>> +       dbc = kzalloc(sizeof(*dbc), GFP_ATOMIC);
>> +       if (dbc == NULL)
>> +               goto err2;
>> +       dbc->cell = cell;
>> +       dect_timer_setup(&dbc->qctrl_timer, 
>> dect_dbc_quality_control_timer, dbc);
>> +       dect_bc_init(cell, &dbc->bc);
>> +
>> +       dect_bearer_init(cell, &dbc->bearer, &dect_dbc_ops, trx, chd, 
>> mode, dbc);
>> +
>> +       if (cell->mode == DECT_MODE_FP)
>> +               dect_tx_bearer_schedule(cell, &dbc->bearer, rssi);
>> +       else {
>> +               dect_bearer_enable(&dbc->bearer);
>> +
>> +               cell->a_rcv_stamp  = jiffies;
>> +               cell->nt_rcv_stamp = jiffies;
>> +       }
>> +
>> +       list_add_tail(&dbc->list, &cell->dbcs);
>> +       return dbc;
>> +
>> +err2:
>> +       dect_channel_release(cell, trx, chd);
>> +err1:
>> +       return NULL;
>> +}
>> +
>> +/*
>> + * Monitor Bearer
>> + */
>> +
>> +static void dect_dmb_release(struct dect_cell *cell, struct dect_dmb 
>> *dmb)
>> +{
>> +       cell->tbc_last_chd = dmb->rxb2.chd;
>> +
>> +       dect_timer_del(&dmb->wd_timer);
>> +
>> +       dect_transceiver_release(&cell->trg, dmb->rxb1.trx, 
>> &dmb->rxb1.chd);
>> +       dect_bearer_release(dmb->cell, &dmb->rxb1);
>> +
>> +       dect_transceiver_release(&cell->trg, dmb->rxb2.trx, 
>> &dmb->rxb2.chd);
>> +       dect_bearer_release(dmb->cell, &dmb->rxb2);
>> +
>> +       dect_bc_release(&dmb->bc);
>> +       list_del(&dmb->list);
>> +       kfree(dmb);
>> +}
>> +
>> +static void dect_dmb_watchdog_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       dect_dmb_release(cell, data);
>> +}
>> +
>> +static void dect_dmb_watchdog_reschedule(struct dect_cell *cell,
>> +                                        struct dect_dmb *dmb)
>> +{
>> +       dect_bearer_timer_add(cell, &dmb->rxb1, &dmb->wd_timer,
>> +                             DECT_TBC_RFPI_TIMEOUT);
>> +}
>> +
>> +static void dect_dmb_rcv(struct dect_cell *cell, struct dect_bearer 
>> *bearer,
>> +                        struct sk_buff *skb)
>> +{
>> +       struct dect_dmb *dmb = bearer->dmb;
>> +       struct dect_tail_msg tm;
>> +
>> +       dect_raw_rcv(skb);
>> +
>> +       if (dect_parse_tail_msg(&tm, skb) < 0)
>> +               goto err;
>> +
>> +       /* Reschedule watchdog on successful RFPI handshake. */
>> +       if (tm.type == DECT_TM_TYPE_ID && !dect_rfpi_cmp(&tm.idi, 
>> &cell->idi))
>> +               dect_dmb_watchdog_reschedule(cell, dmb);
>> +
>> +       dect_bc_rcv(cell, &dmb->bc, skb, &tm);
>> +
>> +       switch (tm.type) {
>> +       case DECT_TM_TYPE_BCCTRL:
>> +       case DECT_TM_TYPE_ACCTRL:
>> +               if (tm.cctl.cmd == DECT_CCTRL_RELEASE)
>> +                       return dect_dmb_release(cell, dmb);
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static const struct dect_bearer_ops dect_dmb_ops = {
>> +       .state          = DECT_MONITOR_BEARER,
>> +       .rcv            = dect_dmb_rcv,
>> +};
>> +
>> +static struct dect_dmb *dect_dmb_init(struct dect_cell *cell,
>> +                                     struct dect_transceiver *trx1,
>> +                                     struct dect_transceiver *trx2,
>> +                                     const struct dect_channel_desc 
>> *chd1,
>> +                                     const struct dect_channel_desc 
>> *chd2)
>> +{
>> +       struct dect_dmb *dmb;
>> +
>> +       dmb = kzalloc(sizeof(*dmb), GFP_ATOMIC);
>> +       if (dmb == NULL)
>> +               return NULL;
>> +       dmb->cell = cell;
>> +
>> +       dect_timer_setup(&dmb->wd_timer, dect_dmb_watchdog_timer, 
>> dmb);
>> +       dect_bearer_init(cell, &dmb->rxb1, &dect_dmb_ops,
>> +                        trx1, chd1, DECT_BEARER_RX, dmb);
>> +       dect_bearer_init(cell, &dmb->rxb2, &dect_dmb_ops,
>> +                        trx2, chd2, DECT_BEARER_RX, dmb);
>> +       dect_bc_init(cell, &dmb->bc);
>> +
>> +       list_add_tail(&dmb->list, &cell->dmbs);
>> +       return dmb;
>> +}
>> +
>> +static void dect_dmb_rcv_request(struct dect_cell *cell,
>> +                                const struct dect_transceiver_slot 
>> *ts,
>> +                                const struct dect_tail_msg *tm,
>> +                                struct sk_buff *skb)
>> +{
>> +       struct dect_transceiver *trx1, *trx2;
>> +       struct dect_channel_desc chd1, chd2;
>> +       struct dect_dmb *dmb;
>> +
>> +       if (tm->cctl.fmid != cell->fmid)
>> +               goto err1;
>> +       dect_raw_rcv(skb);
>> +
>> +       switch (tm->cctl.cmd) {
>> +       case DECT_CCTRL_ACCESS_REQ:
>> +       case DECT_CCTRL_BEARER_HANDOVER_REQ:
>> +       case DECT_CCTRL_CONNECTION_HANDOVER_REQ:
>> +               break;
>> +       default:
>> +               rx_debug(cell, "unhandled DMB request: %llu\n",
>> +                        (unsigned long long)tm->cctl.cmd);
>> +               goto err1;
>> +       }
>> +
>> +       rx_debug(cell, "DMB: RCV ACCESS_REQUEST\n");
>> +
>> +       /* Select transceivers for RX/TX and reserve resources */
>> +       memcpy(&chd1, &ts->chd, sizeof(chd1));
>> +       chd1.pkt   = DECT_PACKET_P32;
>> +       chd1.b_fmt = DECT_B_UNPROTECTED;
>> +       trx1 = dect_select_transceiver(cell, &chd1);
>> +       if (trx1 == NULL)
>> +               goto err1;
>> +       dect_transceiver_reserve(&cell->trg, trx1, &chd1);
>> +
>> +       dect_tdd_channel_desc(&chd2, &chd1);
>> +       trx2 = dect_select_transceiver(cell, &chd2);
>> +       if (trx2 == NULL)
>> +               goto err2;
>> +       dect_transceiver_reserve(&cell->trg, trx2, &chd2);
>> +
>> +       dmb = dect_dmb_init(cell, trx1, trx2, &chd1, &chd2);
>> +       if (dmb == NULL)
>> +               goto err3;
>> +
>> +       dect_bearer_enable(&dmb->rxb1);
>> +       dect_bearer_enable(&dmb->rxb2);
>> +
>> +       dect_bearer_timer_add(cell, &dmb->rxb1, &dmb->wd_timer,
>> +                             DECT_TBC_RFPI_TIMEOUT);
>> +
>> +       kfree_skb(skb);
>> +       return;
>> +
>> +err3:
>> +       dect_transceiver_release(&cell->trg, trx2, &chd2);
>> +err2:
>> +       dect_transceiver_release(&cell->trg, trx1, &chd1);
>> +err1:
>> +       kfree_skb(skb);
>> +}
>> +
>> +/*
>> + * Idle Receiver Control
>> + */
>> +
>> +static void dect_initiate_scan(struct dect_transceiver *trx,
>> +                              const struct dect_ari *ari,
>> +                              const struct dect_ari *ari_mask,
>> +                              void (*notify)(struct dect_cell *,
>> +                                             struct dect_transceiver 
>> *,
>> +                                             enum dect_scan_status))
>> +{
>> +       struct dect_irc *irc = trx->irc;
>> +
>> +       if (ari != NULL) {
>> +               memcpy(&irc->ari, ari, sizeof(irc->ari));
>> +               if (ari_mask != NULL)
>> +                       memcpy(&irc->ari_mask, ari_mask, 
>> sizeof(irc->ari_mask));
>> +               else
>> +                       memset(&irc->ari_mask, 0xff, 
>> sizeof(irc->ari_mask));
>> +       }
>> +
>> +       memset(&irc->si, 0, sizeof(irc->si));
>> +       irc->notify = notify;
>> +
>> +       dect_transceiver_enable(trx);
>> +       dect_set_channel_mode(trx, &trx->slots[DECT_SCAN_SLOT].chd, 
>> DECT_SLOT_SCANNING);
>> +}
>> +
>> +static void dect_restart_scan(struct dect_cell *cell,
>> +                             struct dect_transceiver *trx)
>> +{
>> +       struct dect_irc *irc = trx->irc;
>> +
>> +       memset(&irc->si, 0, sizeof(irc->si));
>> +       dect_transceiver_unlock(trx);
>> +       dect_set_channel_mode(trx, &trx->slots[DECT_SCAN_SLOT].chd, 
>> DECT_SLOT_SCANNING);
>> +}
>> +
>> +/* This function controls the transceiver while scanning. It collects 
>> the
>> + * information requested in struct dect_scan_ctrl and invokes the 
>> completion
>> + * handler once all information is available.
>> + */
>> +void dect_mac_irc_rcv(struct dect_transceiver *trx, struct sk_buff 
>> *skb)
>> +{
>> +       struct dect_cell *cell = trx->cell;
>> +       struct dect_irc *irc = trx->irc;
>> +       struct dect_tail_msg tm;
>> +
>> +       if (dect_parse_tail_msg(&tm, skb) < 0)
>> +               goto err;
>> +
>> +       switch (trx->state) {
>> +       case DECT_TRANSCEIVER_UNLOCKED:
>> +               if (tm.type != DECT_TM_TYPE_ID)
>> +                       break;
>> +               if (dect_ari_masked_cmp(&tm.idi.pari, &irc->ari, 
>> &irc->ari_mask))
>> +                       break;
>> +               memcpy(&irc->idi, &tm.idi, sizeof(irc->idi));
>> +
>> +               irc->timeout = 16 * DECT_FRAMES_PER_MULTIFRAME;
>> +               irc->rssi    = dect_average_rssi(0, 
>> DECT_TRX_CB(skb)->rssi);
>> +               dect_transceiver_confirm(trx);
>> +               break;
>> +       case DECT_TRANSCEIVER_LOCK_PENDING:
>> +               irc->rssi = dect_average_rssi(irc->rssi, 
>> DECT_TRX_CB(skb)->rssi);
>> +               if (dect_parse_tail(skb) == DECT_TI_QT) {
>> +                       dect_bc_update_si(&irc->si, &tm);
>> +                       if (dect_bc_si_cycle_complete(&irc->idi, 
>> &irc->si) &&
>> +                           tm.type == DECT_TM_TYPE_MFN)
>> +                               irc->notify(cell, trx, 
>> DECT_SCAN_COMPLETE);
>> +               }
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +err:
>> +       kfree_skb(skb);
>> +}
>> +
>> +void dect_mac_irc_tick(struct dect_transceiver *trx)
>> +{
>> +       struct dect_cell *cell = trx->cell;
>> +       struct dect_irc *irc = trx->irc;
>> +
>> +       switch (trx->state) {
>> +       case DECT_TRANSCEIVER_UNLOCKED:
>> +               /* maintain scan until clock is running */
>> +               irc->rx_scn = dect_next_carrier(0x3ff, irc->rx_scn);
>> +               dect_set_carrier(trx, DECT_SCAN_SLOT, irc->rx_scn);
>> +               break;
>> +       case DECT_TRANSCEIVER_LOCK_PENDING:
>> +               irc->si.ssi.pscn = dect_next_carrier(0x3ff, 
>> irc->si.ssi.pscn);
>> +               if (--irc->timeout == 0)
>> +                       irc->notify(cell, trx, DECT_SCAN_TIMEOUT);
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +}
>> +
>> +static void dect_scan_bearer_rcv(struct dect_cell *cell,
>> +                                struct dect_bearer *bearer,
>> +                                struct sk_buff *skb)
>> +{
>> +       struct dect_transceiver *trx = bearer->trx;
>> +       struct dect_transceiver_slot *ts;
>> +       enum dect_tail_identifications ti;
>> +       struct dect_tail_msg tm;
>> +       bool monitor = false;
>> +
>> +       ti = dect_parse_tail(skb);
>> +       /* A PP uses a special encoding for the first transmission */
>> +       if (cell->mode == DECT_MODE_FP && ti != DECT_TI_MT_PKT_0)
>> +               goto out;
>> +       if (cell->mode == DECT_MODE_PP) {
>> +               if (cell->flags & DECT_CELL_MONITOR && ti == 
>> DECT_TI_MT_PKT_0)
>> +                       monitor = true;
>> +               else if (ti != DECT_TI_MT)
>> +                       goto out;
>> +       }
>> +
>> +       if (dect_parse_tail_msg(&tm, skb) < 0)
>> +               goto out;
>> +
>> +       ts = &trx->slots[DECT_TRX_CB(skb)->slot];
>> +       switch (tm.type) {
>> +       case DECT_TM_TYPE_BCCTRL:
>> +       case DECT_TM_TYPE_ACCTRL:
>> +               if (monitor)
>> +                       return dect_dmb_rcv_request(cell, ts, &tm, 
>> skb);
>> +               else
>> +                       return dect_tbc_rcv_request(cell, ts, &tm, 
>> skb);
>> +       default:
>> +               break;
>> +       }
>> +out:
>> +       kfree_skb(skb);
>> +}
>> +
>> +static void dect_scan_bearer_report_rssi(struct dect_cell *cell,
>> +                                        struct dect_bearer *bearer,
>> +                                        u8 slot, u8 rssi)
>> +{
>> +       if (cell->chl == NULL)
>> +               return;
>> +       dect_chl_update(cell, cell->chl, 
>> &bearer->trx->slots[slot].chd, rssi);
>> +}
>> +
>> +static const struct dect_bearer_ops dect_scan_ops = {
>> +       .report_rssi    = dect_scan_bearer_report_rssi,
>> +       .rcv            = dect_scan_bearer_rcv,
>> +};
>> +
>> +static void dect_scan_channel_desc(struct dect_channel_desc *chd)
>> +{
>> +       memset(chd, 0, sizeof(*chd));
>> +       chd->pkt   = DECT_PACKET_P32;
>> +       chd->b_fmt = DECT_B_UNPROTECTED;
>> +}
>> +
>> +static void dect_chl_scan_channel_desc(struct dect_channel_desc *chd,
>> +                                      const struct dect_channel_list 
>> *chl)
>> +{
>> +       memset(chd, 0, sizeof(*chd));
>> +       chd->pkt = chl->pkt;
>> +       if (chl->pkt == DECT_PACKET_P00)
>> +               chd->b_fmt = DECT_B_NONE;
>> +       else
>> +               chd->b_fmt = DECT_B_UNPROTECTED;
>> +}
>> +
>> +static void dect_scan_bearer_enable(struct dect_transceiver *trx,
>> +                                   const struct dect_channel_desc 
>> *chd)
>> +{
>> +       trx->slots[chd->slot].bearer = &trx->irc->scan_bearer;
>> +       dect_set_channel_mode(trx, chd, DECT_SLOT_SCANNING);
>> +}
>> +
>> +static void dect_scan_bearer_disable(struct dect_transceiver *trx,
>> +                                    const struct dect_channel_desc 
>> *chd)
>> +{
>> +       dect_set_channel_mode(trx, chd, DECT_SLOT_IDLE);
>> +       trx->slots[chd->slot].bearer = NULL;
>> +}
>> +
>> +static void dect_irc_tx_frame_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       struct dect_irc *irc = data;
>> +       struct dect_transceiver *trx = irc->trx;
>> +       struct dect_channel_desc chd;
>> +       u8 end;
>> +
>> +       irc->tx_scn = dect_next_carrier(cell->si.ssi.rfcars, 
>> irc->tx_scn);
>> +
>> +       /* Begin a pending channel list update:
>> +        *
>> +        * The IRC of the first transceiver that reaches a new frame 
>> queues the
>> +        * channel list. All IRCs then switch the idle normal transmit 
>> slots
>> +        * to scanning mode and switch all scanning slots to the lists 
>> physical
>> +        * channel type. The actual update will begin once the receive 
>> side
>> +        * reaches the same frame.
>> +        */
>> +       if (cell->chl == NULL && cell->chl_next == NULL)
>> +               cell->chl_next = dect_chl_get_pending(cell);
>> +
>> +       if (cell->chl_next != NULL) {
>> +               dect_chl_scan_channel_desc(&chd, cell->chl_next);
>> +               dect_foreach_receive_slot(chd.slot, end, cell) {
>> +                       if (trx->slots[chd.slot].state != 
>> DECT_SLOT_IDLE &&
>> +                           trx->slots[chd.slot].state != 
>> DECT_SLOT_SCANNING)
>> +                               continue;
>> +                       if (!dect_transceiver_channel_available(trx, 
>> &chd))
>> +                               continue;
>> +
>> +                       dect_scan_bearer_enable(trx, &chd);
>> +               }
>> +               dect_foreach_transmit_slot(chd.slot, end, cell) {
>> +                       if (trx->slots[chd.slot].state != 
>> DECT_SLOT_IDLE)
>> +                               continue;
>> +                       if (!dect_transceiver_channel_available(trx, 
>> &chd))
>> +                               continue;
>> +                       dect_scan_bearer_enable(trx, &chd);
>> +               }
>> +       } else if (cell->chl == NULL) {
>> +               /* Switch back primary, secondary and tertiary scan to 
>> proper
>> +                * packet format and disable scan on remaining 
>> transceivers
>> +                * after the channel list update is complete.
>> +                */
>> +               dect_scan_channel_desc(&chd);
>> +               dect_foreach_receive_slot(chd.slot, end, cell) {
>> +                       if (trx->slots[chd.slot].state != 
>> DECT_SLOT_SCANNING)
>> +                               continue;
>> +
>> +                       if (trx->index < 3)
>> +                               dect_scan_bearer_enable(trx, &chd);
>> +                       else
>> +                               dect_scan_bearer_disable(trx, &chd);
>> +               }
>> +
>> +               /* In monitor mode, transmit slots keep scanning for 
>> FP setup
>> +                * attempts.
>> +                */
>> +               if (!(cell->flags & DECT_CELL_MONITOR)) {
>> +                       dect_foreach_transmit_slot(chd.slot, end, 
>> cell) {
>> +                               if (trx->slots[chd.slot].state != 
>> DECT_SLOT_SCANNING)
>> +                                       continue;
>> +                               dect_scan_bearer_disable(trx, &chd);
>> +                       }
>> +               }
>> +       }
>> +
>> +       dect_timer_add(cell, &irc->tx_frame_timer, DECT_TIMER_TX, 1, 
>> 0);
>> +}
>> +
>> +static void dect_irc_rx_frame_timer(struct dect_cell *cell, void 
>> *data)
>> +{
>> +       struct dect_irc *irc = data;
>> +
>> +       /* Update the list status at the end of a frame in case of an
>> +        * active update or activate an update before a new frame 
>> begins.
>> +        */
>> +       if (cell->chl != NULL)
>> +               dect_chl_update_carrier(cell, irc->rx_scn);
>> +       else if (cell->chl_next != NULL) {
>> +               cell->chl = cell->chl_next;
>> +               cell->chl_next = NULL;
>> +               chl_debug(cell, cell->chl, "begin update\n");
>> +       }
>> +
>> +       irc->rx_scn = dect_next_carrier(cell->si.ssi.rfcars, 
>> irc->rx_scn);
>> +       dect_timer_add(cell, &irc->rx_frame_timer, DECT_TIMER_RX, 1, 
>> 23);
>> +}
>> +
>> +/* Primary, secondary and tertiary scan: the secondary scan lags 
>> behind the
>> + * primary scan by 6 TDMA frames, the tertiary scan by 3 TDMA frames.
>> + *
>> + * Additional transceivers don't scan for setup attempts, however 
>> they each
>> + * cover a different carrier in order to speed up channel list 
>> construction.
>> + */
>> +static const u8 scn_off_tbl[10] = {
>> +       [0]     = 0,
>> +       [1]     = 6,
>> +       [2]     = 3,
>> +       [3]     = 8,
>> +       [4]     = 1,
>> +       [5]     = 4,
>> +       [6]     = 9,
>> +       [7]     = 2,
>> +       [8]     = 5,
>> +       [9]     = 7,
>> +};
>> +
>> +static void dect_irc_enable(struct dect_cell *cell, struct dect_irc 
>> *irc)
>> +{
>> +       struct dect_transceiver *trx = irc->trx;
>> +       struct dect_channel_desc chd;
>> +       u8 end, scn_off, scn;
>> +
>> +       if (trx->index >= 10)
>> +               return;
>> +
>> +       scn_off = scn_off_tbl[trx->index];
>> +       scn = dect_carrier_sub(cell->si.ssi.rfcars, cell->si.ssi.pscn, 
>> scn_off);
>> +       irc->rx_scn = scn;
>> +       irc->tx_scn = scn;
>> +
>> +       if (trx->index < 3) {
>> +               /* Set all idle slots to scanning */
>> +               dect_scan_channel_desc(&chd);
>> +               dect_foreach_receive_slot(chd.slot, end, cell) {
>> +                       if (trx->slots[chd.slot].state != 
>> DECT_SLOT_IDLE)
>> +                               continue;
>> +                       if (!dect_transceiver_channel_available(trx, 
>> &chd))
>> +                               continue;
>> +                       dect_scan_bearer_enable(trx, &chd);
>> +               }
>> +
>> +               if (cell->flags & DECT_CELL_MONITOR) {
>> +                       dect_foreach_transmit_slot(chd.slot, end, 
>> cell) {
>> +                               if 
>> (!dect_transceiver_channel_available(trx, &chd))
>> +                                       continue;
>> +                               dect_scan_bearer_enable(trx, &chd);
>> +                       }
>> +               }
>> +       }
>> +
>> +       /* Start frame timers */
>> +       dect_timer_add(cell, &irc->tx_frame_timer, DECT_TIMER_TX, 1, 
>> 0);
>> +       dect_timer_add(cell, &irc->rx_frame_timer, DECT_TIMER_RX, 0, 
>> 23);
>> +}
>> +
>> +static void dect_irc_disable(struct dect_cell *cell, struct dect_irc 
>> *irc)
>> +{
>> +       struct dect_transceiver *trx = irc->trx;
>> +       u8 slot;
>> +
>> +       dect_timer_del(&irc->rx_frame_timer);
>> +       dect_timer_del(&irc->tx_frame_timer);
>> +
>> +       dect_foreach_slot(slot) {
>> +               if (trx->slots[slot].state != DECT_SLOT_SCANNING)
>> +                       continue;
>> +               dect_scan_bearer_disable(trx, &trx->slots[slot].chd);
>> +       }
>> +}
>> +
>> +static struct dect_irc *dect_irc_init(struct dect_cell *cell,
>> +                                     struct dect_transceiver *trx)
>> +{
>> +       struct dect_irc *irc;
>> +
>> +       irc = kzalloc(sizeof(*irc), GFP_KERNEL);
>> +       if (irc == NULL)
>> +               return NULL;
>> +
>> +       irc->cell = cell;
>> +       dect_timer_setup(&irc->rx_frame_timer, 
>> dect_irc_rx_frame_timer, irc);
>> +       dect_timer_setup(&irc->tx_frame_timer, 
>> dect_irc_tx_frame_timer, irc);
>> +       irc->scan_bearer.ops   = &dect_scan_ops;
>> +       irc->scan_bearer.irc   = irc;
>> +       irc->scan_bearer.trx   = trx;
>> +       irc->scan_bearer.mode  = DECT_BEARER_RX;
>> +       irc->scan_bearer.state = DECT_BEARER_ENABLED;
>> +       irc->trx = trx;
>> +       trx->irc = irc;
>> +       return irc;
>> +}
>> +
>> +static void dect_lock_fp(struct dect_cell *cell, struct 
>> dect_transceiver *trx,
>> +                        enum dect_scan_status status)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +       struct dect_irc *irc = trx->irc;
>> +       struct dect_si *si = &irc->si;
>> +       struct dect_channel_desc chd;
>> +       struct dect_dbc *dbc;
>> +
>> +       switch (status) {
>> +       case DECT_SCAN_FAIL:
>> +       case DECT_SCAN_TIMEOUT:
>> +               return dect_restart_scan(cell, trx);
>> +       case DECT_SCAN_COMPLETE:
>> +               break;
>> +       }
>> +
>> +       dect_set_channel_mode(trx, &trx->slots[DECT_SCAN_SLOT].chd, 
>> DECT_SLOT_IDLE);
>> +
>> +       chd.slot    = si->ssi.sn + (si->ssi.nr ? DECT_HALF_FRAME_SIZE 
>> : 0);
>> +       chd.carrier = si->ssi.cn;
>> +       chd.pkt     = DECT_PACKET_P00;
>> +       chd.b_fmt   = DECT_B_NONE;
>> +
>> +       if (!dect_transceiver_channel_available(trx, &chd))
>> +               return dect_restart_scan(cell, trx);
>> +
>> +       if (cell->mode != DECT_MODE_FP) {
>> +               memcpy(&cell->idi, &irc->idi, sizeof(cell->idi));
>> +               cell->fmid = dect_build_fmid(&cell->idi);
>> +               memcpy(&cell->si, si, sizeof(cell->si));
>> +
>> +               /* Q-channel information is broadcast in frame 8 */
>> +               dect_timer_synchronize_framenum(cell, 
>> DECT_Q_CHANNEL_FRAME);
>> +               dect_timer_synchronize_mfn(cell, si->mfn.num);
>> +
>> +               /* Lock framing based on slot position and create DBC 
>> */
>> +               dect_transceiver_lock(trx, chd.slot);
>> +               dect_dbc_init(cell, &chd);
>> +
>> +               clh->ops->mac_info_ind(clh, &cell->idi, &cell->si);
>> +       } else {
>> +               /* secondary transceiver */
>> +               dbc = dect_dbc_get(cell);
>> +               if (!(cell->flags & DECT_CELL_SLAVE) &&
>> +                   (dbc == NULL ||
>> +                    dbc->bearer.chd.slot    != chd.slot ||
>> +                    dbc->bearer.chd.carrier != chd.carrier))
>> +                       return dect_restart_scan(cell, trx);
>> +
>> +               dect_transceiver_lock(trx, chd.slot);
>> +
>> +               /* Lock to the primary dummy bearer to keep the radio 
>> synchronized */
>> +               /* FIXME: do this cleanly */
>> +               dect_set_channel_mode(trx, &chd, DECT_SLOT_RX);
>> +               dect_set_flags(trx, chd.slot, DECT_SLOT_SYNC);
>> +               dect_set_carrier(trx, chd.slot, chd.carrier);
>> +       }
>> +
>> +       /* Enable IRC */
>> +       dect_irc_enable(cell, irc);
>> +}
>> +
>> +static void dect_attempt_lock(struct dect_cell *cell,
>> +                             struct dect_transceiver *trx)
>> +{
>> +       dect_initiate_scan(trx, &cell->idi.pari, NULL, dect_lock_fp);
>> +}
>> +
>> +/*
>> + * Transmission: A- and B-Field MUXes
>> + */
>> +
>> +static struct sk_buff *dect_u_mux(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer)
>> +{
>> +       struct sk_buff *skb = NULL;
>> +       struct dect_tbc *tbc;
>> +       u8 b_field_size;
>> +
>> +       if (bearer->ops->state == DECT_TRAFFIC_BEARER) {
>> +               tbc = bearer->tbc;
>> +               skb = tbc->b_tx_skb;
>> +               tbc->b_tx_skb = NULL;
>> +       }
>> +
>> +       if (skb == NULL) {
>> +               b_field_size = dect_b_field_size(&bearer->chd);
>> +               skb = alloc_skb(b_field_size, GFP_ATOMIC);
>> +               if (skb == NULL)
>> +                       return NULL;
>> +               skb_put(skb, b_field_size);
>> +               memset(skb->data, 0xff, b_field_size);
>> +               DECT_B_CB(skb)->id = DECT_BI_UTYPE_0;
>> +       }
>> +       return skb;
>> +}
>> +
>> +static struct sk_buff *dect_eu_mux(struct dect_cell *cell,
>> +                                  struct dect_bearer *bearer)
>> +{
>> +       return dect_u_mux(cell, bearer);
>> +}
>> +
>> +static struct sk_buff *dect_b_map(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer)
>> +{
>> +       return dect_eu_mux(cell, bearer);
>> +}
>> +
>> +#define tmux_debug(cell, fmt, args...) \
>> +       tx_debug(cell, "%s T-MUX: " fmt, \
>> +                cell->mode == DECT_MODE_FP ? "FT" : "PT", ## args)
>> +
>> +/**
>> + * dect_pt_t_mux - DECT T-MUX for PT transmissions
>> + *
>> + * @cell:      DECT cell
>> + * @bearer:    MAC bearer
>> + *
>> + * The PT T-MUX sequence is used by PTs for all traffic bearers in 
>> connection
>> + * oriented services and is defined as:
>> + *
>> + * Even frames:        M_T, C_T, N_T
>> + * Uneven frames:      N_T
>> + *
>> + * Exception: M_T tails containing "bearer request" or "bearer 
>> release"
>> + * messages may be placed in any frame.
>> + */
>> +static struct sk_buff *dect_pt_t_mux(struct dect_cell *cell,
>> +                                    struct dect_bearer *bearer)
>> +{
>> +       struct dect_tbc *tbc = NULL;
>> +       struct sk_buff *skb;
>> +
>> +       switch (bearer->ops->state) {
>> +       case DECT_DUMMY_BEARER:
>> +       case DECT_CL_BEARER:
>> +       case DECT_MONITOR_BEARER:
>> +               WARN_ON(0);
>> +               break;
>> +       case DECT_TRAFFIC_BEARER:
>> +               tbc = bearer->tbc;
>> +               tbc->cs_tx_ok = false;
>> +               break;
>> +       }
>> +
>> +       if ((dect_framenum(cell, DECT_TIMER_TX) & 0x1) == 0) {
>> +               skb = skb_dequeue(&bearer->m_tx_queue);
>> +               if (skb != NULL) {
>> +                       tmux_debug(cell, "M-channel\n");
>> +                       return skb;
>> +               }
>> +               if (tbc != NULL && tbc->cs_tx_skb != NULL) {
>> +                       skb = tbc->cs_tx_skb;
>> +                       tbc->cs_tx_skb = NULL;
>> +                       tbc->cs_tx_ok = true;
>> +                       tmux_debug(cell, "C-channel\n");
>> +                       return skb;
>> +               }
>> +       } else {
>> +               skb = skb_peek(&bearer->m_tx_queue);
>> +               if (skb != NULL && skb->priority == 
>> DECT_MT_HIGH_PRIORITY) {
>> +                       tmux_debug(cell, "M-channel (high 
>> priority)\n");
>> +                       skb_unlink(skb, &bearer->m_tx_queue);
>> +                       return skb;
>> +               }
>> +       }
>> +
>> +       tmux_debug(cell, "N-channel\n");
>> +       return dect_bc_dequeue(cell, bearer, &tbc->bc, DECT_MC_N);
>> +}
>> +
>> +/**
>> + * dect_rfp_t_mux - DECT T-MUX for RFP transmissions
>> + *
>> + * @cell:      DECT cell
>> + * @bearer:    MAC bearer
>> + *
>> + * The RFP T-MUX sequence is used for all RFP transmissions and is 
>> defined as:
>> + *
>> + * Frame 8:            Q_T
>> + * Frame 14:           N_T
>> + * Other even frames:  P_T, N_T
>> + * Uneven frames:      M_T, C_T, N_T
>> + *
>> + * Exception: M_T tails sent in response to "bearer request" messages 
>> or during
>> + * bearer release may be placed in any frame.
>> + */
>> +static struct sk_buff *dect_rfp_t_mux(struct dect_cell *cell,
>> +                                     struct dect_bearer *bearer)
>> +{
>> +       u8 framenum = dect_framenum(cell, DECT_TIMER_TX);
>> +       struct dect_tbc *tbc = NULL;
>> +       struct dect_bc *bc = NULL;
>> +       struct sk_buff *skb;
>> +
>> +       switch (bearer->ops->state) {
>> +       case DECT_DUMMY_BEARER:
>> +               bc = &bearer->dbc->bc;
>> +               break;
>> +       case DECT_TRAFFIC_BEARER:
>> +               tbc = bearer->tbc;
>> +               tbc->cs_tx_ok = false;
>> +               bc = &bearer->tbc->bc;
>> +               break;
>> +       case DECT_CL_BEARER:
>> +       case DECT_MONITOR_BEARER:
>> +               break;
>> +       }
>> +
>> +       if ((framenum & 0x1) == 0) {
>> +               skb = skb_peek(&bearer->m_tx_queue);
>> +               if (skb != NULL && skb->priority == 
>> DECT_MT_HIGH_PRIORITY) {
>> +                       tmux_debug(cell, "M-channel (high 
>> priority)\n");
>> +                       skb_unlink(skb, &bearer->m_tx_queue);
>> +                       return skb;
>> +               }
>> +
>> +               if (framenum == 8) {
>> +                       tmux_debug(cell, "Q-channel\n");
>> +                       return dect_bc_dequeue(cell, bearer, bc, 
>> DECT_MC_Q);
>> +               }
>> +               if (framenum == 14) {
>> +                       tmux_debug(cell, "N-channel\n");
>> +                       return dect_bc_dequeue(cell, bearer, bc, 
>> DECT_MC_N);
>> +               }
>> +
>> +               skb = dect_bc_dequeue(cell, bearer, bc, DECT_MC_P);
>> +               if (skb != NULL) {
>> +                       tmux_debug(cell, "P-channel\n");
>> +                       return skb;
>> +               }
>> +       } else {
>> +               skb = skb_dequeue(&bearer->m_tx_queue);
>> +               if (skb != NULL) {
>> +                       tmux_debug(cell, "M-channel\n");
>> +                       return skb;
>> +               }
>> +               if (tbc != NULL && tbc->cs_tx_skb != NULL) {
>> +                       skb = tbc->cs_tx_skb;
>> +                       tbc->cs_tx_skb = NULL;
>> +                       tbc->cs_tx_ok = true;
>> +                       tmux_debug(cell, "C-channel\n");
>> +                       return skb;
>> +               }
>> +       }
>> +
>> +       tmux_debug(cell, "N-channel\n");
>> +       return dect_bc_dequeue(cell, bearer, bc, DECT_MC_N);
>> +}
>> +
>> +/**
>> + * dect_a_map - DECT A-Field mapping
>> + *
>> + * @cell:      DECT cell
>> + * @bearer:    MAC bearer
>> + *
>> + * Combine the H-, T- and RA-Fields into the A-Field.
>> + */
>> +static struct sk_buff *dect_a_map(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       switch (cell->mode) {
>> +       case DECT_MODE_PP:
>> +               skb = dect_pt_t_mux(cell, bearer);
>> +               break;
>> +       case DECT_MODE_FP:
>> +               skb = dect_rfp_t_mux(cell, bearer);
>> +               break;
>> +       default:
>> +               skb = NULL;
>> +               break;
>> +       }
>> +
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       /* Append empty RA-Field */
>> +       memset(skb_put(skb, DECT_RA_FIELD_SIZE), 0, 
>> DECT_RA_FIELD_SIZE);
>> +
>> +       /* Prepend Header field */
>> +       skb_push(skb, DECT_HDR_FIELD_SIZE);
>> +       skb->data[DECT_HDR_FIELD_OFF] = DECT_A_CB(skb)->id;
>> +       skb->data[DECT_HDR_FIELD_OFF] |= bearer->q;
>> +       bearer->q = 0;
>> +       return skb;
>> +}
>> +
>> +static struct sk_buff *dect_raw_tx_peek(struct dect_cell *cell)
>> +{
>> +       struct dect_timer_base *base = 
>> &cell->timer_base[DECT_TIMER_TX];
>> +       struct dect_skb_trx_cb *cb;
>> +       struct sk_buff *skb;
>> +
>> +       skb = skb_peek(&cell->raw_tx_queue);
>> +       if (skb == NULL)
>> +               return NULL;
>> +       cb = DECT_TRX_CB(skb);
>> +
>> +       if ((!cb->mfn || cb->mfn == base->mfn) &&
>> +           (!cb->frame || cb->frame == base->framenum) &&
>> +           cb->slot == dect_slotnum(cell, DECT_TIMER_TX))
>> +               return skb;
>> +
>> +       return NULL;
>> +}
>> +
>> +static void dect_raw_tx_configure(struct dect_cell *cell,
>> +                                 struct dect_transceiver *trx,
>> +                                 struct dect_transceiver_slot *ts)
>> +{
>> +       if (dect_raw_tx_peek(cell)) {
>> +               if (ts->state == DECT_SLOT_RX) {
>> +                       tx_debug(cell, "enable raw TX\n");
>> +                       dect_set_channel_mode(trx, &ts->chd, 
>> DECT_SLOT_TX);
>> +                       dect_set_carrier(trx, ts->chd.slot, 
>> ts->chd.carrier);
>> +                       ts->priv_flags |= DECT_SLOT_RAW_TX;
>> +               }
>> +       } else if (ts->priv_flags & DECT_SLOT_RAW_TX) {
>> +               tx_debug(cell, "disable raw TX\n");
>> +               dect_set_channel_mode(trx, &ts->chd, DECT_SLOT_RX);
>> +               dect_set_carrier(trx, ts->chd.slot, ts->chd.carrier);
>> +               ts->priv_flags &= ~DECT_SLOT_RAW_TX;
>> +       }
>> +}
>> +
>> +static struct sk_buff *dect_raw_tx(struct dect_cell *cell)
>> +{
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_raw_tx_peek(cell);
>> +       if (skb == NULL)
>> +               return NULL;
>> +
>> +       tx_debug(cell, "raw transmit\n");
>> +       skb_unlink(skb, &cell->raw_tx_queue);
>> +       return skb;
>> +}
>> +
>> +/**
>> + * dect_d_map - DECT D-Field mapping
>> + *
>> + * @cell:      DECT cell
>> + * @bearer:    MAC bearer
>> + *
>> + * Combine the A- and B-Fields from their respective MAPs into one 
>> D-Field.
>> + */
>> +static struct sk_buff *dect_d_map(struct dect_cell *cell,
>> +                                 struct dect_bearer *bearer)
>> +{
>> +       struct sk_buff *skb_a, *skb_b, *skb;
>> +
>> +       skb = dect_raw_tx(cell);
>> +       if (skb != NULL)
>> +               return skb;
>> +
>> +       skb_a = dect_a_map(cell, bearer);
>> +       if (skb_a == NULL)
>> +               goto err1;
>> +
>> +       if (bearer->chd.pkt != DECT_PACKET_P00) {
>> +               skb_b = dect_b_map(cell, bearer);
>> +               if (skb_b == NULL)
>> +                       goto err2;
>> +               skb_a->data[DECT_HDR_BA_OFF] |= DECT_B_CB(skb_b)->id;
>> +
>> +               skb = skb_append_frag(skb_a, skb_b);
>> +               if (skb_linearize(skb) < 0) {
>> +                       kfree_skb(skb);
>> +                       skb = NULL;
>> +               }
>> +       } else {
>> +               skb_a->data[DECT_HDR_BA_OFF] |= DECT_BI_NONE;
>> +               skb = skb_a;
>> +       }
>> +
>> +       return skb;
>> +
>> +err2:
>> +       kfree_skb(skb_a);
>> +err1:
>> +       return NULL;
>> +}
>> +
>> +static void dect_mac_xmit_frame(struct dect_transceiver *trx,
>> +                               struct dect_transceiver_slot *ts)
>> +{
>> +       struct dect_cell *cell = trx->cell;
>> +       struct dect_bearer *bearer = ts->bearer;
>> +       struct sk_buff *skb;
>> +
>> +       skb = dect_d_map(cell, bearer);
>> +       if (skb == NULL)
>> +               return;
>> +
>> +       tx_debug(cell, "%s: Q1: %d Q2: %d A/B: %02x carrier: %u PSCN: 
>> %u\n",
>> +                trx->name,
>> +                skb->data[DECT_HDR_Q1_OFF] & DECT_HDR_Q1_FLAG ? 1 : 
>> 0,
>> +                skb->data[DECT_HDR_Q2_OFF] & DECT_HDR_Q2_FLAG ? 1 : 
>> 0,
>> +                skb->data[DECT_HDR_TA_OFF] &
>> +                (DECT_HDR_TA_MASK | DECT_HDR_BA_MASK),
>> +                ts->chd.carrier, cell->si.ssi.pscn);
>> +
>> +       switch (cell->mode) {
>> +       case DECT_MODE_FP:
>> +               skb->mac_len = sizeof(dect_fp_preamble);
>> +               memcpy(skb_mac_header(skb), dect_fp_preamble, 
>> skb->mac_len);
>> +               break;
>> +       case DECT_MODE_PP:
>> +               skb->mac_len = sizeof(dect_pp_preamble);
>> +               memcpy(skb_mac_header(skb), dect_pp_preamble, 
>> skb->mac_len);
>> +               break;
>> +       }
>> +
>> +       DECT_TRX_CB(skb)->trx   = trx;
>> +       DECT_TRX_CB(skb)->slot  = ts->chd.slot;
>> +       DECT_TRX_CB(skb)->frame = dect_framenum(cell, DECT_TIMER_TX);
>> +       DECT_TRX_CB(skb)->mfn   = dect_mfn(cell, DECT_TIMER_TX);
>> +       dect_raw_rcv(skb);
>> +
>> +       dect_transceiver_tx(trx, skb);
>> +}
>> +
>> +void dect_mac_rcv(struct dect_transceiver *trx,
>> +                 struct dect_transceiver_slot *ts,
>> +                 struct sk_buff *skb)
>> +{
>> +       struct dect_cell *cell = trx->cell;
>> +
>> +       DECT_TRX_CB(skb)->frame = dect_framenum(cell, DECT_TIMER_RX);
>> +       DECT_TRX_CB(skb)->mfn   = dect_mfn(cell, DECT_TIMER_RX);
>> +
>> +       /* TX bearers can temporarily switch to RX mode for noise 
>> measurement */
>> +       if (ts->bearer != NULL &&
>> +           ts->bearer->mode == DECT_BEARER_RX) {
>> +               rx_debug(cell, "%s: Q1: %d Q2: %d A/B: %02x carrier: 
>> %u %s%s%s",
>> +                        trx->name,
>> +                        skb->data[DECT_HDR_Q1_OFF] & DECT_HDR_Q1_FLAG 
>> ? 1 : 0,
>> +                        skb->data[DECT_HDR_Q2_OFF] & DECT_HDR_Q2_FLAG 
>> ? 1 : 0,
>> +                        skb->data[DECT_HDR_TA_OFF] &
>> +                        (DECT_HDR_TA_MASK | DECT_HDR_BA_MASK), 
>> ts->chd.carrier,
>> +                        DECT_TRX_CB(skb)->csum & 
>> DECT_CHECKSUM_A_CRC_OK ?
>> +                        "" : "A-CRC: 0 ",
>> +                        ts->chd.pkt == DECT_PACKET_P00 ||
>> +                        DECT_TRX_CB(skb)->csum & 
>> DECT_CHECKSUM_X_CRC_OK ?
>> +                        "" : "X-CRC: 0 ",
>> +                        ts->chd.pkt == DECT_PACKET_P00 ||
>> +                        DECT_TRX_CB(skb)->csum & 
>> DECT_CHECKSUM_Z_CRC_OK ?
>> +                        "" : "Z-CRC: 0 ");
>> +
>> +               ts->bearer->ops->rcv(cell, ts->bearer, skb);
>> +       } else
>> +               kfree_skb(skb);
>> +}
>> +
>> +void dect_mac_report_rssi(struct dect_transceiver *trx,
>> +                         struct dect_transceiver_slot *ts,
>> +                         u8 rssi)
>> +{
>> +       struct dect_cell *cell = trx->cell;
>> +
>> +       if (ts->bearer == NULL) {
>> +               pr_debug("%s: RSSI: slot: %u carrier: %u state: %u no 
>> bearer\n",
>> +                        trx->name, ts->chd.slot, ts->chd.carrier, 
>> ts->state);
>> +               return;
>> +       }
>> +       if (ts->bearer->state != DECT_BEARER_ENABLED)
>> +               dect_tx_bearer_report_rssi(cell, ts->bearer, rssi);
>> +       else if (ts->bearer->ops->report_rssi != NULL)
>> +               ts->bearer->ops->report_rssi(cell, ts->bearer, 
>> ts->chd.slot, rssi);
>> +}
>> +
>> +static void dect_fp_state_process(struct dect_cell *cell)
>> +{
>> +       if (list_empty(&cell->dbcs))
>> +               dect_dbc_init(cell, NULL);
>> +
>> +       if (time_before(cell->bfs_xmit_stamp + HZ, jiffies)) {
>> +               dect_cell_schedule_page(cell, (1 << DECT_TM_TYPE_BFS) 
>> |
>> +                                             (1 << DECT_TM_TYPE_BD));
>> +               cell->bfs_xmit_stamp = jiffies;
>> +       }
>> +}
>> +
>> +static bool dect_pp_idle_timeout(const struct dect_cell *cell)
>> +{
>> +       u32 mfn;
>> +
>> +       mfn = dect_mfn_add(cell->timer_sync_stamp, 
>> DECT_CELL_TIMER_RESYNC_TIMEOUT);
>> +       if (dect_mfn_after(dect_mfn(cell, DECT_TIMER_RX), mfn) ||
>> +           time_after(jiffies, cell->a_rcv_stamp + 
>> DECT_CELL_A_RCV_TIMEOUT) ||
>> +           time_after(jiffies, cell->nt_rcv_stamp + 
>> DECT_CELL_NT_RCV_TIMEOUT)) {
>> +               pr_debug("timeout, unlock, a: %ld nt: %ld mfn: %d\n",
>> +                        jiffies - cell->a_rcv_stamp, jiffies - 
>> cell->nt_rcv_stamp,
>> +                        dect_mfn(cell, DECT_TIMER_RX) - 
>> cell->timer_sync_stamp);
>> +               return true;
>> +       }
>> +
>> +       return false;
>> +}
>> +
>> +static void dect_pp_state_process(struct dect_cell *cell)
>> +{
>> +       struct dect_transceiver *trx = cell->trg.trx[0];
>> +       struct dect_dbc *dbc, *next;
>> +
>> +       if (cell->tbc_num_est || !list_empty(&cell->dmbs)) {
>> +               /* Active locked state: release DBCs */
>> +               list_for_each_entry_safe(dbc, next, &cell->dbcs, list)
>> +                       dect_dbc_release(dbc);
>> +       } else if (trx->state == DECT_TRANSCEIVER_LOCKED) {
>> +               /* Idle locked state: install DBC if none present */
>> +               if (list_empty(&cell->dbcs) &&
>> +                   list_empty(&cell->tbcs) &&
>> +                   list_empty(&cell->dmbs)) {
>> +                       struct dect_channel_desc chd;
>> +
>> +                       chd.pkt         = DECT_PACKET_P00;
>> +                       chd.b_fmt       = DECT_B_NONE;
>> +                       chd.slot        = cell->tbc_last_chd.slot;
>> +                       chd.carrier     = cell->tbc_last_chd.carrier;
>> +
>> +                       dect_dbc_init(cell, &chd);
>> +               }
>> +
>> +               if (!list_empty(&cell->dbcs) && 
>> dect_pp_idle_timeout(cell)) {
>> +                       list_for_each_entry_safe(dbc, next, 
>> &cell->dbcs, list)
>> +                               dect_dbc_release(dbc);
>> +
>> +                       dect_irc_disable(cell, trx->irc);
>> +                       dect_transceiver_unlock(trx);
>> +
>> +                       /* Clear system information */
>> +                       memset(&cell->si, 0, sizeof(cell->si));
>> +                       dect_cell_mac_info_ind(cell);
>> +
>> +                       dect_attempt_lock(cell, trx);
>> +               }
>> +       }
>> +}
>> +
>> +static void dect_cell_state_process(struct dect_cell *cell)
>> +{
>> +       if (list_empty(&cell->chanlists) && 
>> list_empty(&cell->chl_pending)) {
>> +               dect_chl_schedule_update(cell, DECT_PACKET_P00);
>> +               dect_chl_schedule_update(cell, DECT_PACKET_P32);
>> +       }
>> +
>> +       switch (cell->mode) {
>> +       case DECT_MODE_FP:
>> +               return dect_fp_state_process(cell);
>> +       case DECT_MODE_PP:
>> +               return dect_pp_state_process(cell);
>> +       }
>> +}
>> +
>> +static void dect_cluster_time_ind(struct dect_cell *cell,
>> +                                 enum dect_timer_bases base,
>> +                                 u8 slot)
>> +{
>> +       struct dect_cluster_handle *clh = cell->handle.clh;
>> +
>> +       clh->ops->time_ind(clh, base,
>> +                          dect_mfn(cell, base),
>> +                          dect_framenum(cell, base),
>> +                          slot);
>> +}
>> +
>> +void dect_mac_rx_tick(struct dect_transceiver_group *grp, u8 slot)
>> +{
>> +       struct dect_cell *cell = container_of(grp, struct dect_cell, 
>> trg);
>> +
>> +       dect_run_timers(cell, DECT_TIMER_RX);
>> +       dect_timer_base_update(cell, DECT_TIMER_RX, slot);
>> +       dect_cluster_time_ind(cell, DECT_TIMER_RX, slot);
>> +}
>> +
>> +void dect_mac_tx_tick(struct dect_transceiver_group *grp, u8 slot)
>> +{
>> +       struct dect_cell *cell = container_of(grp, struct dect_cell, 
>> trg);
>> +       struct dect_transceiver_slot *ts;
>> +       struct dect_transceiver *trx;
>> +       u8 scn;
>> +
>> +       /* TX timers run at the beginning of a slot, update the time 
>> first */
>> +       dect_timer_base_update(cell, DECT_TIMER_TX, slot);
>> +       dect_cluster_time_ind(cell, DECT_TIMER_TX, slot);
>> +       dect_run_timers(cell, DECT_TIMER_TX);
>> +
>> +       dect_cell_state_process(cell);
>> +
>> +       dect_foreach_transceiver(trx, grp) {
>> +               if (trx->state != DECT_TRANSCEIVER_LOCKED)
>> +                       continue;
>> +               ts = &trx->slots[slot];
>> +
>> +               dect_raw_tx_configure(cell, trx, ts);
>> +
>> +               switch (ts->state) {
>> +               case DECT_SLOT_SCANNING:
>> +                       scn = trx->irc->tx_scn;
>> +
>> +                       if (cell->flags & DECT_CELL_MONITOR &&
>> +                           slot >= DECT_HALF_FRAME_SIZE)
>> +                               scn = 
>> dect_prev_carrier(cell->si.ssi.rfcars, scn);
>> +
>> +                       dect_set_carrier(trx, slot, scn);
>> +                       break;
>> +               case DECT_SLOT_TX:
>> +                       dect_mac_xmit_frame(trx, ts);
>> +                       break;
>> +               }
>> +       }
>> +
>> +       if (slot == DECT_FRAME_SIZE - 1)
>> +               cell->si.ssi.pscn = 
>> dect_next_carrier(cell->si.ssi.rfcars,
>> +                                                     
>> cell->si.ssi.pscn);
>> +}
>> +
>> +static void dect_fp_init_primary(struct dect_cell *cell,
>> +                                struct dect_transceiver *trx)
>> +{
>> +       dect_transceiver_enable(trx);
>> +       dect_irc_enable(cell, trx->irc);
>> +}
>> +
>> +static void dect_cell_enable_transceiver(struct dect_cell *cell,
>> +                                        struct dect_transceiver *trx)
>> +{
>> +       /* The primary transceiver of a FP is a timing master. All 
>> other
>> +        * transceivers need to synchronize.
>> +        */
>> +       if (trx->index == 0 && cell->mode == DECT_MODE_FP &&
>> +           !(cell->flags & DECT_CELL_SLAVE)) {
>> +               trx->mode = DECT_TRANSCEIVER_MASTER;
>> +               dect_fp_init_primary(cell, trx);
>> +       } else {
>> +               trx->mode = DECT_TRANSCEIVER_SLAVE;
>> +               dect_attempt_lock(cell, trx);
>> +       }
>> +}
>> +
>> +static int dect_cell_preload(const struct dect_cell_handle *ch,
>> +                            const struct dect_ari *pari, u8 rpn,
>> +                            const struct dect_si *si)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +
>> +       /* Initialise identity */
>> +       spin_lock_bh(&cell->lock);
>> +       cell->idi.e = false;
>> +       memcpy(&cell->idi.pari, pari, sizeof(cell->idi.pari));
>> +       cell->idi.rpn = rpn;
>> +       cell->fmid = dect_build_fmid(&cell->idi);
>> +
>> +       cell->si.ssi.rfcars = 0x3ff;
>> +       memcpy(&cell->si.erfc, &si->erfc, sizeof(cell->si.erfc));
>> +       memcpy(&cell->si.fpc, &si->fpc, sizeof(cell->si.fpc));
>> +       memcpy(&cell->si.efpc, &si->efpc, sizeof(cell->si.efpc));
>> +       memcpy(&cell->si.efpc2, &si->efpc2, sizeof(cell->si.efpc2));
>> +       memcpy(&cell->si.mfn, &si->mfn, sizeof(cell->si.mfn));
>> +       memcpy(cell->si.sari, si->sari, sizeof(cell->si.sari));
>> +       cell->si.num_saris = si->num_saris;
>> +       dect_timer_synchronize_mfn(cell, cell->si.mfn.num);
>> +       spin_unlock_bh(&cell->lock);
>> +       return 0;
>> +}
>> +
>> +static int dect_cell_enable(const struct dect_cell_handle *ch)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_transceiver *trx;
>> +
>> +       cell->state |= DECT_CELL_ENABLED;
>> +       dect_foreach_transceiver(trx, &cell->trg) {
>> +               dect_cell_enable_transceiver(cell, trx);
>> +               if (cell->mode == DECT_MODE_PP)
>> +                       break;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void dect_scan_report(struct dect_cell *cell,
>> +                            struct dect_transceiver *trx,
>> +                            enum dect_scan_status status)
>> +{
>> +       const struct dect_cluster_handle *clh = cell->handle.clh;
>> +       const struct dect_irc *irc = trx->irc;
>> +       struct dect_scan_result res;
>> +
>> +       switch (status) {
>> +       case DECT_SCAN_FAIL:
>> +               break;
>> +       case DECT_SCAN_TIMEOUT:
>> +               pr_debug("timeout\n");
>> +       case DECT_SCAN_COMPLETE:
>> +               res.lreq = irc->lreq;
>> +               res.rssi = irc->rssi;
>> +               res.idi  = irc->idi;
>> +               res.si   = irc->si;
>> +               clh->ops->scan_report(clh, &res);
>> +               break;
>> +       }
>> +
>> +       return dect_restart_scan(cell, trx);
>> +}
>> +
>> +static int dect_cell_scan(const struct dect_cell_handle *ch,
>> +                         const struct dect_llme_req *lreq,
>> +                         const struct dect_ari *pari,
>> +                         const struct dect_ari *pari_mask)
>> +{
>> +       struct dect_cell *cell = dect_cell(ch);
>> +       struct dect_transceiver *trx = cell->trg.trx[0];
>> +
>> +       if (trx == NULL)
>> +               return -ENODEV;
>> +       // FIXME
>> +       memcpy(&trx->irc->lreq, lreq, sizeof(trx->irc->lreq));
>> +       dect_initiate_scan(trx, pari, pari_mask, dect_scan_report);
>> +       return 0;
>> +}
>> +
>>