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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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 <***@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
>> <***@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 <***@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 <***@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 <***@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 <***@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 <***@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;
>> +}
>> +
>> +static int dect_cell_set_mode(const struct dect_cell_handle *ch,
>> + enum dect_cluster_modes mode)
>> +{
>> + struct dect_cell *cell = dect_cell(ch);
>> +
>> + cell->mode = mode;
>> + return 0;
>> +}
>> +
>> +static void dect_cell_page_req(const struct dect_cell_handle *ch,
>> + struct sk_buff *skb)
>> +{
>> + struct dect_cell *cell = dect_cell(ch);
>> +
>> + DECT_BMC_CB(skb)->stamp = dect_mfn(cell, DECT_TIMER_TX);
>> + dect_queue_page(cell, skb);
>> +}
>> +
>> +static const struct dect_csf_ops dect_csf_ops = {
>> + .set_mode = dect_cell_set_mode,
>> + .scan = dect_cell_scan,
>> + .enable = dect_cell_enable,
>> + .preload = dect_cell_preload,
>> + .page_req = dect_cell_page_req,
>> + .tbc_establish_req = dect_tbc_establish_req,
>> + .tbc_establish_res = dect_tbc_establish_res,
>> + .tbc_dis_req = dect_tbc_dis_req,
>> + .tbc_enc_key_req = dect_tbc_enc_key_req,
>> + .tbc_enc_eks_req = dect_tbc_enc_eks_req,
>> + .tbc_enc_req = dect_tbc_enc_req,
>> + .tbc_data_req = dect_tbc_data_req,
>> +};
>> +
>> +static int dect_cell_bind(struct dect_cell *cell, u8 index)
>> +{
>> + struct dect_cluster_handle *clh;
>> + struct dect_cluster *cl;
>> +
>> + if (cell->flags & DECT_CELL_CCP) {
>> + clh = dect_ccp_cell_init(cell, index);
>> + if (IS_ERR(clh))
>> + return PTR_ERR(clh);
>> + } else {
>> + cl = dect_cluster_get_by_index(index);
>> + if (cl == NULL)
>> + return -ENOENT;
>> + clh = &cl->handle;
>> + }
>> +
>> + return clh->ops->bind(clh, &cell->handle);
>> +}
>> +
>> +static void dect_cell_shutdown(struct dect_cell *cell)
>> +{
>> + struct dect_cluster_handle *clh = cell->handle.clh;
>> + struct dect_transceiver *trx;
>> +
>> + if (clh != NULL)
>> + clh->ops->unbind(clh, &cell->handle);
>> +
>> + dect_foreach_transceiver(trx, &cell->trg)
>> + dect_cell_detach_transceiver(cell, trx);
>> + dect_cell_bmc_disable(cell);
>> + skb_queue_purge(&cell->raw_tx_queue);
>> +}
>> +
>> +/**
>> + * dect_mac_init_cell - Initialize a DECT cell
>> + */
>> +static void dect_cell_init(struct dect_cell *cell)
>> +{
>> + spin_lock_init(&cell->lock);
>> + INIT_LIST_HEAD(&cell->bcs);
>> + INIT_LIST_HEAD(&cell->dbcs);
>> + INIT_LIST_HEAD(&cell->tbcs);
>> + INIT_LIST_HEAD(&cell->dmbs);
>> + INIT_LIST_HEAD(&cell->chl_pending);
>> + INIT_LIST_HEAD(&cell->chanlists);
>> + dect_timer_base_init(cell->timer_base, DECT_TIMER_TX);
>> + dect_timer_base_init(cell->timer_base, DECT_TIMER_RX);
>> + skb_queue_head_init(&cell->raw_tx_queue);
>> + dect_cell_bmc_init(cell);
>> + cell->blind_full_slots = (1 << DECT_HALF_FRAME_SIZE) - 1;
>> + cell->trg_blind_full_slots = (1 << DECT_HALF_FRAME_SIZE) - 1;
>> + dect_transceiver_group_init(&cell->trg);
>> + cell->handle.ops = &dect_csf_ops;
>> +}
>> +
>> +/**
>> + * dect_cell_attach_transceiver - attach a transceiver to a DECT cell
>> + *
>> + * Attach the transceiver to the cell's transceiver group and
>> initialize
>> + * an idle receiver control instance.
>> + */
>> +int dect_cell_attach_transceiver(struct dect_cell *cell,
>> + struct dect_transceiver *trx)
>> +{
>> + int err;
>> +
>> + if (trx->cell != NULL)
>> + return -EBUSY;
>> +
>> + err = dect_transceiver_group_add(&cell->trg, trx);
>> + if (err < 0)
>> + goto err1;
>> +
>> + err = -ENOMEM;
>> + if (!dect_irc_init(cell, trx))
>> + goto err2;
>> +
>> + trx->cell = cell;
>> + if (cell->state & DECT_CELL_ENABLED)
>> + dect_cell_enable_transceiver(cell, trx);
>> +
>> + return 0;
>> +
>> +err2:
>> + dect_transceiver_group_remove(&cell->trg, trx);
>> +err1:
>> + return err;
>> +}
>> +
>> +/**
>> + * dect_cell_detach_transceiver - detach a transceiver from a DECT
>> cell
>> + *
>> + * Detach the transceiver from the cell's transceiver group and
>> release
>> + * the associated resources.
>> + */
>> +void dect_cell_detach_transceiver(struct dect_cell *cell,
>> + struct dect_transceiver *trx)
>> +{
>> + dect_irc_disable(cell, trx->irc);
>> + dect_transceiver_disable(trx);
>> + dect_transceiver_group_remove(&cell->trg, trx);
>> + kfree(trx->irc);
>> + trx->cell = NULL;
>> +
>> + dect_notify_cell(DECT_NEW_CELL, cell, NULL, 0);
>> +}
>> +
>> +/*
>> + * Cell netlink interface
>> + */
>> +
>> +static u32 dect_cell_alloc_index(void)
>> +{
>> + static u32 index;
>> +
>> + for (;;) {
>> + if (++index == 0)
>> + index = 1;
>> + if (!dect_cell_get_by_index(index))
>> + return index;
>> + }
>> +}
>> +
>> +static int dect_fill_cell(struct sk_buff *skb,
>> + const struct dect_cell *cell,
>> + u16 type, u32 pid, u32 seq, u16 flags)
>> +{
>> + const struct dect_transceiver *trx;
>> + struct nlmsghdr *nlh;
>> + struct dectmsg *dm;
>> + struct nlattr *nest;
>> +
>> + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*dm), flags);
>> + if (nlh == NULL)
>> + return -EMSGSIZE;
>> + dm = nlmsg_data(nlh);
>> + dm->dm_index = cell->index;
>> +
>> + nla_put_string(skb, DECTA_CELL_NAME, cell->name);
>> + if (cell->flags != 0)
>> + nla_put_u32(skb, DECTA_CELL_FLAGS, cell->flags);
>> + if (cell->trg.trxmask != 0) {
>> + nest = nla_nest_start(skb, DECTA_CELL_TRANSCEIVERS);
>> + if (nest == NULL)
>> + goto nla_put_failure;
>> + dect_foreach_transceiver(trx, &cell->trg)
>> + nla_put_string(skb, DECTA_LIST_ELEM,
>> trx->name);
>> + nla_nest_end(skb, nest);
>> + }
>> + if (cell->handle.clh != NULL)
>> + nla_put_u8(skb, DECTA_CELL_CLUSTER,
>> cell->handle.clh->index);
>> +
>> + return nlmsg_end(skb, nlh);
>> +
>> +nla_put_failure:
>> + nlmsg_cancel(skb, nlh);
>> + return -EMSGSIZE;
>> +}
>> +
>> +static int dect_dump_cell(struct sk_buff *skb,
>> + struct netlink_callback *cb)
>> +{
>> + const struct dect_cell *cell;
>> + unsigned int idx, s_idx;
>> +
>> + s_idx = cb->args[0];
>> + idx = 0;
>> + list_for_each_entry(cell, &dect_cell_list, list) {
>> + if (idx < s_idx)
>> + goto cont;
>> + if (dect_fill_cell(skb, cell, DECT_NEW_CELL,
>> + 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_cell(u16 event, const struct dect_cell *cell,
>> + 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_cell(skb, cell, event, pid, seq, NLMSG_DONE);
>> + if (err < 0) {
>> + WARN_ON(err == -EMSGSIZE);
>> + kfree_skb(skb);
>> + goto err;
>> + }
>> + nlmsg_notify(dect_nlsk, skb, pid, DECTNLGRP_CELL, report,
>> GFP_KERNEL);
>> +err:
>> + if (err < 0)
>> + netlink_set_err(dect_nlsk, pid, DECTNLGRP_CELL, err);
>> +}
>> +
>> +static const struct nla_policy dect_cell_policy[DECTA_CELL_MAX + 1] =
>> {
>> + [DECTA_CELL_NAME] = { .type = NLA_STRING, .len =
>> DECTNAMSIZ },
>> + [DECTA_CELL_FLAGS] = { .type = NLA_U32 },
>> + [DECTA_CELL_CLUSTER] = { .type = NLA_U8 },
>> +};
>> +
>> +static int dect_new_cell(const struct sk_buff *skb,
>> + const struct nlmsghdr *nlh,
>> + const struct nlattr *tb[DECTA_CELL_MAX + 1])
>> +{
>> + struct dect_cell *cell;
>> + struct dectmsg *dm;
>> + u32 flags = 0;
>> + u8 cli = 0;
>> + int err;
>> +
>> + dm = nlmsg_data(nlh);
>> + if (dm->dm_index != 0)
>> + cell = dect_cell_get_by_index(dm->dm_index);
>> + else if (tb[DECTA_CELL_NAME] != NULL)
>> + cell = dect_cell_get_by_name(tb[DECTA_CELL_NAME]);
>> + else
>> + return -EINVAL;
>> +
>> + if (tb[DECTA_CELL_FLAGS] != NULL) {
>> + flags = nla_get_u32(tb[DECTA_CELL_FLAGS]);
>> + if (flags & ~(DECT_CELL_CCP | DECT_CELL_SLAVE |
>> + DECT_CELL_MONITOR))
>> + return -EINVAL;
>> + }
>> +
>> + if (tb[DECTA_CELL_CLUSTER] != NULL)
>> + cli = nla_get_u8(tb[DECTA_CELL_CLUSTER]);
>> +
>> + if (cell != NULL) {
>> + if (nlh->nlmsg_flags & NLM_F_EXCL)
>> + return -EEXIST;
>> +
>> + if (tb[DECTA_CELL_CLUSTER] != NULL) {
>> + if (cell->handle.clh != NULL)
>> + return -EBUSY;
>> + if (cli != 0)
>> + return dect_cell_bind(cell, cli);
>> + }
>> + return 0;
>> + }
>> +
>> + if (!(nlh->nlmsg_flags & NLM_F_CREATE))
>> + return -ENOENT;
>> +
>> + cell = kzalloc(sizeof(*cell), GFP_KERNEL);
>> + if (cell == NULL)
>> + return -ENOMEM;
>> + cell->index = dect_cell_alloc_index();
>> + nla_strlcpy(cell->name, tb[DECTA_CELL_NAME],
>> sizeof(cell->name));
>> + cell->flags = flags;
>> + dect_cell_init(cell);
>> +
>> + if (cli != 0) {
>> + err = dect_cell_bind(cell, cli);
>> + if (err < 0)
>> + goto err;
>> + }
>> +
>> + list_add_tail(&cell->list, &dect_cell_list);
>> + dect_notify_cell(DECT_NEW_CELL, cell, nlh,
>> NETLINK_CB(skb).portid);
>> + return 0;
>> +
>> +err:
>> + kfree(cell);
>> + return err;
>> +}
>> +
>> +static int dect_del_cell(const struct sk_buff *skb,
>> + const struct nlmsghdr *nlh,
>> + const struct nlattr *tb[DECTA_CELL_MAX + 1])
>> +{
>> + struct dect_cell *cell = NULL;
>> + struct dectmsg *dm;
>> +
>> + dm = nlmsg_data(nlh);
>> + if (dm->dm_index != 0)
>> + cell = dect_cell_get_by_index(dm->dm_index);
>> + else if (tb[DECTA_CELL_NAME] != NULL)
>> + cell = dect_cell_get_by_name(tb[DECTA_CELL_NAME]);
>> + if (cell == NULL)
>> + return -ENODEV;
>> +
>> + cell = dect_cell_get_by_name(tb[DECTA_CELL_NAME]);
>> + if (cell == NULL)
>> + return -ENOENT;
>> +
>> + dect_cell_shutdown(cell);
>> + list_del(&cell->list);
>> + dect_notify_cell(DECT_DEL_CELL, cell, nlh,
>> NETLINK_CB(skb).portid);
>> + kfree(cell);
>> + return 0;
>> +}
>> +
>> +static int dect_get_cell(const struct sk_buff *in_skb,
>> + const struct nlmsghdr *nlh,
>> + const struct nlattr *tb[DECTA_CELL_MAX + 1])
>> +{
>> + u32 pid = NETLINK_CB(in_skb).portid;
>> + const struct dect_cell *cell = NULL;
>> + struct dectmsg *dm;
>> + struct sk_buff *skb;
>> + int err;
>> +
>> + dm = nlmsg_data(nlh);
>> + if (dm->dm_index != 0)
>> + cell = dect_cell_get_by_index(dm->dm_index);
>> + else if (tb[DECTA_CELL_NAME] != NULL)
>> + cell = dect_cell_get_by_name(tb[DECTA_CELL_NAME]);
>> + if (cell == NULL)
>> + return -ENODEV;
>> +
>> + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (skb == NULL)
>> + return -ENOMEM;
>> + err = dect_fill_cell(skb, cell, DECT_NEW_CELL, 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_cell_handlers[] = {
>> + {
>> + /* DECT_NEW_CELL */
>> + .policy = dect_cell_policy,
>> + .maxtype = DECTA_CELL_MAX,
>> + .doit = dect_new_cell,
>> + },
>> + {
>> + /* DECT_DEL_CELL */
>> + .policy = dect_cell_policy,
>> + .maxtype = DECTA_CELL_MAX,
>> + .doit = dect_del_cell,
>> + },
>> + {
>> + /* DECT_GET_CELL */
>> + .policy = dect_cell_policy,
>> + .maxtype = DECTA_CELL_MAX,
>> + .doit = dect_get_cell,
>> + .dump = dect_dump_cell,
>> + },
>> +};
>> +
>> +static int __init dect_csf_module_init(void)
>> +{
>> + int err;
>> +
>> + err = dect_transceiver_module_init();
>> + if (err < 0)
>> + return err;
>> +
>> + dect_netlink_register_handlers(dect_cell_handlers,
>> DECT_NEW_CELL,
>> +
>> ARRAY_SIZE(dect_cell_handlers));
>> + return 0;
>> +}
>> +
>> +static void __exit dect_csf_module_exit(void)
>> +{
>> + dect_netlink_unregister_handlers(DECT_NEW_CELL,
>> +
>> ARRAY_SIZE(dect_cell_handlers));
>> + dect_transceiver_module_exit();
>> +}
>> +
>> +module_init(dect_csf_module_init);
>> +module_exit(dect_csf_module_exit);
>> diff --git a/target/linux/generic/files/net/dect/raw.c
>> b/target/linux/generic/files/net/dect/raw.c
>> new file mode 100644
>> index 0000000..86056cf
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/raw.c
>> @@ -0,0 +1,267 @@
>> +/*
>> + * DECT RAW sockets
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <***@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/mac_csf.h>
>> +
>> +static HLIST_HEAD(dect_raw_sockets);
>> +
>> +struct dect_raw_sk {
>> + struct sock sk;
>> +};
>> +
>> +static inline struct dect_raw_sk *dect_raw_sk(struct sock *sk)
>> +{
>> + return (struct dect_raw_sk *)sk;
>> +}
>> +
>> +static void __dect_raw_rcv(struct sk_buff *skb)
>> +{
>> + struct dect_cell *cell = DECT_TRX_CB(skb)->trx->cell;
>> + struct sk_buff *skb2;
>> + struct sock *sk;
>> +
>> + sk_for_each_bound(sk, &dect_raw_sockets) {
>> + if (sk->sk_bound_dev_if &&
>> + sk->sk_bound_dev_if != cell->index)
>> + continue;
>> + if (skb->sk == sk)
>> + continue;
>> +
>> + skb2 = skb_clone(skb, GFP_ATOMIC);
>> + if (skb2 == NULL) {
>> + sk->sk_err = -ENOMEM;
>> + sk->sk_error_report(sk);
>> + } else {
>> + /* Release the transceiver reference, it is
>> only valid
>> + * in IRQ and softirq context.
>> + */
>> + DECT_TRX_CB(skb2)->trx = NULL;
>> + if (dect_sock_queue_rcv_skb(sk, skb2) < 0)
>> + kfree_skb(skb2);
>> + }
>> + }
>> +}
>> +
>> +static void dect_raw_close(struct sock *sk, long timeout)
>> +{
>> + sk_common_release(sk);
>> +}
>> +
>> +static int dect_raw_bind(struct sock *sk, struct sockaddr *uaddr, int
>> len)
>> +{
>> + struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
>> +
>> + if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
>> + return -EINVAL;
>> +
>> + if (addr->dect_index != 0 &&
>> + !dect_cell_get_by_index(addr->dect_index))
>> + return -ENODEV;
>> +
>> + lock_sock(sk);
>> + sk->sk_bound_dev_if = addr->dect_index;
>> + if (!hlist_unhashed(&sk->sk_bind_node))
>> + __sk_del_bind_node(sk);
>> + sk_add_bind_node(sk, &dect_raw_sockets);
>> + release_sock(sk);
>> + return 0;
>> +}
>> +
>> +static void dect_raw_unhash(struct sock *sk)
>> +{
>> + if (!hlist_unhashed(&sk->sk_bind_node))
>> + __sk_del_bind_node(sk);
>> +}
>> +
>> +static int dect_raw_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_raw_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_raw_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;
>> +
>> + 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.mfn = DECT_TRX_CB(skb)->mfn;
>> + aux.frame = DECT_TRX_CB(skb)->frame;
>> + aux.slot = DECT_TRX_CB(skb)->slot;
>> + aux.rssi = DECT_TRX_CB(skb)->rssi;
>> + put_cmsg(msg, SOL_DECT, DECT_RAW_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_raw_sendmsg(struct kiocb *iocb, struct sock *sk,
>> + struct msghdr *msg, size_t len)
>> +{
>> + struct sockaddr_dect *addr = msg->msg_name;
>> + struct dect_raw_auxdata *aux = NULL;
>> + struct dect_cell *cell;
>> + struct sk_buff *skb;
>> + struct cmsghdr *cmsg;
>> + size_t size;
>> + 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;
>> +
>> + cell = dect_cell_get_by_index(index);
>> + if (cell == NULL)
>> + return -ENODEV;
>> +
>> + 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_RAW_AUXDATA:
>> + if (cmsg->cmsg_len != CMSG_LEN(sizeof(*aux)))
>> + return -EINVAL;
>> + aux = (struct dect_raw_auxdata
>> *)CMSG_DATA(cmsg);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + }
>> +
>> + if (aux == NULL)
>> + return -EINVAL;
>> +
>> + size = DECT_PREAMBLE_SIZE + len;
>> + skb = sock_alloc_send_skb(sk, size, msg->msg_flags &
>> MSG_DONTWAIT, &err);
>> + if (skb == NULL)
>> + goto err1;
>> +
>> + /* Reserve space for preamble */
>> + skb_reset_mac_header(skb);
>> + skb_reserve(skb, DECT_PREAMBLE_SIZE);
>> +
>> + err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
>> + if (err < 0)
>> + goto err2;
>> +
>> + DECT_TRX_CB(skb)->mfn = aux->mfn;
>> + DECT_TRX_CB(skb)->frame = aux->frame;
>> + DECT_TRX_CB(skb)->slot = aux->slot;
>> +
>> + skb_queue_tail(&cell->raw_tx_queue, skb);
>> + return len;
>> +
>> +err2:
>> + kfree_skb(skb);
>> +err1:
>> + return err;
>> +}
>> +
>> +static struct dect_proto dect_raw_proto = {
>> + .type = SOCK_RAW,
>> + .protocol = DECT_RAW,
>> + .capability = CAP_NET_RAW,
>> + .ops = &dect_dgram_ops,
>> + .proto.name = "DECT_RAW",
>> + .proto.owner = THIS_MODULE,
>> + .proto.obj_size = sizeof(struct dect_raw_sk),
>> + .proto.close = dect_raw_close,
>> + .proto.bind = dect_raw_bind,
>> + .proto.unhash = dect_raw_unhash,
>> + .proto.recvmsg = dect_raw_recvmsg,
>> + .proto.sendmsg = dect_raw_sendmsg,
>> + .getname = dect_raw_getname,
>> +};
>> +
>> +static int __init dect_raw_init(void)
>> +{
>> + int err;
>> +
>> + BUILD_BUG_ON(sizeof(struct sockaddr_dect) >
>> + sizeof(struct sockaddr));
>> + err = dect_proto_register(&dect_raw_proto);
>> + if (err < 0)
>> + return err;
>> + rcu_assign_pointer(dect_raw_rcv_hook, __dect_raw_rcv);
>> + return 0;
>> +}
>> +
>> +static void __exit dect_raw_exit(void)
>> +{
>> + rcu_assign_pointer(dect_raw_rcv_hook, NULL);
>> + synchronize_rcu();
>> + dect_proto_unregister(&dect_raw_proto);
>> +}
>> +
>> +module_init(dect_raw_init);
>> +module_exit(dect_raw_exit);
>> +
>> +MODULE_AUTHOR("Patrick McHardy <***@trash.net>");
>> +MODULE_DESCRIPTION("DECT RAW sockets");
>> +MODULE_LICENSE("GPL");
>> +
>> +MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_RAW);
>> diff --git a/target/linux/generic/files/net/dect/transceiver.c
>> b/target/linux/generic/files/net/dect/transceiver.c
>> new file mode 100644
>> index 0000000..84b71a0
>> --- /dev/null
>> +++ b/target/linux/generic/files/net/dect/transceiver.c
>> @@ -0,0 +1,1031 @@
>> +/*
>> + * DECT transceiver and transceiver group functions
>> + *
>> + * Copyright (c) 2009 Patrick McHardy <***@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/mutex.h>
>> +#include <linux/list.h>
>> +#include <linux/notifier.h>
>> +#include <net/dect/dect.h>
>> +#include <net/dect/mac_csf.h>
>> +#include <net/dect/transceiver.h>
>> +
>> +static LIST_HEAD(dect_transceiver_list);
>> +static int dect_transceiver_notify(struct dect_transceiver *trx,
>> + unsigned long event);
>> +
>> +#define trx_debug(trx, fmt, args...) \
>> + pr_debug("%s: " fmt, trx->name, ## args)
>> +
>> +static const struct dect_band *dect_band[DECT_BAND_NUM];
>> +static const u8 dect_pkt_size[] = {
>> + [DECT_PACKET_P00] = DECT_P00_SIZE,
>> + [DECT_PACKET_P08] = DECT_P08_SIZE,
>> + [DECT_PACKET_P32] = DECT_P32_SIZE,
>> + [DECT_PACKET_P640j] = DECT_P640j_SIZE,
>> + [DECT_PACKET_P672j] = DECT_P672j_SIZE,
>> + [DECT_PACKET_P80] = DECT_P80_SIZE,
>> +};
>> +
>> +/**
>> + * dect_transceiver_alloc_skb - allocate a transceiver RX skb
>> + *
>> + * @trx: transceiver
>> + * @slot: slot number
>> + *
>> + * Allocate a skb according to the receiving channel characteristics.
>> + */
>> +struct sk_buff *dect_transceiver_alloc_skb(struct dect_transceiver
>> *trx, u8 slot)
>> +{
>> + const struct dect_transceiver_slot *ts = &trx->slots[slot];
>> + unsigned int align;
>> + struct sk_buff *skb;
>> +
>> + align = __alignof__(u64) - DECT_PREAMBLE_SIZE;
>> +
>> + skb = alloc_skb(dect_pkt_size[ts->chd.pkt] + align,
>> GFP_ATOMIC);
>> + if (skb == NULL)
>> + return NULL;
>> + DECT_TRX_CB(skb)->trx = trx;
>> + DECT_TRX_CB(skb)->slot = ts->chd.slot;
>> + /* Reserve room for preamble and set up adjacent packet data
>> pointer */
>> + skb_reserve(skb, DECT_PREAMBLE_SIZE + align);
>> + skb_put(skb, dect_pkt_size[ts->chd.pkt] - DECT_PREAMBLE_SIZE);
>> + return skb;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_transceiver_alloc_skb);
>> +
>> +/* Transceiver virtual clock maintenance:
>> + *
>> + * The transceiver layer processes the received frames from some
>> slots in
>> + * the past while the transceiver is transceiving on the following
>> slots.
>> + * Additionally the transceiver needs to be maintained for the
>> upcoming
>> + * slots. Therefore there are three different reference frames of
>> time:
>> + *
>> + * [ RX ][ TRX ][ TX ]
>> + * slot_0 -> slot_23
>> + *
>> + * - Real time, which is only known to the transceiver
>> + *
>> + * - RX time, which is a virtual clock following real time by at
>> least one
>> + * slot and advancing as received slots are processed. A
>> transceiver must
>> + * generate enough events so that the RX time never lags behind the
>> TRX
>> + * time for more than one TDMA half frame.
>> + *
>> + * - TX time, which is a virtual clock leading RX time by a usually
>> constant
>> + * amount of slots large enough so that packets queued to the
>> transceiver
>> + * will reach the transceiver in time to be sent. It always leads
>> real time,
>> + * but must never have a distance greater than one TDMA half frame
>> from RX
>> + * time, resulting in a maximal distance of 11 to real time.
>> + *
>> + * Transceivers periodically notify the transceiver layer of an
>> elapsed amount
>> + * of time and the frames that were received during that period. The
>> events
>> + * batches generated by multiple transceivers contained in a group
>> are merged
>> + * and processed as a single chronological event stream.
>> + *
>> + * The following steps are performed during processing (for every
>> slot):
>> + *
>> + * - Received packets are passed to the MAC layer
>> + * - A RX tick is generated, ending the last RX slot
>> + * - A TX tick with some offset in the future is generated, beginning
>> the
>> + * next TX slot
>> + *
>> + * The RX and TX ticks are used by the MAC layer to maintain two
>> timer bases
>> + * for performing maintenance operations after a slot was received or
>> before
>> + * a slot will be transmitted.
>> + */
>> +
>> +/**
>> + * dect_transceiver_queue_event - queue a transceiver event for BH
>> processing
>> + *
>> + * @trx: DECT transceiver
>> + * @event: Transceiver event
>> + */
>> +void dect_transceiver_queue_event(struct dect_transceiver *trx,
>> + struct dect_transceiver_event
>> *event)
>> +{
>> + struct dect_transceiver_group *grp = &trx->cell->trg;
>> +
>> + spin_lock(&grp->lock);
>> + list_add_tail(&event->list, &grp->events);
>> + spin_unlock(&grp->lock);
>> +
>> + tasklet_hi_schedule(&grp->tasklet);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_transceiver_queue_event);
>> +
>> +static struct dect_transceiver_event *
>> +dect_dequeue_event(struct dect_transceiver_group *grp)
>> +{
>> + struct dect_transceiver_event *event;
>> + unsigned long flags;
>> +
>> + event = NULL;
>> + spin_lock_irqsave(&grp->lock, flags);
>> + if (!list_empty(&grp->events)) {
>> + event = list_first_entry(&grp->events,
>> + struct
>> dect_transceiver_event,
>> + list);
>> + list_del(&event->list);
>> + }
>> + spin_unlock_irqrestore(&grp->lock, flags);
>> + return event;
>> +}
>> +
>> +static void dect_tg_merge_events(struct dect_transceiver_group *grp,
>> + struct dect_transceiver *trx,
>> + struct dect_transceiver_event *event)
>> +{
>> + struct sk_buff *skb;
>> + u8 slot, idx, i;
>> +
>> + /* Transfer the packets to the slot input queues and mark the
>> + * slot events.
>> + */
>> + trx_debug(trx, "merge %u events pos %u rssi_mask %x\n",
>> + trx->ops->eventrate, event->slotpos,
>> event->rssi_mask);
>> +
>> + for (i = 0; i < trx->ops->eventrate; i++) {
>> + slot = event->slotpos + i;
>> + idx = slot % ARRAY_SIZE(grp->slots);
>> +
>> + skb = skb_peek(&event->rx_queue);
>> + if (skb != NULL && DECT_TRX_CB(skb)->slot == slot) {
>> + __skb_unlink(skb, &event->rx_queue);
>> + __skb_queue_tail(&grp->slots[idx].queue, skb);
>> + } else if (event->rssi_mask & (1 << i))
>> + grp->slots[idx].rssi[trx->index] =
>> event->rssi[i];
>> +
>> + grp->slots[idx].mask |= 1 << trx->index;
>> + }
>> +}
>> +
>> +static bool seqno_before(u32 seq1, u32 seq2)
>> +{
>> + return (s32)(seq2 - seq1) > 0;
>> +}
>> +
>> +static bool seqno_after(u32 seq1, u32 seq2)
>> +{
>> + return seqno_before(seq2, seq1);
>> +}
>> +
>> +static void dect_tg_process_events(struct dect_transceiver_group
>> *grp)
>> +{
>> + struct dect_transceiver *trx;
>> + struct dect_transceiver_slot *ts;
>> + struct sk_buff *skb;
>> + u8 idx, d, i;
>> + u16 late;
>> +
>> + pr_debug("process events slot_low=%u slot_high=%u
>> distance=%u\n",
>> + grp->slot_low, grp->slot_high,
>> + dect_slot_distance(grp->slot_low, grp->slot_high));
>> +
>> + while (grp->slot_low != grp->slot_high) {
>> + /*
>> + * If more than one half frame is missing, only
>> forward the
>> + * clock since the slot positions refer to slots in
>> the
>> + * following half frame.
>> + */
>> + d = dect_slot_distance(grp->slot_low, grp->slot_high);
>> + if (d > ARRAY_SIZE(grp->slots))
>> + goto tick;
>> +
>> + idx = grp->slot_low % ARRAY_SIZE(grp->slots);
>> +
>> + /* Check for transceivers which are lagging by more
>> than their
>> + * event rate window and mark the current window
>> entirely as
>> + * lost.
>> + */
>> + late = grp->slots[idx].mask ^ grp->trxmask;
>> + while (late != 0) {
>> + trx = grp->trx[ffs(late) - 1];
>> + late &= ~(1 << trx->index);
>> +
>> + if (!seqno_before(trx->seqno +
>> trx->ops->eventrate,
>> + grp->seqno) &&
>> + d <= trx->ops->eventrate)
>> + continue;
>> +
>> + trx_debug(trx, "late for window %u\n",
>> grp->slot_low);
>> + for (i = 0; i < trx->ops->eventrate; i++)
>> + grp->slots[(idx + i) % 12].mask |= 1
>> << trx->index;
>> + trx->stats.event_late++;
>> + }
>> +
>> + if (grp->slots[idx].mask != grp->trxmask) {
>> + pr_debug("slot %u incomplete: mask %x trx
>> %x\n",
>> + grp->slot_low, grp->slots[idx].mask,
>> grp->trxmask);
>> + break;
>> + }
>> +
>> + while ((skb = __skb_dequeue(&grp->slots[idx].queue)))
>> {
>> + trx = DECT_TRX_CB(skb)->trx;
>> + ts = &trx->slots[DECT_TRX_CB(skb)->slot];
>> + dect_mac_rcv(trx, ts, skb);
>> + }
>> +
>> + for (i = 0; i < ARRAY_SIZE(grp->slots[idx].rssi); i++)
>> {
>> + if (grp->slots[idx].rssi[i] == 0)
>> + continue;
>> + trx = grp->trx[i];
>> + ts = &trx->slots[grp->slot_low];
>> + dect_mac_report_rssi(trx, ts,
>> grp->slots[idx].rssi[i]);
>> + grp->slots[idx].rssi[i] = 0;
>> + }
>> +
>> + grp->slots[idx].mask = 0;
>> +tick:
>> + dect_mac_rx_tick(grp,
>> dect_next_slotnum(grp->slot_low));
>> + dect_mac_tx_tick(grp, dect_slot_add(grp->slot_low,
>> + 2 *
>> grp->latency));
>> +
>> + grp->slot_low = dect_next_slotnum(grp->slot_low);
>> + }
>> +}
>> +
>> +/*
>> + * Softirq transceiver group event processing
>> + */
>> +static void dect_transceiver_tasklet(unsigned long data)
>> +{
>> + struct dect_transceiver_group *grp = (struct
>> dect_transceiver_group *)data;
>> + struct dect_transceiver *trx;
>> + struct dect_transceiver_event *event;
>> + struct sk_buff *skb;
>> +
>> +again:
>> + event = dect_dequeue_event(grp);
>> + if (event == NULL) {
>> + dect_tg_process_events(grp);
>> + return;
>> + }
>> +
>> + trx = event->trx;
>> +
>> + trx_debug(trx, "event handler: trx: seq %u pos %u grp: seq %u
>> pos %u\n",
>> + trx->seqno, event->slotpos, grp->seqno,
>> grp->slot_low);
>> +
>> + /* Before a transceiver is locked, its timing might vary and
>> isn't
>> + * synchronized to the remaining group. The MAC layer handles
>> this
>> + * manually.
>> + */
>> + if (trx->state != DECT_TRANSCEIVER_LOCKED) {
>> + skb = __skb_dequeue(&event->rx_queue);
>> + if (skb != NULL)
>> + dect_mac_irc_rcv(trx, skb);
>> + dect_mac_irc_tick(trx);
>> + goto out;
>> + }
>> +
>> + /* If a secondary transceiver enters locked state or a
>> tranceiver missed
>> + * a previous window, its sequence number is out of sync.
>> Resync it once
>> + * it starts reporting events in the current window.
>> + *
>> + * FIXME: driver should ignore frames with missed interrupts
>> completely
>> + */
>> + if (seqno_before(trx->seqno + trx->ops->eventrate,
>> grp->seqno)) {
>> + if (event->slotpos != grp->slot_low) {
>> + trx_debug(trx, "unsynchronized\n");
>> + __skb_queue_purge(&event->rx_queue);
>> + goto out;
>> + }
>> +
>> + trx->seqno = grp->seqno;
>> + if (grp->slot_high != grp->slot_low)
>> + trx->seqno -= trx->ops->eventrate;
>> +
>> + trx_debug(trx, "synchronized to seqno %u\n",
>> trx->seqno);
>> + }
>> +
>> + /* Merge the events and update the sequence number. The
>> transceiver
>> + * with the highest sequence number determines the slot
>> position for
>> + * the entire group.
>> + */
>> + dect_tg_merge_events(grp, trx, event);
>> +
>> + trx->seqno += trx->ops->eventrate;
>> + if (seqno_after(trx->seqno, grp->seqno)) {
>> + grp->seqno = trx->seqno;
>> + grp->slot_high =
>> + dect_slot_add(event->slotpos,
>> trx->ops->eventrate);
>> + }
>> +
>> +out:
>> + dect_release_transceiver_event(event);
>> + goto again;
>> +}
>> +
>> +int dect_transceiver_group_add(struct dect_transceiver_group *grp,
>> + struct dect_transceiver *trx)
>> +{
>> + u8 index;
>> +
>> + index = ffz(grp->trxmask);
>> + if (index >= ARRAY_SIZE(grp->trx))
>> + return -EMFILE;
>> +
>> + trx->index = index;
>> + grp->trx[index] = trx;
>> + if (trx->ops->latency > grp->latency)
>> + grp->latency = trx->ops->latency;
>> +
>> + grp->trxmask |= 1 << index;
>> + return 0;
>> +}
>> +
>> +void dect_transceiver_group_remove(struct dect_transceiver_group
>> *grp,
>> + struct dect_transceiver *trx)
>> +{
>> + grp->trxmask &= ~(1 << trx->index);
>> + /* Synchronize with interrupt and softirq processing */
>> + synchronize_rcu();
>> + grp->trx[trx->index] = NULL;
>> +}
>> +
>> +void dect_transceiver_group_init(struct dect_transceiver_group *grp)
>> +{
>> + unsigned int i;
>> +
>> + spin_lock_init(&grp->lock);
>> + INIT_LIST_HEAD(&grp->events);
>> + for (i = 0; i < ARRAY_SIZE(grp->slots); i++)
>> + __skb_queue_head_init(&grp->slots[i].queue);
>> +
>> + tasklet_init(&grp->tasklet, dect_transceiver_tasklet,
>> + (unsigned long)grp);
>> +}
>> +
>> +void dect_transceiver_disable(struct dect_transceiver *trx)
>> +{
>> + trx->ops->disable(trx);
>> + trx->state = DECT_TRANSCEIVER_STOPPED;
>> +}
>> +
>> +void dect_transceiver_enable(struct dect_transceiver *trx)
>> +{
>> + if (trx->mode == DECT_TRANSCEIVER_MASTER)
>> + trx->state = DECT_TRANSCEIVER_LOCKED;
>> + else
>> + trx->state = DECT_TRANSCEIVER_UNLOCKED;
>> +
>> + trx->ops->enable(trx);
>> +}
>> +
>> +void dect_transceiver_confirm(struct dect_transceiver *trx)
>> +{
>> + trx_debug(trx, "confirm\n");
>> + trx->state = DECT_TRANSCEIVER_LOCK_PENDING;
>> + trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_RX;
>> + trx->ops->confirm(trx);
>> +}
>> +
>> +void dect_transceiver_unlock(struct dect_transceiver *trx)
>> +{
>> + trx_debug(trx, "unlock\n");
>> + trx->ops->unlock(trx);
>> + trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_SCANNING;
>> + trx->state = DECT_TRANSCEIVER_UNLOCKED;
>> +}
>> +
>> +int dect_transceiver_set_band(struct dect_transceiver *trx, u8
>> bandnum)
>> +{
>> + const struct dect_band *band;
>> +
>> + band = dect_band[bandnum];
>> + if (band == NULL)
>> + return -ENOENT;
>> + trx->carriers = trx->ops->set_band(trx, band);
>> + trx->band = band;
>> + return 0;
>> +}
>> +
>> +void dect_transceiver_lock(struct dect_transceiver *trx, u8 slot)
>> +{
>> + trx_debug(trx, "lock to slot %u\n", slot);
>> + trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_IDLE;
>> + trx->state = DECT_TRANSCEIVER_LOCKED;
>> + trx->ops->lock(trx, slot);
>> +}
>> +
>> +static void dect_transceiver_set_blind(struct dect_transceiver *trx,
>> u8 slot)
>> +{
>> + u8 n = DECT_FRAME_SIZE - 1 - slot;
>> +
>> + trx->slots[slot].blinded++;
>> + trx->blind_full_slots |= 1 << n;
>> +}
>> +
>> +static void dect_transceiver_set_visible(struct dect_transceiver
>> *trx, u8 slot)
>> +{
>> + u8 n = DECT_FRAME_SIZE - 1 - slot;
>> +
>> + if (--trx->slots[slot].blinded == 0)
>> + trx->blind_full_slots &= ~(1 << n);
>> +}
>> +
>> +static bool dect_transceiver_slot_blind(const struct dect_transceiver
>> *trx, u8 slot)
>> +{
>> + u8 n = DECT_FRAME_SIZE - 1 - slot;
>> +
>> + return trx->blind_full_slots & (1 << n);
>> +}
>> +
>> +bool dect_transceiver_channel_available(const struct dect_transceiver
>> *trx,
>> + const struct dect_channel_desc
>> *chd)
>> +{
>> + u8 slot = chd->slot, prev, next;
>> +
>> + if (trx->slots[slot].state == DECT_SLOT_RX ||
>> + trx->slots[slot].state == DECT_SLOT_TX)
>> + return false;
>> +
>> + switch ((int)chd->pkt) {
>> + case DECT_PACKET_P80:
>> + case DECT_PACKET_P640j:
>> + case DECT_PACKET_P672j:
>> + if (dect_transceiver_slot_blind(trx, slot + 1))
>> + return false;
>> + case DECT_PACKET_P32:
>> + case DECT_PACKET_P08:
>> + case DECT_PACKET_P00:
>> + if (dect_transceiver_slot_blind(trx, slot))
>> + return false;
>> + break;
>> + }
>> +
>> + /* In case of slow hopping transceivers the adjacent slots
>> must be
>> + * available as well. Scanning slots are not blind, so they
>> must be
>> + * checked for explicitly.
>> + */
>> + if (trx->ops->features & DECT_TRANSCEIVER_SLOW_HOPPING) {
>> + prev = dect_prev_slotnum(slot);
>> + if (trx->slots[prev].state == DECT_SLOT_SCANNING)
>> + return false;
>> + next = dect_next_slotnum(slot);
>> + if (trx->slots[next].state == DECT_SLOT_SCANNING)
>> + return false;
>> + }
>> +
>> + return true;
>> +}
>> +
>> +static bool dect_tg_update_blind_full_slots(struct
>> dect_transceiver_group *trg)
>> +{
>> + const struct dect_transceiver *trx;
>> + u32 blind_full_slots;
>> +
>> + blind_full_slots = (~0U) & DECT_SLOT_MASK;
>> + dect_foreach_transceiver(trx, trg)
>> + blind_full_slots &= trx->blind_full_slots;
>> +
>> + if (trg->blind_full_slots != blind_full_slots) {
>> + trg->blind_full_slots = blind_full_slots;
>> + return true;
>> + } else
>> + return false;
>> +}
>> +
>> +/**
>> + * dect_transceiver_reserve - reserve transceiver resources for a
>> physical channel
>> + *
>> + * Reserve the slot positions necessary to estabish the specified
>> physical
>> + * channel. The chosen transceivers and the global groups blind full
>> slot
>> + * masks are updated.
>> + *
>> + * Returns true when the global visibility state has changed.
>> + */
>> +bool dect_transceiver_reserve(struct dect_transceiver_group *trg,
>> + struct dect_transceiver *trx,
>> + const struct dect_channel_desc *chd)
>> +{
>> + u8 slot = chd->slot;
>> +
>> + switch ((int)chd->pkt) {
>> + case DECT_PACKET_P80:
>> + case DECT_PACKET_P640j:
>> + case DECT_PACKET_P672j:
>> + dect_transceiver_set_blind(trx, slot + 1);
>> + case DECT_PACKET_P32:
>> + case DECT_PACKET_P08:
>> + case DECT_PACKET_P00:
>> + dect_transceiver_set_blind(trx, slot);
>> + break;
>> + }
>> +
>> + /* Set adjacent slots blind if the transceiver is slow hopping
>> */
>> + if (trx->ops->features & DECT_TRANSCEIVER_SLOW_HOPPING) {
>> + dect_transceiver_set_blind(trx,
>> dect_prev_slotnum(slot));
>> + dect_transceiver_set_blind(trx,
>> dect_next_slotnum(slot));
>> + }
>> +
>> + return dect_tg_update_blind_full_slots(trg);
>> +}
>> +
>> +/**
>> + * dect_transceiver_release - release transceiver resources of a
>> phyiscal channel
>> + *
>> + * Release the slot positions used by the specified physical channel.
>> The
>> + * transceiver and the global group blind full slot masks are
>> updated.
>> + *
>> + * Returns true when the global visibility state has changed.
>> + */
>> +bool dect_transceiver_release(struct dect_transceiver_group *trg,
>> + struct dect_transceiver *trx,
>> + const struct dect_channel_desc *chd)
>> +{
>> + u8 slot = chd->slot;
>> +
>> + switch ((int)chd->pkt) {
>> + case DECT_PACKET_P80:
>> + case DECT_PACKET_P640j:
>> + case DECT_PACKET_P672j:
>> + dect_transceiver_set_visible(trx, slot + 1);
>> + case DECT_PACKET_P32:
>> + case DECT_PACKET_P08:
>> + case DECT_PACKET_P00:
>> + dect_transceiver_set_visible(trx, slot);
>> + break;
>> + }
>> +
>> + /* Set adjacent slots unblind if the transceiver is slow
>> hopping */
>> + if (trx->ops->features & DECT_TRANSCEIVER_SLOW_HOPPING) {
>> + dect_transceiver_set_visible(trx,
>> dect_next_slotnum(slot));
>> + dect_transceiver_set_visible(trx,
>> dect_prev_slotnum(slot));
>> + }
>> +
>> + return dect_tg_update_blind_full_slots(trg);
>> +}
>> +
>> +struct dect_transceiver *dect_transceiver_alloc(const struct
>> dect_transceiver_ops *ops,
>> + unsigned int priv)
>> +{
>> + struct dect_transceiver *trx;
>> + unsigned int nevents, size, i;
>> +
>> + /* Allocate enough event structures for one TDMA half frame */
>> + nevents = DECT_HALF_FRAME_SIZE / ops->eventrate;
>> + size = nevents * sizeof(trx->event[0]) + priv;
>> +
>> + trx = kzalloc(sizeof(*trx) + size, GFP_KERNEL);
>> + if (trx == NULL)
>> + return NULL;
>> +
>> + trx->state = DECT_TRANSCEIVER_STOPPED;
>> + trx->ops = ops;
>> + for (i = 0; i < DECT_FRAME_SIZE; i++)
>> + trx->slots[i].chd.slot = i;
>> +
>> + for (i = 0; i < nevents; i++) {
>> + skb_queue_head_init(&trx->event[i].rx_queue);
>> + trx->event[i].trx = trx;
>> + }
>> + return trx;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_transceiver_alloc);
>> +
>> +void dect_transceiver_free(struct dect_transceiver *trx)
>> +{
>> + kfree(trx);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_transceiver_free);
>> +
>> +static int dect_transceiver_alloc_name(struct dect_transceiver *trx)
>> +{
>> + struct dect_transceiver *t;
>> + unsigned long *inuse;
>> + int i;
>> +
>> + inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
>> + if (inuse == NULL)
>> + return -ENOMEM;
>> +
>> + list_for_each_entry(t, &dect_transceiver_list, list) {
>> + if (!sscanf(t->name, "trx%d", &i))
>> + continue;
>> + if (i > BITS_PER_BYTE * PAGE_SIZE)
>> + continue;
>> + set_bit(i, inuse);
>> + }
>> +
>> + i = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
>> + free_page((unsigned long)inuse);
>> + if (i == BITS_PER_BYTE * PAGE_SIZE)
>> + return -ENFILE;
>> +
>> + snprintf(trx->name, sizeof(trx->name), "trx%d", i);
>> + return 0;
>> +}
>> +
>> +int dect_register_transceiver(struct dect_transceiver *trx)
>> +{
>> + int err;
>> +
>> + dect_lock();
>> + err = dect_transceiver_alloc_name(trx);
>> + if (err < 0)
>> + goto out;
>> +
>> + err = dect_transceiver_set_band(trx, DECT_DEFAULT_BAND);
>> + if (err < 0)
>> + goto out;
>> +
>> + list_add_tail(&trx->list, &dect_transceiver_list);
>> + dect_transceiver_notify(trx, DECT_TRANSCEIVER_REGISTER);
>> +out:
>> + dect_unlock();
>> +
>> + return err;
>> +}
>> +EXPORT_SYMBOL_GPL(dect_register_transceiver);
>> +
>> +void dect_unregister_transceiver(struct dect_transceiver *trx)
>> +{
>> + dect_lock();
>> + list_del(&trx->list);
>> + dect_transceiver_notify(trx, DECT_TRANSCEIVER_UNREGISTER);
>> + dect_unlock();
>> +
>> + synchronize_rcu();
>> + trx->ops->destructor(trx);
>> +}
>> +EXPORT_SYMBOL_GPL(dect_unregister_transceiver);
>> +
>> +/*
>> + * Transceiver netlink interface
>> + */
>> +
>> +static struct dect_transceiver *dect_transceiver_get_by_name(const
>> struct nlattr *nla)
>> +{
>> + struct dect_transceiver *trx;
>> +
>> + list_for_each_entry(trx, &dect_transceiver_list, list) {
>> + if (!nla_strcmp(nla, trx->name))
>> + return trx;
>> + }
>> + return NULL;
>> +}
>> +
>> +static int dect_fill_slot(struct sk_buff *skb,
>> + const struct dect_transceiver *trx, u8 slot)
>> +{
>> + const struct dect_transceiver_slot *ts = &trx->slots[slot];
>> +
>> + nla_put_u8(skb, DECTA_SLOT_NUM, slot);
>> + nla_put_u8(skb, DECTA_SLOT_STATE, ts->state);
>> + nla_put_u32(skb, DECTA_SLOT_FLAGS, ts->flags);
>> + if (ts->state != DECT_SLOT_IDLE) {
>> + nla_put_u8(skb, DECTA_SLOT_PACKET, ts->chd.pkt);
>> + nla_put_u8(skb, DECTA_SLOT_CARRIER, ts->chd.carrier);
>> + nla_put_u32(skb, DECTA_SLOT_FREQUENCY,
>> trx->band->frequency[ts->chd.carrier]);
>> + }
>> + if (ts->state == DECT_SLOT_RX) {
>> + nla_put_u32(skb, DECTA_SLOT_PHASEOFF, ts->phaseoff);
>> + nla_put_u8(skb, DECTA_SLOT_RSSI,
>> + ts->rssi >> DECT_RSSI_AVG_SCALE);
>> + }
>> + nla_put_u32(skb, DECTA_SLOT_RX_BYTES, ts->rx_bytes);
>> + nla_put_u32(skb, DECTA_SLOT_RX_PACKETS, ts->rx_packets);
>> + nla_put_u32(skb, DECTA_SLOT_RX_A_CRC_ERRORS,
>> ts->rx_a_crc_errors);
>> + nla_put_u32(skb, DECTA_SLOT_RX_X_CRC_ERRORS,
>> ts->rx_x_crc_errors);
>> + nla_put_u32(skb, DECTA_SLOT_RX_Z_CRC_ERRORS,
>> ts->rx_z_crc_errors);
>> + nla_put_u32(skb, DECTA_SLOT_TX_BYTES, ts->tx_bytes);
>> + nla_put_u32(skb, DECTA_SLOT_TX_PACKETS, ts->tx_packets);
>> + return 0;
>> +}
>> +
>> +static int dect_fill_transceiver(struct sk_buff *skb,
>> + const struct dect_transceiver *trx,
>> + u16 type, u32 pid, u32 seq, u16
>> flags)
>> +{
>> + const struct dect_transceiver_stats *stats = &trx->stats;
>> + struct nlattr *nest, *chan;
>> + struct nlmsghdr *nlh;
>> + struct dectmsg *dm;
>> + u8 slot;
>> +
>> + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*dm), flags);
>> + if (nlh == NULL)
>> + return -EMSGSIZE;
>> +
>> + dm = nlmsg_data(nlh);
>> +
>> + nla_put_string(skb, DECTA_TRANSCEIVER_NAME, trx->name);
>> + nla_put_string(skb, DECTA_TRANSCEIVER_TYPE, trx->ops->name);
>> + nla_put_u32(skb, DECTA_TRANSCEIVER_FEATURES,
>> trx->ops->features);
>> + if (trx->cell != NULL)
>> + nla_put_u8(skb, DECTA_TRANSCEIVER_LINK,
>> trx->cell->index);
>> +
>> + nest = nla_nest_start(skb, DECTA_TRANSCEIVER_STATS);
>> + if (nest == NULL)
>> + goto nla_put_failure;
>> + nla_put_u32(skb, DECTA_TRANSCEIVER_STATS_EVENT_BUSY,
>> stats->event_busy);
>> + nla_put_u32(skb, DECTA_TRANSCEIVER_STATS_EVENT_LATE,
>> stats->event_late);
>> + nla_nest_end(skb, nest);
>> +
>> + nla_put_u8(skb, DECTA_TRANSCEIVER_BAND, trx->band->band);
>> +
>> + nest = nla_nest_start(skb, DECTA_TRANSCEIVER_SLOTS);
>> + if (nest == NULL)
>> + goto nla_put_failure;
>> + for (slot = 0; slot < DECT_FRAME_SIZE; slot++) {
>> + chan = nla_nest_start(skb, DECTA_LIST_ELEM);
>> + if (chan == NULL)
>> + goto nla_put_failure;
>> + if (dect_fill_slot(skb, trx, slot) < 0)
>> + goto nla_put_failure;
>> + nla_nest_end(skb, chan);
>> + }
>> + nla_nest_end(skb, nest);
>> +
>> + return nlmsg_end(skb, nlh);
>> +
>> +nla_put_failure:
>> + nlmsg_cancel(skb, nlh);
>> + return -EMSGSIZE;
>> +}
>> +
>> +static const struct nla_policy
>> dect_transceiver_policy[DECTA_TRANSCEIVER_MAX + 1] = {
>> + [DECTA_TRANSCEIVER_NAME] = { .type = NLA_STRING, .len =
>> DECTNAMSIZ },
>> + [DECTA_TRANSCEIVER_LINK] = { .type = NLA_U8 },
>> +};
>> +
>> +static int dect_new_transceiver(const struct sk_buff *in_skb,
>> + const struct nlmsghdr *nlh,
>> + const struct nlattr
>> *tb[DECTA_TRANSCEIVER_MAX + 1])
>> +{
>> + struct dect_transceiver *trx;
>> + struct dect_cell *cell;
>> + struct dectmsg *dm;
>> + int index;
>> +
>> + dm = nlmsg_data(nlh);
>> +
>> + if (tb[DECTA_TRANSCEIVER_NAME] == NULL)
>> + return -EINVAL;
>> +
>> + trx =
>> dect_transceiver_get_by_name(tb[DECTA_TRANSCEIVER_NAME]);
>> + if (trx == NULL) {
>> + if (nlh->nlmsg_flags & NLM_F_CREATE)
>> + return -EOPNOTSUPP;
>> + return -ENOENT;
>> + }
>> + if (nlh->nlmsg_flags & NLM_F_EXCL)
>> + return -EEXIST;
>> +
>> + if (tb[DECTA_TRANSCEIVER_LINK] != NULL) {
>> + index = nla_get_u8(tb[DECTA_TRANSCEIVER_LINK]);
>> + if (index == -1)
>> + dect_cell_detach_transceiver(trx->cell, trx);
>> + else {
>> + cell = dect_cell_get_by_index(index);
>> + if (cell == NULL)
>> + return -ENOENT;
>> + return dect_cell_attach_transceiver(cell,
>> trx);
>> + }
>> + }
>> + return 0;
>> +}
>> +
>> +static int dect_get_transceiver(const struct sk_buff *in_skb,
>> + const struct nlmsghdr *nlh,
>> + const struct nlattr
>> *tb[DECTA_TRANSCEIVER_MAX + 1])
>> +{
>> + u32 pid = NETLINK_CB(in_skb).portid;
>> + const struct dect_transceiver *trx;
>> + struct sk_buff *skb;
>> + int err;
>> +
>> + if (tb[DECTA_TRANSCEIVER_NAME] == NULL)
>> + return -EINVAL;
>> +
>> + trx =
>> dect_transceiver_get_by_name(tb[DECTA_TRANSCEIVER_NAME]);
>> + if (trx == NULL)
>> + return -ENOENT;
>> +
>> + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (skb == NULL)
>> + return -ENOMEM;
>> + err = dect_fill_transceiver(skb, trx, DECT_NEW_TRANSCEIVER,
>> 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 int dect_dump_transceiver(struct sk_buff *skb,
>> + struct netlink_callback *cb)
>> +{
>> + const struct dect_transceiver *trx;
>> + unsigned int idx, s_idx;
>> +
>> + s_idx = cb->args[0];
>> + idx = 0;
>> + list_for_each_entry(trx, &dect_transceiver_list, list) {
>> + if (idx < s_idx)
>> + goto cont;
>> + if (dect_fill_transceiver(skb, trx,
>> DECT_NEW_TRANSCEIVER,
>> + 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_transceiver(u16 event, const struct
>> dect_transceiver *trx,
>> + 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_transceiver(skb, trx, event, pid, seq,
>> NLMSG_DONE);
>> + if (err < 0) {
>> + WARN_ON(err == -EMSGSIZE);
>> + kfree_skb(skb);
>> + goto err;
>> + }
>> + nlmsg_notify(dect_nlsk, skb, pid, DECTNLGRP_TRANSCEIVER,
>> report, GFP_KERNEL);
>> +err:
>> + if (err < 0)
>> + netlink_set_err(dect_nlsk, pid, DECTNLGRP_TRANSCEIVER,
>> err);
>> +}
>> +
>> +static int dect_transceiver_notify(struct dect_transceiver *trx,
>> + unsigned long event)
>> +{
>> + struct dect_cell *cell = trx->cell;
>> +
>> + switch (event) {
>> + case DECT_TRANSCEIVER_REGISTER:
>> + dect_notify_transceiver(DECT_NEW_TRANSCEIVER, trx,
>> NULL, 0);
>> + break;
>> + case DECT_TRANSCEIVER_UNREGISTER:
>> + if (cell != NULL)
>> + dect_cell_detach_transceiver(cell, trx);
>> + dect_notify_transceiver(DECT_DEL_TRANSCEIVER, trx,
>> NULL, 0);
>> + break;
>> + }
>> + return 0;
>> +};
>> +
>> +
>> +static const struct dect_netlink_handler dect_transceiver_handlers[]
>> = {
>> + {
>> + /* DECT_NEW_TRANSCEIVER */
>> + .policy = dect_transceiver_policy,
>> + .maxtype = DECTA_TRANSCEIVER_MAX,
>> + .doit = dect_new_transceiver,
>> + },
>> + {
>> + /* DECT_DEL_TRANSCEIVER */
>> + },
>> + {
>> + /* DECT_GET_TRANSCEIVER */
>> + .policy = dect_transceiver_policy,
>> + .maxtype = DECTA_TRANSCEIVER_MAX,
>> + .doit = dect_get_transceiver,
>> + .dump = dect_dump_transceiver,
>> + },
>> +};
>> +
>> +/*
>> + * RF-bands:
>> + */
>> +
>> +struct dect_band_desc {
>> + u8 band;
>> + u8 carriers;
>> + s16 c1_off;
>> + u8 c2;
>> + s16 c2_off;
>> +};
>> +
>> +static const struct dect_band_desc dect_band_desc[] __initdata = {
>> + /* 1880 MHz to 1900 MHz RF band 00000 */
>> + { 0, 10, 0, -1, 0, },
>> + /* 1880 MHz to 1978 MHz and 2010 MHz to 2025 MHz RF band 00001
>> */
>> + { 1, 64, 0, 56, 19, },
>> + /* 1880 MHz to 1925 MHz and 2010 MHz to 2025 MHz RF band 00010
>> */
>> + { 2, 33, 0, 25, 50, },
>> + /* 1880 MHz to 1900 MHz, 1915 MHz to 1940 MHz and 2010 MHz to
>> + * 2025 MHz RF band 00011 */
>> + { 3, 33, 10, 25, 50, },
>> + /* 1880 MHz to 1900 MHz, 1935 MHz to 1960 MHz and 2010 MHz to
>> + * 2025 MHz RF band 00100 */
>> + { 4, 33, 22, 25, 50, },
>> + /* 1880 MHz to 1900 MHZ, 1955 MHz to 1980 MHz and 2010 MHz to
>> + * 2025 MHz RF band 00101 */
>> + { 5, 33, 34, 25, 50, },
>> + /* 902 MHz to 928 MHz RF band 01000 */
>> + { 8, 24, -576, -1, 0, },
>> + /* 2400 MHz to 2483,5 MHz RF band 01001 */
>> + { 9, 55, 292, -1, 0, },
>> +};
>> +
>> +/*
>> + * A nominal DECT RF carrier is one whose center frequency is
>> generated by
>> + * the formula:
>> + *
>> + * Fg = F0 - g × 1,728 MHz, where g is any integer
>> + */
>> +static u32 __init dect_calc_frequency(s16 g)
>> +{
>> + if (g >= 0 && g < 10)
>> + return DECT_FREQUENCY_F0 - g * DECT_CARRIER_WIDTH;
>> + else
>> + return DECT_FREQUENCY_F0 + (g - 9) *
>> DECT_CARRIER_WIDTH;
>> +}
>> +
>> +static int __init dect_init_band(const struct dect_band_desc *desc)
>> +{
>> + struct dect_band *band;
>> + unsigned int size;
>> + u8 carrier;
>> +
>> + size = sizeof(*band) + desc->carriers *
>> sizeof(band->frequency[0]);
>> + band = kmalloc(size, GFP_KERNEL);
>> + if (band == NULL)
>> + return -ENOMEM;
>> +
>> + band->band = desc->band;
>> + band->carriers = desc->carriers;
>> +
>> + for (carrier = 0; carrier < 10; carrier++)
>> + band->frequency[carrier] =
>> + dect_calc_frequency(carrier);
>> +
>> + for (; carrier < min(desc->carriers, desc->c2); carrier++)
>> + band->frequency[carrier] =
>> + dect_calc_frequency(carrier + desc->c1_off);
>> +
>> + for (; carrier < desc->carriers; carrier++)
>> + band->frequency[carrier] =
>> + dect_calc_frequency(carrier + desc->c2_off);
>> +
>> + printk("RF-band %u:\n", band->band);
>> + for (carrier = 0; carrier < band->carriers; carrier++) {
>> + printk(" carrier %u: %u.%03uMHz\n", carrier,
>> + band->frequency[carrier] / 1000,
>> + band->frequency[carrier] % 1000);
>> + }
>> + printk("\n");
>> +
>> + dect_band[band->band] = band;
>> + return 0;
>> +}
>> +
>> +int __init dect_transceiver_module_init(void)
>> +{
>> + unsigned int i;
>> + int err;
>> +
>> + for (i = 0; i < ARRAY_SIZE(dect_band_desc); i++) {
>> + err = dect_init_band(&dect_band_desc[i]);
>> + if (err < 0)
>> + goto err1;
>> + }
>> +
>> + dect_netlink_register_handlers(dect_transceiver_handlers,
>> + DECT_NEW_TRANSCEIVER,
>> +
>> ARRAY_SIZE(dect_transceiver_handlers));
>> + return 0;
>> +
>> +err1:
>> + dect_transceiver_module_exit();
>> + return err;
>> +}
>> +
>> +void dect_transceiver_module_exit(void)
>> +{
>> + u8 band;
>> +
>> + dect_netlink_unregister_handlers(DECT_NEW_TRANSCEIVER,
>> +
>> ARRAY_SIZE(dect_transceiver_handlers));
>> +
>> + for (band = 0; band < ARRAY_SIZE(dect_band); band++)
>> + kfree(dect_band[band]);
>> +}
>> diff --git a/target/linux/generic/patches-3.10/780-dect-support.patch
>> b/target/linux/generic/patches-3.10/780-dect-support.patch
>> new file mode 100644
>> index 0000000..6524db5
>> --- /dev/null
>> +++ b/target/linux/generic/patches-3.10/780-dect-support.patch
>> @@ -0,0 +1,155 @@
>> +