commit 902da5b9f598c35c6d8dac37e443a323d3e122a7 Author: Patrick McHardy Date: Thu Oct 28 01:31:00 2010 +0200 Import dectmon Signed-off-by: Patrick McHardy diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe7e376 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Dependency and object files +.*.d +*.o + +# Generated by autoconf/configure +Makefile +Makefile.defs +Makefile.rules +config.h +config.h.in +config.h.in~ +config.log +config.status +configure +autom4te.cache + +# vim swap files +.*.swp diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..e90dfed --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile.defs.in b/Makefile.defs.in new file mode 100644 index 0000000..af20d76 --- /dev/null +++ b/Makefile.defs.in @@ -0,0 +1,46 @@ +DEBUG = @CONFIG_DEBUG@ +CC = @CC@ +CPP = @CPP@ +LEX = @LEX@ +YACC = @YACC@ +MKDIR_P = @MKDIR_P@ +LN_S = @LN_S@ +INSTALL = @INSTALL@ +DOXYGEN = @DOXYGEN@ + +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +docdir = @docdir@ +pdfdir = @pdfdir@ +confdir = @sysconfdir@/dect + +LDFLAGS += @LDFLAGS@ +LDFLAGS += @LIBS@ + +CPPFLAGS += @CPPFLAGS@ + +CFLAGS += @CFLAGS@ @DEFS@ +CFLAGS += -include config.h -I include +CFLAGS += -fvisibility=hidden +CFLAGS += -fstack-protector-all + +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations +CFLAGS += -Wdeclaration-after-statement -Wsign-compare -Winit-self +CFLAGS += -Wformat-nonliteral -Wformat-security -Wmissing-format-attribute +CFLAGS += -Wcast-align -Wundef -Wbad-function-cast # -Wshadow +CFLAGS += -Waggregate-return -Wunused -Wwrite-strings + +ifeq ($(DEBUG),y) +CFLAGS += -g -DDEBUG +endif + +EVENT_CFLAGS += @EVENT_CFLAGS@ +EVENT_LDFLAGS += @EVENT_LDFLAGS@ diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..7f0b0c9 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,3 @@ +SUBDIRS += src + +include Makefile.rules diff --git a/Makefile.rules.in b/Makefile.rules.in new file mode 100644 index 0000000..411f47b --- /dev/null +++ b/Makefile.rules.in @@ -0,0 +1,114 @@ +include Makefile.defs + +makedeps += $(SUBDIR)Makefile +makedeps += Makefile +makedeps += Makefile.defs +makedeps += Makefile.rules + +configure: configure.ac + sh autogen.sh + +%: %.in configure + sh configure + +%.o: %.c $(makedeps) + @/bin/echo -e " CC\t\t$<" + $(CC) $(CFLAGS) -c -o $@ $< + +.%.d: %.c $(makedeps) + @/bin/echo -e " DEP\t\t$<" + $(RM) $@ + $(CC) -M $(CFLAGS) $< | sed 's,$(*F)\.o[ :]*,$*.o $@ : ,g' > $@ + +%.c %.h: %.y $(makedeps) + @/bin/echo -e " YACC\t\t$<" + $(YACC) $(YACCFLAGS) -d -o $@ $< + +%.c %.h: %.l $(makedeps) + @/bin/echo -e " LEX\t\t$<" + $(LEX) -t --header-file=$(<:.l=.h) $< > $@ + +%.8: %.xml $(makedeps) + @/bin/echo -e " MAN\t\t$<" + docbook2x-man $< + +%.pdf: %.xml $(makedeps) + @/bin/echo -e " PDF\t\t$<" + db2pdf $< + +define generic_template +$(1)-obj := $$(patsubst %,$(SUBDIR)%,$$($(1)-obj)) +$(1)-depfiles := $$(patsubst $(SUBDIR)%.o,$(SUBDIR).%.d,$$($(1)-obj)) + +.PHONY: $(1)-clean +$(1)-clean: + @/bin/echo -e " CLEAN\t\t$(1)" + $$(RM) $$($(1)-obj) $$($(1)-depfiles) \ + $$($(1)-clean_files) $$($(1)-extra-clean-files) +clean_targets += $(1)-clean + +.PHONY: $(1)-install + +ifneq ($(MAKECMDGOALS),clean) +-include $$($(1)-depfiles) +endif +endef + +define program_template +$(eval $(call generic_template,$(1))) + +$(SUBDIR)$(1): $$($(1)-extra-targets) $$($(1)-obj) + @/bin/echo -e " LD\t\t$$@" + $$(CC) $$($(1)-obj) $$($(1)-ldflags) $$(LDFLAGS) -o $$@ +all_targets += $(SUBDIR)$(1) + +$(1)-clean_files += $(SUBDIR)$(1) + +$(1)-install: + @/bin/echo -e " INSTALL\t$1" + $(MKDIR_P) $$(DESTDIR)/$$($(1)-destdir) + $(INSTALL) -m 755 -o root -g root $(SUBDIR)$(1) \ + $$(DESTDIR)/$$($(1)-destdir)/$(1) +install_targets += $(1)-install +endef + +define library_template +$(eval $(call generic_template,$(1))) + +$(SUBDIR)lib$(1).so: $$($(1)-extra-targets) $$($(1)-obj) + @/bin/echo -e " LD\t\t$$@" + $$(CC) -shared -Wl,-soname,lib$(1).so.0 $$($(1)-obj) $$($(1)-ldflags) $$(LDFLAGS) -o $$@ + $(LN_S) -f lib$(1).so $$@.0 +all_targets += $(SUBDIR)lib$(1).so + +$(1)-clean_files += $(SUBDIR)lib$(1).so $(SUBDIR)lib$(1).so.0 + +$(1)-install: + @/bin/echo -e " INSTALL\t$1" + $(MKDIR_P) $$(DESTDIR)/$$($(1)-destdir) + $(INSTALL) -m 755 -o root -g root $(SUBDIR)lib$(1).so \ + $$(DESTDIR)/$$($(1)-destdir)/lib$(1).so.$(PACKAGE_VERSION) + $(LN_S) -f lib$(1).so.$(PACKAGE_VERSION) \ + $(DESTDIR)/$$($(1)-destdir)/lib$(1).so.0 + $(LN_S) -f lib$(1).so.$(PACKAGE_VERSION) \ + $(DESTDIR)/$$($(1)-destdir)/lib$(1).so +install_targets += $(1)-install +endef + +ifneq ($(SUBDIR),) +include $(SUBDIR)/Makefile +$(foreach prog,$(PROGRAMS),$(eval $(call program_template,$(prog)))) +$(foreach lib,$(LIBS),$(eval $(call library_template,$(lib)))) +endif + +.DEFAULT_GOAL := all + +.PHONY: all clean install +all: $(SUBDIRS) $(all_targets) +clean: $(SUBDIRS) $(clean_targets) +install: all $(SUBDIRS) $(install_targets) + +.PHONY: $(SUBDIRS) +$(SUBDIRS): + @/bin/echo -e " SUBDIR\t$@/" + @$(MAKE) -s -f Makefile.rules $(MAKECMDGOALS) SUBDIR="$@/" SUBDIRS="" diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..7d2e816 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +autoreconf -fi; +rm -Rf autom4te*.cache config.h.in~ diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..abbde70 --- /dev/null +++ b/configure.ac @@ -0,0 +1,95 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) + +AC_COPYRIGHT([Copyright (c) 2008 Patrick McHardy ]) +AC_INIT([libdect], [0.0.1], [kaber@trash.net]) +AC_DEFINE([RELEASE_NAME], ["libdect"], [Release name]) + +AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_HEADER([config.h]) + +AC_DEFINE([_GNU_SOURCE], [], [Enable various GNU extensions]) +AC_DEFINE([_STDC_FORMAT_MACROS], [], [printf-style format macros]) + +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug], [enable debugging [yes]]), + [CONFIG_DEBUG="$(echo $enableval | cut -b1)"], + [CONFIG_DEBUG="y"]) +AC_SUBST([CONFIG_DEBUG]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_MKDIR_P +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_SED + +AC_ARG_ENABLE([doc], + AS_HELP_STRING([--enable-doc], [build documentation [no]]), + AC_CHECK_PROG(DOXYGEN, doxygen, doxygen), + AC_MSG_NOTICE([Documentation build disabled]) + DOXYGEN=/bin/true) + +# Checks for libraries. +AC_CHECK_LIB([nl], [nl_socket_alloc], , + AC_MSG_ERROR([No suitable version of libnl found])) + +AC_CHECK_LIB([nl-dect], [nl_dect_cluster_alloc], , + AC_MSG_ERROR([No suitable version of libnl-dect found])) + +AC_CHECK_LIB(ev, event_init, + [EVENTLIB="-lev"], + [AC_CHECK_LIB([event], [event_init], + [EVENTLIB="-levent"], + [AC_ERROR([libev or libevent not found])])]) +EVENT_LDFLAGS=$EVENTLIB +AC_SUBST(EVENT_LDFLAGS) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_ASSERT +AC_CHECK_HEADERS([fcntl.h inttypes.h libintl.h limits.h malloc.h \ + stddef.h stdint.h stdlib.h string.h unistd.h \ + sys/socket.h], , + AC_MSG_ERROR([Header file not found])) +AC_CHECK_HEADERS([linux/dect.h linux/dect_netlink.h], , + AC_MSG_ERROR([DECT kernel header files not found]), + [#include ]) + +AC_CHECK_HEADER([event.h], + [EVENTINC="-include event.h"], + [AC_CHECK_HEADER([libev/event.h], + [EVENTINC="-include libev/event.h"], + [AC_MSG_ERROR([event.h not found])])]) +EVENT_CFLAGS=$EVENTINC +AC_SUBST(EVENT_CFLAGS) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_C_INLINE +AC_C_TYPEOF + +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UID_T +AC_TYPE_INT8_T +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T + +# Checks for library functions. +# AC_FUNC_MALLOC +# AC_FUNC_REALLOC +AC_CHECK_FUNCS([memmove memset strchr strdup strerror strtoull]) + +AC_CONFIG_FILES([Makefile Makefile.defs Makefile.rules]) +AC_CONFIG_FILES([src/Makefile]) +AC_OUTPUT diff --git a/include/dectmon.h b/include/dectmon.h new file mode 100644 index 0000000..e3d9aa1 --- /dev/null +++ b/include/dectmon.h @@ -0,0 +1,101 @@ +#ifndef _DECTMON_H +#define _DECTMON_H + +#include +#include +#include + +extern struct dect_handle *dh; + +enum { + DECTMON_DUMP_MAC = 0x1, + DECTMON_DUMP_DLC = 0x2, + DECTMON_DUMP_NWK = 0x4, +}; + +extern uint32_t dumpopts; + +struct dect_ops; +extern int dect_event_ops_init(struct dect_ops *ops); +extern void dect_event_loop_stop(void); +extern void dect_event_loop(void); +extern void dect_event_ops_cleanup(void); +extern void dect_dummy_ops_init(struct dect_ops *ops); + +extern void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size); + +enum dect_mm_procedures { + DECT_MM_NONE, + DECT_MM_KEY_ALLOCATION, + DECT_MM_AUTHENTICATION, + DECT_MM_CIPHERING, +}; + + +struct dect_pt { + struct list_head list; + struct dect_ie_portable_identity *portable_identity; + struct dect_tbc *tbc; + + uint8_t uak[DECT_AUTH_KEY_LEN]; + uint8_t dck[DECT_CIPHER_KEY_LEN]; + + enum dect_mm_procedures procedure; + uint8_t last_msg; + + struct dect_ie_auth_type *auth_type; + struct dect_ie_auth_value *rand_f; + struct dect_ie_auth_value *rs; + struct dect_ie_auth_res *res; +}; + +/* DLC */ + +struct dect_dl { + struct dect_pt *pt; + struct dect_tbc *tbc; +}; + +struct dect_msg_buf; +extern void dect_dl_data_ind(struct dect_dl *dl, struct dect_msg_buf *mb); + +struct dect_lc { + uint16_t lsig; + struct dect_msg_buf *rx_buf; + uint8_t rx_len; +}; + +struct dect_mac_con { + struct dect_lc *lc; + uint32_t pmid; + struct dect_tbc *tbc; +}; + +enum dect_data_channels; +extern void dect_mac_co_data_ind(struct dect_mac_con *mc, + enum dect_data_channels chan, + struct dect_msg_buf *mb); + +/* MAC */ + +struct dect_mbc { + bool cs_seq; + bool cf_seq; + struct dect_mac_con mc; +}; + +struct dect_tbc { + struct dect_mbc mbc[2]; + struct dect_dl dl; + bool ciphered; +}; + +extern void dect_mac_rcv(struct dect_msg_buf *mb, uint8_t slot); + +/* DSC */ + +extern void dect_dsc_keystream(uint64_t iv, const uint8_t *key, + uint8_t *output, unsigned int len); +extern uint64_t dect_dsc_iv(uint32_t mfn, uint8_t framenum); + +#endif /* _DECTMON_H */ diff --git a/include/dlc.h b/include/dlc.h new file mode 100644 index 0000000..f9f393b --- /dev/null +++ b/include/dlc.h @@ -0,0 +1,463 @@ +/* + * DECT DLC Layer + * + * Copyright (c) 2009 Patrick McHardy + */ + +#ifndef _NET_DECT_DLC_H +#define _NET_DECT_DLC_H + +/* + * C-Plane data link service + */ + +/* + * FA-Frame + */ + +#define DECT_FA_HDR_SIZE 3 + +struct dect_fa_hdr { + uint8_t addr; + uint8_t ctrl; + uint8_t 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 { + uint8_t 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) + */ +#if 0 +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; + uint8_t v_s; + uint8_t v_a; + uint8_t v_r; + + bool busy; + bool peer_busy; + + uint8_t window; + uint8_t mod; + + uint8_t retransmit_cnt; + struct sk_buff_head retransmit_queue; + struct timer_list timer; + + struct sk_buff *rcv_head; +}; +#endif + +/* 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) + +#if 0 +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; + uint16_t lsig; + + struct sk_buff *rx_head; + uint8_t rx_len; + + struct sk_buff_head txq; + struct sk_buff *tx_head; + uint8_t tx_len; + + uint8_t use; + struct dect_lapc *lapcs[DECT_LLN_MAX + 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 + +/** + * 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; + + uint8_t 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); + +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 + +#endif /* _NET_DECT_DLC_H */ diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..5405dbb --- /dev/null +++ b/include/list.h @@ -0,0 +1,636 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include + +#define prefetch(x) ((void)0) + +#define LIST_POISON1 ((void *)0x12345678) +#define LIST_POISON2 ((void *)0x87654321) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void init_list_head(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + init_list_head(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + init_list_head(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + init_list_head(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + init_list_head(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + init_list_head(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } + +#define init_hlist_head(ptr) ((ptr)->first = NULL) + +static inline void init_hlist_node(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + init_hlist_node(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif diff --git a/include/mac.h b/include/mac.h new file mode 100644 index 0000000..6400392 --- /dev/null +++ b/include/mac.h @@ -0,0 +1,936 @@ +/* + * DECT MAC Layer - Header and global definitions + * + * Copyright (c) 2009 Patrick McHardy + */ + +#ifndef _NET_DECT_MAC_H +#define _NET_DECT_MAC_H + +#include +#include + +#define DECT_FRAME_SIZE 24 +#define DECT_HALF_FRAME_SIZE (DECT_FRAME_SIZE / 2) + +/* + * 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 + +/* + * 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 + +struct dect_ari_ { + enum dect_ari_classes arc; + uint32_t fpn; + uint32_t fps; + union { + uint16_t emc; + uint16_t eic; + uint16_t poc; + uint32_t gop; + uint16_t fil; + }; +}; + +#if 0 +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, +}; +#endif + +/* + * RFPI + */ + +#define DECT_RFPI_E_FLAG 0x8000000000000000ULL +#define DECT_RFPI_ARI_SHIFT 1 +#define DECT_RFPI_RPN_SHIFT 24 + +/** + * @e: indicates whether SARIs are available + * @pari: primary access rights identifier + * @rpn: radio part number + */ +struct dect_idi { + bool e; + struct dect_ari pari; + uint8_t 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 0xf000000000000000ULL +#define DECT_QT_H_SHIFT 60 + +/** + * 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 0x1000000000000000ULL + +/* slot number */ +#define DECT_QT_SSI_SN_MASK 0x0f00000000000000ULL +#define DECT_QT_SSI_SN_SHIFT 56 + +/* start position */ +#define DECT_QT_SSI_SP_MASK 0x00c0000000000000ULL +#define DECT_QT_SSI_SP_SHIFT 54 + +/* escape bit */ +#define DECT_QT_SSI_ESC_FLAG 0x0020000000000000ULL + +/* number of transceivers */ +#define DECT_QT_SSI_TXS_MASK 0x0018000000000000ULL +#define DECT_QT_SSI_TXS_SHIFT 51 + +/* extended RF carrier information available */ +#define DECT_QT_SSI_MC_FLAG 0x0004000000000000ULL + +/* RF carriers available */ +#define DECT_QT_SSI_RFCARS_MASK 0x0003ff0000000000ULL +#define DECT_QT_SSI_RFCARS_SHIFT 40 + +/* carrier number */ +#define DECT_QT_SSI_CN_MASK 0x0000003f00000000ULL +#define DECT_QT_SSI_CN_SHIFT 32 + +/* primary scan carrier number */ +#define DECT_QT_SSI_PSCN_MASK 0x000000003f000000ULL +#define DECT_QT_SSI_PSCN_SHIFT 24 + +struct dect_ssi { + bool nr; + bool mc; + uint16_t rfcars; + uint8_t sn; + uint8_t sp; + uint8_t txs; + uint8_t cn; + uint8_t pscn; +}; + +/* + * Extended RF carrier information + */ + +#define DECT_QT_ERFC_FREQ 8 + +#define DECT_QT_ERFC_RFCARS_MASK 0x0fffffe000000000ULL +#define DECT_QT_ERFC_RFCARS_SHIFT 9 + +#define DECT_QT_ERFC_RFBAND_MASK 0x0000001f00000000ULL +#define DECT_QT_ERFC_RFBAND_SHIFT 32 + +#define DECT_QT_ERFC_ERFC2_FLAG 0x0000000080000000ULL + +#define DECT_QT_ERFC_NUM_RFCARS_MASK 0x000000003f000000ULL +#define DECT_QT_ERFC_NUM_RFCARS_SHIFT 24 + +struct dect_erfc { + uint32_t rfcars; + uint8_t band; + uint8_t num_rfcars; + bool erfc2; +}; + +/* + * Fixed Part capabilities + */ + +#define DECT_QT_FPC_FREQ 8 + +#define DECT_QT_FPC_CAPABILITY_MASK 0x0fffff0000000000ULL +#define DECT_QT_FPC_CAPABILITY_SHIFT 40 + +#define DECT_QT_FPC_HLC_MASK 0x000000ffff000000ULL +#define DECT_QT_FPC_HLC_SHIFT 24 + +struct dect_fpc { + uint32_t fpc; + uint16_t hlc; +}; + +/* + * Extended Fixed Part capabilities + */ + +#define DECT_QT_EFPC_EFPC_MASK 0x0fff800000000000ULL +#define DECT_QT_EFPC_EFPC_SHIFT 47 + +#define DECT_QT_EFPC_EHLC_MASK 0x00007fffff000000ULL +#define DECT_QT_EFPC_EHLC_SHIFT 24 + +struct dect_efpc { + uint16_t fpc; + uint32_t hlc; +}; + +#define DECT_QT_EFPC2_FPC_MASK 0x0fff000000000000ULL +#define DECT_QT_EFPC2_FPC_SHIFT 48 + +#define DECT_QT_EFPC2_HLC_MASK 0x0000ffffff000000ULL +#define DECT_QT_EFPC2_HLC_SHIFT 24 + +struct dect_efpc2 { + uint16_t fpc; + uint32_t hlc; +}; + +/* + * SARI message + */ + +#define DECT_QT_SARI_FREQ 4 + +#define DECT_QT_SARI_LIST_CYCLE_MASK 0x000e000000000000ULL +#define DECT_QT_SARI_LIST_CYCLE_SHIFT 49 + +#define DECT_QT_SARI_TARI_FLAG 0x0001000000000000ULL + +#define DECT_QT_SARI_BLACK_FLAG 0x0000800000000000ULL + +#define DECT_QT_SARI_ARI_MASK 0x00007fffffff0000ULL +#define DECT_QT_SARI_ARI_SHIFT 17 + +struct dect_sari { + uint8_t 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 0x0000ffffff000000ULL +#define DECT_QT_MFN_SHIFT 24 + +struct dect_mfn { + uint32_t num; +}; + +/* + * Extended RF carrier information part 2 + */ + +#define DECT_QT_TXI_ERFC2_FREQ 8 + +#define DECT_QT_ERFC2_RFCARS_MASK 0x0fffffffe0000000ULL +#define DECT_QT_ERFC2_RFCARS_SHIFT 29 + +struct dect_erfc2 { + uint32_t rfcars; +}; + +/* + * Transmit Information + */ + +#define DECT_QT_TXI_FREQ 8 + +#define DECT_QT_TXI_TYPE_MASK 0x0f00000000000000ULL +#define DECT_QT_TXI_TYPE_SHIFT 56 + +#define DECT_QT_TXI_PWL_MASK 0x00ff000000000000ULL +#define DECT_QT_TXI_PWL_SHIFT 48 + +/* + * Extended fixed part capabilitiees part 2 + */ + +/* + * Paging Tail (P-channel) + */ + +#define DECT_PT_HDR_EXTEND_FLAG 0x8000000000000000ULL + +#define DECT_PT_HDR_LENGTH_MASK 0x7000000000000000ULL +#define DECT_PT_HDR_LENGTH_SHIFT 60 + +/** + * @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 0x0fffff0000000000ULL +#define DECT_PT_ZP_RFPI_SHIFT 40 + +/* short page B_S channel data */ +#define DECT_PT_SP_BS_DATA_MASK 0x0fffff0000000000ULL +#define DECT_PT_SP_BS_DATA_SHIFT 40 +#define DECT_PT_SP_BS_DATA_SIZE 3 + +/* long and full page B_S channel data */ +#define DECT_PT_LFP_BS_DATA_MASK 0x0fffffffff000000ULL +#define DECT_PT_LFP_BS_DATA_SHIFT 24 +#define DECT_PT_LFP_BS_DATA_SIZE 5 + +struct dect_page { + bool extend; + enum dect_page_lengths length; + uint32_t rfpi; +}; + +/* MAC layer information */ +#define DECT_PT_INFO_TYPE_MASK 0x000000f000000000ULL +#define DECT_PT_INFO_TYPE_SHIFT 36 +#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 0x0000000fff000000ULL +#define DECT_PT_BFS_SHIFT 24 + +struct dect_bfs { + struct dect_page page; + uint16_t mask; +}; + +/* Bearer description */ +#define DECT_PT_BEARER_SN_MASK 0x0000000f00000000ULL +#define DECT_PT_BEARER_SN_SHIFT 32 + +#define DECT_PT_BEARER_SP_MASK 0x00000000c0000000ULL +#define DECT_PT_BEARER_SP_SHIFT 30 + +#define DECT_PT_BEARER_CN_MASK 0x000000003f000000ULL +#define DECT_PT_BEARER_CN_SHIFT 24 + +struct dect_bearer_desc { + struct dect_page page; + enum dect_pt_info_types bt; + uint8_t sn; + uint8_t sp; + uint8_t cn; +}; + +/* RFP identity */ +#define DECT_PT_RFP_ID_MASK 0x0000000fff000000ULL +#define DECT_PT_RFP_ID_SHIFT 24 + +struct dect_rfp_id { + struct dect_page page; + uint16_t id; +}; + +/* RFP status */ +#define DECT_PT_RFPS_RFP_BUSY_FLAG 0x0000000100000000ULL +#define DECT_PT_RFPS_SYS_BUSY_FLAG 0x0000000200000000ULL + +struct dect_rfp_status { + struct dect_page page; + bool rfp_busy; + bool sys_busy; +}; + +/* Active carriers */ +#define DECT_PT_ACTIVE_CARRIERS_MASK 0x0000000ffc000000ULL +#define DECT_PT_ACTIVE_CARRIERS_SHIFT 26 + +struct dect_active_carriers { + struct dect_page page; + uint16_t active; +}; + +/* + * MAC control (M-channel) + */ + +#define DECT_MT_FRAME_RATE 2 + +#define DECT_MT_HDR_MASK 0xf000000000000000ULL +#define DECT_MT_HDR_SHIFT 60 + +#define DECT_MT_CMD_MASK 0x0f00000000000000ULL +#define DECT_MT_CMD_SHIFT 56 + +/** + * 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 0x00fff00000000000ULL +#define DECT_CCTRL_FMID_SHIFT 44 + +#define DECT_CCTRL_PMID_MASK 0x00000fffff000000ULL +#define DECT_CCTRL_PMID_SHIFT 24 + +/* Attributes-T request/confirm */ +#define DECT_CCTRL_ATTR_ECN_MASK 0x00f0000000000000ULL +#define DECT_CCTRL_ATTR_ECN_SHIFT 52 + +#define DECT_CCTRL_ATTR_LBN_MASK 0x000f000000000000ULL +#define DECT_CCTRL_ATTR_LBN_SHIFT 48 + +#define DECT_CCTRL_ATTR_TYPE_MASK 0x0000c00000000000ULL +#define DECT_CCTRL_ATTR_TYPE_SHIFT 46 + +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 0x00003f0000000000ULL +#define DECT_CCTRL_ATTR_SERVICE_SHIFT 40 + +enum dect_mac_service_types { + DECT_SERVICE_IN_MIN_DELAY = 0x0, + DECT_SERVICE_IPX_ENCODED_PROTECTED = 0x1, + DECT_SERVICE_IN_NORM_DELAY = 0x2, + DECT_SERVICE_UNKNOWN = 0x4, + DECT_SERVICE_C_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, +}; + +#define DECT_SERVICE_LIFETIME_MASK = 0x7 + +#define DECT_CCTRL_ATTR_SLOT_MASK 0x000000f000000000ULL +#define DECT_CCTRL_ATTR_SLOT_SHIFT 36 + +#define DECT_CCTRL_ATTR_CF_FLAG 0x0000000800000000ULL + +#define DECT_CCTRL_ATTR_BZ_EXT_MOD_MASK 0x0000000700000000ULL +#define DECT_CCTRL_ATTR_BZ_EXT_MOD_SHIFT 32 + +#define DECT_CCTRL_ATTR_ACR_MASK 0x00000000f0000000ULL +#define DECT_CCTRL_ATTR_ACR_SHIFT 28 + +enum dect_adaptive_code_rates { + DECT_ACR_NONE = 0x0, +}; + +#define DECT_CCTRL_ATTR_A_MOD_MASK 0x000000000c000000ULL +#define DECT_CCTRL_ATTR_A_MOD_SHIFT 26 + +#define DECT_CCTRL_ATTR_BZ_MOD_MASK 0x0000000003000000ULL +#define DECT_CCTRL_ATTR_BZ_MOD_SHIFT 24 + +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 0x00f0000000000000ULL +#define DECT_CCTRL_RELEASE_INFO1_SHIFT 52 + +#define DECT_CCTRL_RELEASE_LBN_MASK 0x000f000000000000ULL +#define DECT_CCTRL_RELEASE_LBN_SHIFT 48 + +#define DECT_CCTRL_RELEASE_REASON_MASK 0x0000f00000000000ULL +#define DECT_CCTRL_RELEASE_REASON_SHIFT 44 + +enum dect_mac_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 0x00000fffff000000ULL +#define DECT_CCTRL_RELEASE_PMID_SHIFT 24 + +struct dect_cctrl { + enum dect_cctrl_cmds cmd; + union { + struct { + uint32_t pmid; + uint16_t fmid; + }; + struct { + uint8_t lbn; + uint8_t ecn; + uint8_t type; + uint8_t service; + uint8_t slot; + bool cf; + uint8_t a_mod; + uint8_t bz_mod; + uint8_t bz_ext_mod; + uint8_t acr; + }; + struct { + uint32_t pmid; + uint8_t lbn; + uint8_t reason; + }; + }; +}; + +/* Encryption Control */ + +#define DECT_ENCCTRL_FILL_MASK 0x5000000000000000ULL + +#define DECT_ENCCTRL_CMD_MASK 0x0f00000000000000ULL +#define DECT_ENCCTRL_CMD_SHIFT 56 + +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 0x00fff00000000000ULL +#define DECT_ENCCTRL_FMID_SHIFT 44 + +#define DECT_ENCCTRL_PMID_MASK 0x00000fffff000000ULL +#define DECT_ENCCTRL_PMID_SHIFT 24 + +struct dect_encctrl { + enum dect_encctrl_cmds cmd; + uint32_t pmid; + uint16_t 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 { + uint8_t 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 { + uint32_t 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; + uint8_t num_saris; +}; + +/* + * B-Field + */ + +#define DECT_B_FIELD_SIZE 40 + +/** + * 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_ETYPE_CF_1 = 0x3 << DECT_HDR_BA_SHIFT, + DECT_BI_ETYPE_NOT_ALL_CF_0 = 0x4 << DECT_HDR_BA_SHIFT, + DECT_BI_ETYPE_NOT_ALL_CF_1 = 0x5 << DECT_HDR_BA_SHIFT, + DECT_BI_ETYPE_MAC = 0x6 << DECT_HDR_BA_SHIFT, + 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_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 { + uint32_t mcei; + enum dect_mac_connection_types type; + //struct dect_ari ari; + //struct dect_pmid pmid; + uint8_t ecn; + enum dect_mac_service_types service; +}; + +#endif /* _NET_DECT_MAC_H */ diff --git a/include/nwk.h b/include/nwk.h new file mode 100644 index 0000000..2ffcbf8 --- /dev/null +++ b/include/nwk.h @@ -0,0 +1,73 @@ +#ifndef _NWK_H +#define _NWK_H + +/* LCE message types */ +enum dect_lce_msg_types { + DECT_LCE_PAGE_RESPONSE = 0x71, + DECT_LCE_PAGE_REJECT = 0x72, +}; + +/** + * Call Control message types + */ +enum dect_cc_msg_types { + DECT_CC_RESERVED = 0x0, + DECT_CC_ALERTING = 0x1, + DECT_CC_CALL_PROC = 0x2, + DECT_CC_SETUP = 0x5, + DECT_CC_CONNECT = 0x7, + DECT_CC_SETUP_ACK = 0xd, + DECT_CC_CONNECT_ACK = 0xf, + DECT_CC_SERVICE_CHANGE = 0x20, + DECT_CC_SERVICE_ACCEPT = 0x21, + DECT_CC_SERVICE_REJECT = 0x22, + DECT_CC_RELEASE = 0x4d, + DECT_CC_RELEASE_COM = 0x5a, + DECT_CC_IWU_INFO = 0x60, + DECT_CC_NOTIFY = 0x6e, + DECT_CC_INFO = 0x7b, +}; + +/** + * Call Independant Supplementary Services messages types + */ +enum dect_ciss_msg_types { + DECT_CISS_RELEASE_COM = 0x5a, + DECT_CISS_FACILITY = 0x62, + DECT_CISS_REGISTER = 0x64, +}; + +/** + * MM message types + */ +enum dect_mm_msg_types { + DECT_MM_AUTHENTICATION_REQUEST = 0x40, + DECT_MM_AUTHENTICATION_REPLY = 0x41, + DECT_MM_KEY_ALLOCATE = 0x42, + DECT_MM_AUTHENTICATION_REJECT = 0x43, + DECT_MM_ACCESS_RIGHTS_REQUEST = 0x44, + DECT_MM_ACCESS_RIGHTS_ACCEPT = 0x45, + DECT_MM_ACCESS_RIGHTS_REJECT = 0x47, + DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST = 0x48, + DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT = 0x49, + DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT = 0x4b, + DECT_MM_CIPHER_REQUEST = 0x4c, + DECT_MM_CIPHER_SUGGEST = 0x4e, + DECT_MM_CIPHER_REJECT = 0x4f, + DECT_MM_INFO_REQUEST = 0x50, + DECT_MM_INFO_ACCEPT = 0x51, + DECT_MM_INFO_SUGGEST = 0x52, + DECT_MM_INFO_REJECT = 0x53, + DECT_MM_LOCATE_REQUEST = 0x54, + DECT_MM_LOCATE_ACCEPT = 0x55, + DECT_MM_DETACH = 0x56, + DECT_MM_LOCATE_REJECT = 0x57, + DECT_MM_IDENTITY_REQUEST = 0x58, + DECT_MM_IDENTITY_REPLY = 0x59, + DECT_MM_IWU = 0x5b, + DECT_MM_TEMPORARY_IDENTITY_ASSIGN = 0x5c, + DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK = 0x5d, + DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ = 0x5f, +}; + +#endif /* _NWK_H */ diff --git a/include/phl.h b/include/phl.h new file mode 100644 index 0000000..ae31b19 --- /dev/null +++ b/include/phl.h @@ -0,0 +1,61 @@ +/* + * DECT Transceiver Layer + * + * Copyright (c) 2009 Patrick McHardy + */ + +#include + +#ifndef _NET_DECT_TRANSCEIVER_H +#define _NET_DECT_TRANSCEIVER_H + +#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 uint8_t dect_next_slotnum(uint8_t slot) +{ + if (++slot == DECT_FRAME_SIZE) + slot = 0; + return slot; +} + +static inline uint8_t dect_slot_add(uint8_t s1, uint8_t s2) +{ + return (s1 + s2) % DECT_FRAME_SIZE; +} + +static inline uint8_t dect_slot_distance(uint8_t s1, uint8_t 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 uint8_t dect_normal_transmit_base(enum dect_cluster_modes mode) +{ + return mode == DECT_MODE_FP ? 0 : DECT_HALF_FRAME_SIZE; +} + +static inline uint8_t dect_normal_receive_base(enum dect_cluster_modes mode) +{ + return mode == DECT_MODE_FP ? DECT_HALF_FRAME_SIZE : 0; +} + +static inline uint8_t 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 uint8_t dect_tdd_slot(uint8_t slot) +{ + return slot < DECT_HALF_FRAME_SIZE ? slot + DECT_HALF_FRAME_SIZE : + slot - DECT_HALF_FRAME_SIZE; +} + +#endif /* _NET_DECT_TRANSCEIVER_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..d4744f0 --- /dev/null +++ b/install-sh @@ -0,0 +1,269 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..f9e7749 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +dectmon diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..c89c94c --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,13 @@ +CFLAGS += $(EVENT_CFLAGS) +LDFLAGS += -ldect $(EVENT_LDFLAGS) + +PROGRAMS = dectmon + +dectmon-obj += event_ops.o +dectmon-obj += dummy_ops.o +dectmon-obj += debug.o +dectmon-obj += dsc.o +dectmon-obj += mac.o +dectmon-obj += dlc.o +dectmon-obj += nwk.o +dectmon-obj += main.o diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..675f65f --- /dev/null +++ b/src/debug.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BLOCKSIZE 16 + +void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size) +{ + unsigned int i, off, plen = 0; + char hbuf[3 * BLOCKSIZE + 1], abuf[BLOCKSIZE + 1]; + + for (i = 0; i < strlen(prefix); i++) + plen += prefix[i] == '\t' ? 8 : 1; + + for (i = 0; i < size; i++) { + off = i % BLOCKSIZE; + + sprintf(hbuf + 3 * off, "%.2x ", buf[i]); + abuf[off] = isascii(buf[i]) && isprint(buf[i]) ? buf[i] : '.'; + + if (off == BLOCKSIZE - 1 || i == size - 1) { + abuf[off + 1] = '\0'; + printf("%s: %-*s |%s|\n", prefix, 64 - plen, hbuf, abuf); + } + } +} diff --git a/src/dlc.c b/src/dlc.c new file mode 100644 index 0000000..9340519 --- /dev/null +++ b/src/dlc.c @@ -0,0 +1,141 @@ +/* + * dectmon DLC message reassembly + * + * Copyright (c) 2010 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#define dlc_print(fmt, args...) \ + do { \ + if (dumpopts & DECTMON_DUMP_DLC) \ + printf(fmt, ## args); \ + } while (0) + +#if 1 +#define lc_debug(lc, fmt, args...) dlc_print(fmt, ## args) +#else +#define lc_debug(lc, fmt, args...) +#endif + +static void dect_fa_parse_len(struct dect_fa_len *len, + const struct dect_msg_buf *mb) +{ + uint8_t l; + + l = mb->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); +} + +static struct dect_lc *dect_lc_init(struct dect_mac_con *mc) +{ + struct dect_lc *lc; + + lc = calloc(1, sizeof(*lc)); + if ((mc->pmid & 0xf0000) != 0xe0000) + lc->lsig = mc->pmid; + return lc; +} + +static bool dect_fa_frame_csum_verify(const struct dect_lc *lc, + struct dect_msg_buf *mb) +{ + uint8_t *data = mb->data; + unsigned int i; + uint8_t c0 = 0, c1 = 0; + uint16_t t; + + data[mb->len - 2] ^= lc->lsig >> 8; + data[mb->len - 1] ^= lc->lsig & 0xff; + + for (i = 0; i < mb->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 == (uint8_t)~0 && c1 == (uint8_t)~0; +} + +static const uint8_t channel_sdu_size[] = { + [DECT_MC_C_S] = DECT_C_S_SDU_SIZE, + [DECT_MC_C_F] = DECT_C_F_SDU_SIZE, +}; + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +static struct dect_msg_buf *dect_lc_reassemble(struct dect_lc *lc, + enum dect_data_channels chan, + struct dect_msg_buf *mb) +{ + struct dect_fa_len fl; + uint8_t sdu_len, len; + + sdu_len = channel_sdu_size[chan]; + if (lc->rx_buf == NULL) { + dect_fa_parse_len(&fl, mb); + len = fl.len; + len += DECT_FA_HDR_SIZE + DECT_FA_CSUM_SIZE; + + lc->rx_len = roundup(len, sdu_len); + lc->rx_buf = dect_mbuf_alloc(dh); + if (lc->rx_buf == NULL) + goto err; + } + + memcpy(dect_mbuf_put(lc->rx_buf, sdu_len), mb->data, sdu_len); + mb = NULL; + + if (lc->rx_buf->len >= lc->rx_len) { + assert(lc->rx_buf->len == lc->rx_len); + mb = lc->rx_buf; + lc->rx_buf = NULL; + + if (!dect_fa_frame_csum_verify(lc, mb)) + goto err; + + /* Trim checksum and filling */ + dect_fa_parse_len(&fl, mb); + mb->len = fl.len + DECT_FA_HDR_SIZE; + lc_debug(lc, "reassembled SDU len %u\n", mb->len); + } + + return mb; + +err: + lc_debug(lc, "reassembly failed\n"); + return NULL; +} + +void dect_mac_co_data_ind(struct dect_mac_con *mc, enum dect_data_channels chan, + struct dect_msg_buf *mb) +{ + struct dect_lc *lc; + + //printf("MAC_CO_DATA-ind\n"); + if (mc->lc == NULL) { + lc = dect_lc_init(mc); + if (lc == NULL) + return; + mc->lc = lc; + } + + mb = dect_lc_reassemble(mc->lc, chan, mb); + if (mb != NULL && mb->len > DECT_FA_HDR_SIZE) { + dect_mbuf_pull(mb, DECT_FA_HDR_SIZE); + dect_dl_data_ind(&mc->tbc->dl, mb); + } +} diff --git a/src/dsc.c b/src/dsc.c new file mode 100644 index 0000000..3288ad3 --- /dev/null +++ b/src/dsc.c @@ -0,0 +1,147 @@ +/* + * DECT Standard Cipher + * + * Copyright (c) 2010 Erik Tews + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include + +#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))); + } +} + +uint64_t dect_dsc_iv(uint32_t mfn, uint8_t framenum) +{ + return __cpu_to_le64((mfn << 4) + framenum); +} diff --git a/src/dummy_ops.c b/src/dummy_ops.c new file mode 100644 index 0000000..945e502 --- /dev/null +++ b/src/dummy_ops.c @@ -0,0 +1,443 @@ +#include +#include + +/* + * LLME Ops + */ + +static void llme_mac_me_info_ind(struct dect_handle *dh, + const struct dect_fp_capabilities *fpc) +{ +} + +static struct dect_llme_ops_ dummy_llme_ops; + +/* + * LCE Ops + */ + +static bool lce_page_response(struct dect_handle *dh, + struct dect_lce_page_param *param) +{ + return false; +} + +static void lce_group_ring_ind(struct dect_handle *dh, + enum dect_alerting_patterns pattern) +{ +} + +static struct dect_lce_ops dummy_lce_ops; + +/* + * CC Ops + */ + +static void mncc_setup_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_setup_param *param) +{ +} + +static void mncc_setup_ack_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_setup_ack_param *param) +{ +} + +static void mncc_reject_ind(struct dect_handle *dh, struct dect_call *call, + enum dect_causes cause, + struct dect_mncc_release_param *param) +{ +} + +static void mncc_call_proc_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_call_proc_param *param) +{ +} + +static void mncc_alert_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_alert_param *param) +{ +} + +static void mncc_connect_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_connect_param *param) +{ +} + +static void mncc_connect_cfm(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_connect_param *param) +{ +} + +static void mncc_release_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_release_param *param) +{ +} + +static void mncc_release_cfm(struct dect_handle *dh, struct dect_call *call, + enum dect_causes cause, + struct dect_mncc_release_param *param) +{ +} + +static void mncc_facility_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_facility_param *param) +{ +} + +static void mncc_info_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_info_param *param) +{ +} + +static void mncc_modify_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_modify_param *param) +{ +} + +static void mncc_modify_cfm(struct dect_handle *dh, struct dect_call *call, + bool success, + struct dect_mncc_modify_param *param) +{ +} + +static void mncc_hold_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_hold_param *param) +{ +} + +static void mncc_hold_cfm(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_hold_param *param) +{ +} + +static void mncc_retrieve_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_hold_param *param) +{ +} + +static void mncc_retrieve_cfm(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_hold_param *param) +{ +} + +static void mncc_iwu_info_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_mncc_iwu_info_param *param) +{ +} + +static void dl_u_data_ind(struct dect_handle *dh, struct dect_call *call, + struct dect_msg_buf *mb) +{ +} + +static struct dect_cc_ops dummy_cc_ops; + +/* + * MM Ops + */ + +static void mm_access_rights_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_access_rights_param *param) +{ + struct dect_mm_access_rights_param reply = {}; + + dect_mm_access_rights_res(dh, mme, false, &reply); +} + +static void mm_access_rights_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_access_rights_param *param) +{ +} + +static void mm_access_rights_terminate_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_access_rights_terminate_param *param) +{ + struct dect_mm_access_rights_terminate_param reply = {}; + + dect_mm_access_rights_terminate_res(dh, mme, false, &reply); +} + +static void mm_access_rights_terminate_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_access_rights_terminate_param *param) +{ +} + +static void mm_key_allocate_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_key_allocate_param *param) +{ +} + +static void mm_authenticate_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_authenticate_param *param) +{ + struct dect_mm_authenticate_param reply = {}; + + dect_mm_authenticate_res(dh, mme, false, &reply); +} + +static void mm_authenticate_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_authenticate_param *param) +{ +} + +static void mm_cipher_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_cipher_param *param) +{ + struct dect_mm_cipher_param reply = {}; + + dect_mm_cipher_res(dh, mme, false, &reply, NULL); +} + +static void mm_cipher_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_cipher_param *param) +{ +} + +static void mm_locate_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_locate_param *param) +{ + struct dect_mm_locate_param reply = {}; + + dect_mm_locate_res(dh, mme, false, &reply); +} + +static void mm_locate_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_locate_param *param) +{ +} + +static void mm_detach_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_detach_param *param) +{ +} + +static void mm_identity_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_identity_param *param) +{ +} + +static void mm_identity_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_identity_param *param) +{ +} + +static void mm_identity_assign_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_identity_assign_param *param) +{ + struct dect_mm_identity_assign_param reply = {}; + + dect_mm_identity_assign_res(dh, mme, false, &reply); +} + +static void mm_identity_assign_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_identity_assign_param *param) +{ +} + +static void mm_info_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_info_param *param) +{ + struct dect_mm_info_param reply = {}; + + dect_mm_info_res(dh, mme, false, &reply); +} + +static void mm_info_cfm(struct dect_handle *dh, + struct dect_mm_endpoint *mme, bool accept, + struct dect_mm_info_param *param) +{ +} + +static void mm_iwu_ind(struct dect_handle *dh, + struct dect_mm_endpoint *mme, + struct dect_mm_iwu_param *param) +{ +} + +static struct dect_mm_ops dummy_mm_ops; + +/* + * SS Ops + */ + +static void mnss_setup_ind(struct dect_handle *dh, struct dect_ss_endpoint *sse, + struct dect_mnss_param *param) +{ + +} + +static void mnss_facility_ind(struct dect_handle *dh, struct dect_ss_endpoint *sse, + struct dect_mnss_param *param) +{ + +} + +static void mnss_release_ind(struct dect_handle *dh, struct dect_ss_endpoint *sse, + struct dect_mnss_param *param) + +{ + +} + +static struct dect_ss_ops dummy_ss_ops; + +/* + * CLMS Ops + */ + +static void mncl_unitdata_ind(struct dect_handle *dh, + enum dect_clms_message_types type, + struct dect_mncl_unitdata_param *param, + struct dect_msg_buf *mb) +{ +} + +static struct dect_clms_ops dummy_clms_ops; + +void dect_dummy_ops_init(struct dect_ops *ops) +{ + struct dect_llme_ops_ *llme_ops; + struct dect_lce_ops *lce_ops; + struct dect_cc_ops *cc_ops; + struct dect_mm_ops *mm_ops; + struct dect_ss_ops *ss_ops; + struct dect_clms_ops *clms_ops; + + if (!ops->llme_ops) + ops->llme_ops = &dummy_llme_ops; + llme_ops = (void *)ops->llme_ops; + + if (!llme_ops->mac_me_info_ind) + llme_ops->mac_me_info_ind = llme_mac_me_info_ind; + + if (!ops->lce_ops) + ops->lce_ops = &dummy_lce_ops; + lce_ops = (void *)ops->lce_ops; + + if (!lce_ops->lce_page_response) + lce_ops->lce_page_response = lce_page_response; + if (!lce_ops->lce_group_ring_ind) + lce_ops->lce_group_ring_ind = lce_group_ring_ind; + + if (!ops->cc_ops) + ops->cc_ops = &dummy_cc_ops; + cc_ops = (void *)ops->cc_ops; + + if (!cc_ops->mncc_setup_ind) + cc_ops->mncc_setup_ind = mncc_setup_ind; + if (!cc_ops->mncc_setup_ack_ind) + cc_ops->mncc_setup_ack_ind = mncc_setup_ack_ind; + if (!cc_ops->mncc_reject_ind) + cc_ops->mncc_reject_ind = mncc_reject_ind; + if (!cc_ops->mncc_call_proc_ind) + cc_ops->mncc_call_proc_ind = mncc_call_proc_ind; + if (!cc_ops->mncc_alert_ind) + cc_ops->mncc_alert_ind = mncc_alert_ind; + if (!cc_ops->mncc_connect_ind) + cc_ops->mncc_connect_ind = mncc_connect_ind; + if (!cc_ops->mncc_connect_cfm) + cc_ops->mncc_connect_cfm = mncc_connect_cfm; + if (!cc_ops->mncc_release_ind) + cc_ops->mncc_release_ind = mncc_release_ind; + if (!cc_ops->mncc_release_cfm) + cc_ops->mncc_release_cfm = mncc_release_cfm; + if (!cc_ops->mncc_facility_ind) + cc_ops->mncc_facility_ind = mncc_facility_ind; + if (!cc_ops->mncc_info_ind) + cc_ops->mncc_info_ind = mncc_info_ind; + if (!cc_ops->mncc_modify_ind) + cc_ops->mncc_modify_ind = mncc_modify_ind; + if (!cc_ops->mncc_modify_cfm) + cc_ops->mncc_modify_cfm = mncc_modify_cfm; + if (!cc_ops->mncc_hold_ind) + cc_ops->mncc_hold_ind = mncc_hold_ind; + if (!cc_ops->mncc_hold_cfm) + cc_ops->mncc_hold_cfm = mncc_hold_cfm; + if (!cc_ops->mncc_retrieve_ind) + cc_ops->mncc_retrieve_ind = mncc_retrieve_ind; + if (!cc_ops->mncc_retrieve_cfm) + cc_ops->mncc_retrieve_cfm = mncc_retrieve_cfm; + if (!cc_ops->mncc_iwu_info_ind) + cc_ops->mncc_iwu_info_ind = mncc_iwu_info_ind; + if (!cc_ops->dl_u_data_ind) + cc_ops->dl_u_data_ind = dl_u_data_ind; + + if (!ops->mm_ops) + ops->mm_ops = &dummy_mm_ops; + mm_ops = (void *)ops->mm_ops; + + if (!mm_ops->mm_access_rights_ind) + mm_ops->mm_access_rights_ind = mm_access_rights_ind; + if (!mm_ops->mm_access_rights_cfm) + mm_ops->mm_access_rights_cfm = mm_access_rights_cfm; + if (!mm_ops->mm_access_rights_terminate_ind) + mm_ops->mm_access_rights_terminate_ind = mm_access_rights_terminate_ind; + if (!mm_ops->mm_access_rights_terminate_cfm) + mm_ops->mm_access_rights_terminate_cfm = mm_access_rights_terminate_cfm; + if (!mm_ops->mm_key_allocate_ind) + mm_ops->mm_key_allocate_ind = mm_key_allocate_ind; + if (!mm_ops->mm_authenticate_ind) + mm_ops->mm_authenticate_ind = mm_authenticate_ind; + if (!mm_ops->mm_authenticate_cfm) + mm_ops->mm_authenticate_cfm = mm_authenticate_cfm; + if (!mm_ops->mm_cipher_ind) + mm_ops->mm_cipher_ind = mm_cipher_ind; + if (!mm_ops->mm_cipher_cfm) + mm_ops->mm_cipher_cfm = mm_cipher_cfm; + if (!mm_ops->mm_locate_ind) + mm_ops->mm_locate_ind = mm_locate_ind; + if (!mm_ops->mm_locate_cfm) + mm_ops->mm_locate_cfm = mm_locate_cfm; + if (!mm_ops->mm_authenticate_ind) + mm_ops->mm_detach_ind = mm_detach_ind; + if (!mm_ops->mm_identity_ind) + mm_ops->mm_identity_ind = mm_identity_ind; + if (!mm_ops->mm_identity_cfm) + mm_ops->mm_identity_cfm = mm_identity_cfm; + if (!mm_ops->mm_identity_assign_ind) + mm_ops->mm_identity_assign_ind = mm_identity_assign_ind; + if (!mm_ops->mm_identity_assign_cfm) + mm_ops->mm_identity_assign_cfm = mm_identity_assign_cfm; + if (!mm_ops->mm_info_ind) + mm_ops->mm_info_ind = mm_info_ind; + if (!mm_ops->mm_info_cfm) + mm_ops->mm_info_cfm = mm_info_cfm; + if (!mm_ops->mm_iwu_ind) + mm_ops->mm_iwu_ind = mm_iwu_ind; + + if (!ops->ss_ops) + ops->ss_ops = &dummy_ss_ops; + ss_ops = (void *)ops->ss_ops; + + if (!ss_ops->mnss_setup_ind) + ss_ops->mnss_setup_ind = mnss_setup_ind; + if (!ss_ops->mnss_facility_ind) + ss_ops->mnss_facility_ind = mnss_facility_ind; + if (!ss_ops->mnss_release_ind) + ss_ops->mnss_release_ind = mnss_release_ind; + + if (!ops->clms_ops) + ops->clms_ops = &dummy_clms_ops; + clms_ops = (void *)ops->clms_ops; + + if (!clms_ops->mncl_unitdata_ind) + clms_ops->mncl_unitdata_ind = mncl_unitdata_ind; +} diff --git a/src/event_ops.c b/src/event_ops.c new file mode 100644 index 0000000..e69abe9 --- /dev/null +++ b/src/event_ops.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +#include +#include + +static void event_io_callback(int fd, short mask, void *data) +{ + struct dect_fd *dfd = data; + uint32_t events; + + events = 0; + if (mask & EV_READ) + events |= DECT_FD_READ; + if (mask & EV_WRITE) + events |= DECT_FD_WRITE; + + dect_fd_process(dh, dfd, events); +} + +static int register_fd(const struct dect_handle *dh, struct dect_fd *dfd, + uint32_t events) +{ + struct event *ev = dect_fd_priv(dfd); + unsigned short mask; + + mask = EV_PERSIST; + if (events & DECT_FD_READ) + mask |= EV_READ; + if (events & DECT_FD_WRITE) + mask |= EV_WRITE; + + event_set(ev, dect_fd_num(dfd), mask, event_io_callback, dfd); + event_add(ev, NULL); + return 0; +} + +static void unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd) +{ + struct event *ev = dect_fd_priv(dfd); + + event_del(ev); +} + +static void event_timer_callback(int fd, short mask, void *data) +{ + dect_timer_run(dh, data); +} + +static void start_timer(const struct dect_handle *dh, + struct dect_timer *timer, + const struct timeval *tv) +{ + struct event *ev = dect_timer_priv(timer); + + evtimer_set(ev, event_timer_callback, timer); + evtimer_add(ev, (struct timeval *)tv); +} + +static void stop_timer(const struct dect_handle *dh, struct dect_timer *timer) +{ + struct event *ev = dect_timer_priv(timer); + + evtimer_del(ev); +} + +static const struct dect_event_ops dect_event_ops = { + .fd_priv_size = sizeof(struct event), + .register_fd = register_fd, + .unregister_fd = unregister_fd, + .timer_priv_size = sizeof(struct event), + .start_timer = start_timer, + .stop_timer = stop_timer +}; + +static struct event_base *ev_base; +static struct event sig_event; +static bool sigint; +static bool endloop; + +static void sig_callback(int fd, short event, void *data) +{ + sigint = true; +} + +int dect_event_ops_init(struct dect_ops *ops) +{ + + ev_base = event_init(); + if (ev_base == NULL) + return -1; + ops->event_ops = &dect_event_ops; + + signal_set(&sig_event, SIGINT, sig_callback, NULL); + signal_add(&sig_event, NULL); + return 0; +} + +void dect_event_loop_stop(void) +{ + endloop = true; +} + +void dect_event_loop(void) +{ + endloop = false; + + while (!sigint && !endloop) + event_loop(EVLOOP_ONCE); +} + +void dect_event_ops_cleanup(void) +{ + signal_del(&sig_event); + event_base_free(ev_base); +} diff --git a/src/mac.c b/src/mac.c new file mode 100644 index 0000000..65d66e3 --- /dev/null +++ b/src/mac.c @@ -0,0 +1,657 @@ +/* + * dectmon MAC layer message tracing + * + * Copyright (c) 2010 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define BITS_PER_BYTE 8 + +#define mac_print(fmt, args...) \ + do { \ + if (dumpopts & DECTMON_DUMP_MAC) \ + printf(fmt, ## args); \ + } while (0) + +/* + * Tail message parsing/construction + */ + +static enum dect_tail_identifications dect_parse_tail(const struct dect_msg_buf *mb) +{ + return mb->data[DECT_HDR_TA_OFF] & DECT_HDR_TA_MASK; +} + +static uint8_t dect_parse_ari(struct dect_ari *ari, uint64_t 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; + } +} + +static int dect_parse_identities_information(struct dect_tail_msg *tm, uint64_t t) +{ + struct dect_idi *idi = &tm->idi; + uint8_t 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; + + mac_print("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 int dect_parse_static_system_information(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("static system information: SN: %u CN: %u PSCN: %u NR: %u " + "Txs: %u Mc: %u RF-carriers: %x\n", + ssi->sn, ssi->cn, ssi->pscn, ssi->nr, ssi->txs, ssi->mc, + ssi->rfcars); + return 0; +} + +static int dect_parse_extended_rf_carrier_information(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("extended rf carrier information: RF-carriers: %.6x band: %u num: %u\n", + erfc->rfcars, erfc->band, erfc->num_rfcars); + return 0; +} + +static int dect_parse_fixed_part_capabilities(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("fixed part capabilities: FPC: %.5x HLC: %.4x\n", + fpc->fpc, fpc->hlc); + return 0; +} + +static int dect_parse_extended_fixed_part_capabilities(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("extended fixed part capabilities: FPC: %.5x HLC: %.6x\n", + efpc->fpc, efpc->hlc); + return 0; +} + +static int dect_parse_extended_fixed_part_capabilities2(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("extended fixed part capabilities2: FPC: %x HLC: %x\n", + efpc2->fpc, efpc2->hlc); + return 0; +} + +static int dect_parse_sari(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("sari: cycle %u TARI: %u black: %u\n", + sari->list_cycle, sari->tari, sari->black); + return 0; +} + +static int dect_parse_multiframe_number(struct dect_tail_msg *tm, uint64_t t) +{ + tm->mfn.num = (t & DECT_QT_MFN_MASK) >> DECT_QT_MFN_SHIFT; + tm->type = DECT_TM_TYPE_MFN; + + mac_print("multiframe number: %u\n", tm->mfn.num); + return 0; +} + +static int dect_parse_system_information(struct dect_tail_msg *tm, uint64_t 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: + mac_print("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, uint64_t t) +{ + struct dect_bfs *bfs = &tm->bfs; + + bfs->mask = (t & DECT_PT_BFS_MASK) >> DECT_PT_BFS_SHIFT; + tm->type = DECT_TM_TYPE_BFS; + + mac_print("page: RFPI: %.3x blind full slots: %.3x\n", + tm->page.rfpi, bfs->mask); + return 0; +} + +static int dect_parse_bearer_description(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("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 int dect_parse_rfp_identity(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("page: RFPI: %.3x RFP identity: %.3x\n", + tm->page.rfpi, id->id); + return 0; +} + +static int dect_parse_rfp_status(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("page: RFPI: %.3x RFP status: rfp_busy: %d sys_busy: %d\n", + tm->page.rfpi, st->rfp_busy, st->sys_busy); + return 0; +} + +static int dect_parse_active_carriers(struct dect_tail_msg *tm, uint64_t 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; + + mac_print("page: RFPI: %.3x active carriers: %.3x\n", + tm->page.rfpi, ac->active); + return 0; +} + +static int dect_parse_paging_info(struct dect_tail_msg *tm, uint64_t 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: + mac_print("dummy or connectionless 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: + mac_print("unknown paging info %llx\n", + (unsigned long long)t); + return -1; + } +} + +static int dect_parse_paging_msg(struct dect_tail_msg *tm, uint64_t 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; + mac_print("full/long page: extend: %u length: %llx\n", + tm->page.extend, (unsigned long long)tm->page.length); + return 0; + default: + mac_print("invalid page length %llx\n", + (unsigned long long)tm->page.length); + return -1; + } +} + +static int dect_parse_cctrl_common(struct dect_cctrl *cctl, uint64_t t) +{ + cctl->fmid = (t & DECT_CCTRL_FMID_MASK) >> DECT_CCTRL_FMID_SHIFT; + cctl->pmid = (t & DECT_CCTRL_PMID_MASK) >> DECT_CCTRL_PMID_SHIFT; + + mac_print("cctrl: command: %llx FMID: %.3x PMID: %.5x\n", + (unsigned long long)cctl->cmd, cctl->fmid, cctl->pmid); + return 0; +} + +static int dect_parse_cctrl_attr(struct dect_cctrl *cctl, uint64_t 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; + + mac_print("cctrl: command: %llx ECN: %x LBN: %x type: %x " + "service: %x slot type: %x CF: %d A-modulation: %x " + "B/Z-modulation: %x B/Z extended modulation: %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 int dect_parse_cctrl_release(struct dect_cctrl *cctl, uint64_t 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; + + mac_print("cctrl: release: PMID: %.5x LBN: %x reason: %x\n", + cctl->pmid, cctl->lbn, cctl->reason); + return 0; +} + +static int dect_parse_basic_cctrl(struct dect_tail_msg *tm, uint64_t 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: + mac_print("unknown basic cctrl command: %llx\n", + (unsigned long long)cctl->cmd); + return -1; + } +} + +static int dect_parse_advanced_cctrl(struct dect_tail_msg *tm, uint64_t 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: + case DECT_CCTRL_UNCONFIRMED_DUMMY: + case DECT_CCTRL_UNCONFIRMED_HANDOVER: + 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_BANDWIDTH_T_REQUEST: + case DECT_CCTRL_BANDWIDTH_T_CONFIRM: + return -1; + case DECT_CCTRL_RELEASE: + return dect_parse_cctrl_release(cctl, t); + default: + mac_print("unknown advanced cctrl command: %llx\n", + (unsigned long long)cctl->cmd); + return -1; + } +} + +static int dect_parse_encryption_ctrl(struct dect_tail_msg *tm, uint64_t 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; + mac_print("encctrl: command: %x FMID: %.4x PMID: %.5x\n", + ectl->cmd, ectl->fmid, ectl->pmid); + return 0; +} + +static int dect_parse_mac_ctrl(struct dect_tail_msg *tm, uint64_t 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: + mac_print("Unknown MAC control %llx\n", + (unsigned long long)t & DECT_MT_HDR_MASK); + return -1; + } +} + +static int dect_parse_ct_data(struct dect_tail_msg *tm, uint64_t t, uint8_t seq) +{ + struct dect_ct_data *ctd = &tm->ctd; + + ctd->seq = seq; + tm->type = DECT_TM_TYPE_CT; + mac_print("CS tail: sequence number: %u\n", seq); + return 0; +} + +static int dect_parse_tail_msg(struct dect_tail_msg *tm, uint8_t slot, + const struct dect_msg_buf *mb) +{ + uint64_t t; + + tm->type = DECT_TM_TYPE_INVALID; + t = __be64_to_cpu(*(uint64_t *)&mb->data[DECT_T_FIELD_OFF]); + + switch (dect_parse_tail(mb)) { + 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: + mac_print("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 (slot < 12) + return dect_parse_paging_msg(tm, t); + case DECT_TI_MT: + return dect_parse_mac_ctrl(tm, t); + default: + mac_print("unknown tail %x\n", dect_parse_tail(mb)); + return -1; + } +} + +static struct dect_trx_slot { + struct dect_tbc *tbc; +} slots[DECT_FRAME_SIZE]; + +static struct dect_tbc *dect_tbc_init(uint32_t pmid) +{ + struct dect_tbc *tbc; + + tbc = calloc(1, sizeof(*tbc)); + if (tbc == NULL) + return NULL; + + tbc->dl.tbc = tbc; + + tbc->mbc[DECT_MODE_FP].cs_seq = 1; + tbc->mbc[DECT_MODE_FP].cf_seq = 1; + tbc->mbc[DECT_MODE_FP].mc.pmid = pmid; + tbc->mbc[DECT_MODE_FP].mc.tbc = tbc; + + + tbc->mbc[DECT_MODE_PP].cs_seq = 1; + tbc->mbc[DECT_MODE_PP].cf_seq = 1; + tbc->mbc[DECT_MODE_PP].mc.pmid = pmid; + tbc->mbc[DECT_MODE_PP].mc.tbc = tbc; + + return tbc; +} + +static void dect_tbc_rcv(struct dect_tbc *tbc, uint8_t slot, + struct dect_msg_buf *mb, struct dect_tail_msg *tm) +{ + enum dect_b_identifications b_id; + struct dect_mbc *mbc; + unsigned int i; + bool cf; + + mbc = &tbc->mbc[slot < 12 ? DECT_MODE_FP : DECT_MODE_PP]; + b_id = (mb->data[0] & DECT_HDR_BA_MASK); + + if (tm->type == DECT_TM_TYPE_CT) { + if (tm->ctd.seq != mbc->cs_seq) { + printf("CS: incorrect seq: %u\n", tm->ctd.seq); + return; + } + mbc->cs_seq = !mbc->cs_seq; + + dect_mbuf_pull(mb, 1); + dect_mac_co_data_ind(&mbc->mc, DECT_MC_C_S, mb); + dect_mbuf_pull(mb, 7); + } else + dect_mbuf_pull(mb, 8); + + cf = true; + switch (b_id) { + case DECT_BI_ETYPE_NOT_ALL_CF_0: + case DECT_BI_ETYPE_NOT_ALL_CF_1: + mac_print("Not all CF\n"); + cf = false; + case DECT_BI_ETYPE_CF_0: + case DECT_BI_ETYPE_CF_1: + if (((b_id >> DECT_HDR_BA_SHIFT) & 0x1) != mbc->cf_seq) { + printf("CF: incorrect seq: %u\n", b_id & 0x1); + return; + } + mbc->cf_seq = !mbc->cf_seq; + + for (i = 0; i < mb->len / 10; i++) { + if (cf) { + mac_print("CF: seq: %u\n", i); + dect_mac_co_data_ind(&mbc->mc, DECT_MC_C_F, mb); + dect_mbuf_pull(mb, 10); + continue; + } + + if (!(mb->data[0] & 0x80)) + cf = true; + dect_mbuf_pull(mb, 10); + } + break; + default: + break; + } + + if (tm->type == DECT_TM_TYPE_BCCTRL || + tm->type == DECT_TM_TYPE_ACCTRL) { + if (tm->cctl.cmd == DECT_CCTRL_RELEASE) { + slots[slot].tbc = NULL; + slots[dect_tdd_slot(slot)].tbc = NULL; + free(tbc); + } + } +} + +void dect_mac_rcv(struct dect_msg_buf *mb, uint8_t slot) +{ + struct dect_trx_slot *ts = &slots[slot]; + enum dect_tail_identifications a_id; + enum dect_b_identifications b_id; + struct dect_tail_msg tm; + struct dect_tbc *tbc; + + a_id = (mb->data[0] & DECT_HDR_TA_MASK) >> DECT_HDR_TA_SHIFT; + b_id = (mb->data[0] & DECT_HDR_BA_MASK) >> DECT_HDR_BA_SHIFT; + mac_print("slot: %02u A: %x B: %x ", slot, a_id, b_id); + + dect_parse_tail_msg(&tm, slot, mb); + //dect_hexdump("MAC RCV", mb->data, mb->len); + + if (ts->tbc != NULL) + return dect_tbc_rcv(ts->tbc, slot, mb, &tm); + + if (tm.type == DECT_TM_TYPE_BCCTRL || + tm.type == DECT_TM_TYPE_ACCTRL) { + switch (tm.cctl.cmd) { + case DECT_CCTRL_ACCESS_REQ: + case DECT_CCTRL_BEARER_HANDOVER_REQ: + case DECT_CCTRL_CONNECTION_HANDOVER_REQ: + tbc = dect_tbc_init(tm.cctl.pmid); + if (tbc == NULL) + break; + + ts->tbc = tbc; + slots[slot - 12].tbc = tbc; + printf("TBC slot %u\n", slot); + break; + default: + printf("unknown\n"); + break; + } + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1905f45 --- /dev/null +++ b/src/main.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +#include +#include +#include + +struct dect_handle *dh; + +static void pexit(const char *str) +{ + perror(str); + exit(1); +} + +static void dect_raw_rcv(struct dect_handle *dh, struct dect_fd *dfd, + struct dect_msg_buf *mb) +{ + dect_mac_rcv(mb, mb->slot); +} + +static struct dect_raw_ops raw_ops = { + .raw_rcv = dect_raw_rcv, +}; + +static struct dect_ops ops = { + .raw_ops = &raw_ops, +}; + +#define OPTSTRING "m:d:n:h" + +enum { + OPT_DUMP_MAC = 'm', + OPT_DUMP_DLC = 'd', + OPT_DUMP_NWK = 'n', + OPT_HELP = 'h', +}; + +static const struct option dectmon_opts[] = { + { .name = "dump-mac", .has_arg = true, .flag = 0, .val = OPT_DUMP_MAC, }, + { .name = "dump-dlc", .has_arg = true, .flag = 0, .val = OPT_DUMP_DLC, }, + { .name = "dump-nwk", .has_arg = true, .flag = 0, .val = OPT_DUMP_NWK, }, + { .name = "help", .has_arg = false, .flag = 0, .val = OPT_HELP, }, + { }, +}; + +static uint32_t opt_yesno(const char *arg, uint32_t opts, uint32_t flag) +{ + if (!strcmp(arg, "yes")) + opts |= flag; + else if (!strcmp(arg, "no")) + opts &= ~flag; + else + pexit("invalid argument\n"); + + return opts; +} + +uint32_t dumpopts = DECTMON_DUMP_NWK; + +int main(int argc, char **argv) +{ + struct dect_fd *dfd; + int optidx = 0, c; + + for (;;) { + c = getopt_long(argc, argv, OPTSTRING, dectmon_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case OPT_DUMP_MAC: + dumpopts = opt_yesno(optarg, dumpopts, DECTMON_DUMP_MAC); + break; + case OPT_DUMP_DLC: + dumpopts = opt_yesno(optarg, dumpopts, DECTMON_DUMP_DLC); + break; + case OPT_DUMP_NWK: + dumpopts = opt_yesno(optarg, dumpopts, DECTMON_DUMP_NWK); + break; + case OPT_HELP: + printf("%s [ options ]\n" + "\n" + "Options:\n" + " -m/--dump-mac=yes/no\n" + " -d/--dump-dlc=yes/no\n" + " -n/--dump-nwk=yes/no\n" + " -h/--help\n", + argv[0]); + + exit(0); + case '?': + exit(1); + } + } + + dect_event_ops_init(&ops); + dect_dummy_ops_init(&ops); + + dh = dect_open_handle(&ops, NULL); + if (dh == NULL) + pexit("dect_init_handle"); + + dfd = dect_raw_socket(dh); + if (dfd == NULL) + pexit("dect_raw_socket"); + + dect_event_loop(); + return 0; +} diff --git a/src/nwk.c b/src/nwk.c new file mode 100644 index 0000000..48395b3 --- /dev/null +++ b/src/nwk.c @@ -0,0 +1,291 @@ +/* + * dectmon - NWK layer message parsing + * + * Copyright (c) 2010 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include +#include +#include +#include + +static LIST_HEAD(dect_pt_list); + +static const char * const nwk_msg_types[256] = { + [DECT_LCE_PAGE_RESPONSE] = "LCE-PAGE-RESPONSE", + [DECT_LCE_PAGE_REJECT] = "LCE-PAGE-REJECT", + [DECT_CC_ALERTING] = "CC-ALERTING", + [DECT_CC_CALL_PROC] = "CC-CALL-PROC", + [DECT_CC_SETUP] = "CC-SETUP", + [DECT_CC_CONNECT] = "CC-CONNECT", + [DECT_CC_SETUP_ACK] = "CC-SETUP-ACK", + [DECT_CC_CONNECT_ACK] = "CC-CONNECT-ACK", + [DECT_CC_SERVICE_CHANGE] = "CC-SERVICE-CHANGE", + [DECT_CC_SERVICE_ACCEPT] = "CC-SERVICE-ACCEPT", + [DECT_CC_SERVICE_REJECT] = "CC-SERVICE-REJECT", + [DECT_CC_RELEASE] = "CC-RELEASE", + [DECT_CC_RELEASE_COM] = "CC-RELEASE-COM", + [DECT_CC_IWU_INFO] = "CC-IWU-INFO", + [DECT_CC_NOTIFY] = "CC-NOTIFY", + [DECT_CC_INFO] = "CC-INFO", + [DECT_CISS_FACILITY] = "CISS-FACILITY", + [DECT_CISS_REGISTER] = "CISS-REGISTER", + [DECT_MM_AUTHENTICATION_REQUEST] = "MM-AUTHENTICATION-REQUEST", + [DECT_MM_AUTHENTICATION_REPLY] = "MM-AUTHENTICATION-REPLY", + [DECT_MM_KEY_ALLOCATE] = "MM-KEY-ALLOCATE", + [DECT_MM_AUTHENTICATION_REJECT] = "MM-AUTHENTICATION-REJECT", + [DECT_MM_ACCESS_RIGHTS_REQUEST] = "MM-ACCESS-RIGHTS-REQUEST", + [DECT_MM_ACCESS_RIGHTS_ACCEPT] = "MM-ACCESS-RIGHTS-ACCEPT", + [DECT_MM_ACCESS_RIGHTS_REJECT] = "MM-ACCESS-RIGHTS-REJECT", + [DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST] = "MM-ACCESS-RIGHTS-TERMINATE-REQUEST", + [DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT] = "MM-ACCESS-RIGHTS-TERMINATE-ACCEPT", + [DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT] = "MM-ACCESS-RIGHTS-TERMINATE-REJECT", + [DECT_MM_CIPHER_REQUEST] = "MM-CIPHER-REQUEST", + [DECT_MM_CIPHER_SUGGEST] = "MM-CIPHER-SUGGEST", + [DECT_MM_CIPHER_REJECT] = "MM-CIPHER-REJECT", + [DECT_MM_INFO_REQUEST] = "MM-INFO-REQUEST", + [DECT_MM_INFO_ACCEPT] = "MM-INFO-ACCEPT", + [DECT_MM_INFO_SUGGEST] = "MM-INFO-SUGGEST", + [DECT_MM_INFO_REJECT] = "MM-INFO-REJECT", + [DECT_MM_LOCATE_REQUEST] = "MM-LOCATE-REQUEST", + [DECT_MM_LOCATE_ACCEPT] = "MM-LOCATE-ACCEPT", + [DECT_MM_DETACH] = "MM-DETACH", + [DECT_MM_LOCATE_REJECT] = "MM-LOCATE-REJECT", + [DECT_MM_IDENTITY_REQUEST] = "MM-IDENTITY-REQUEST", + [DECT_MM_IDENTITY_REPLY] = "MM-IDENTITY-REPLY", + [DECT_MM_IWU] = "MM-IWU", + [DECT_MM_TEMPORARY_IDENTITY_ASSIGN] = "MM-TEMPORARY-IDENTITY-ASSIGN", + [DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK] = "MM-TEMPORARY-IDENTITY-ASSIGN-ACK", + [DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ] = "MM-TEMPORARY-IDENTITY-ASSIGN-REJ", +}; + +#define dect_ie_release(dh, ie) \ + do { \ + if (ie != NULL) \ + dect_ie_put(dh, ie); \ + ie = NULL; \ + } while (0) + +static struct dect_pt *dect_pt_lookup(struct dect_ie_portable_identity *portable_identity) +{ + struct dect_pt *pt; + + list_for_each_entry(pt, &dect_pt_list, list) { + if (!dect_ipui_cmp(&pt->portable_identity->ipui, + &portable_identity->ipui)) + return pt; + } + return NULL; +} + +static struct dect_pt *dect_pt_init(struct dect_ie_portable_identity *portable_identity) +{ + struct dect_pt *pt; + + pt = calloc(1, sizeof(*pt)); + if (pt == NULL) + return NULL; + + pt->portable_identity = dect_ie_hold(portable_identity); + list_add_tail(&pt->list, &dect_pt_list); + + return pt; +} + +static void dect_pt_track_key_allocation(struct dect_pt *pt, uint8_t msgtype, + const struct dect_sfmt_ie *ie, + struct dect_ie_common *common) +{ + uint8_t k[DECT_AUTH_KEY_LEN], ks[DECT_AUTH_KEY_LEN]; + uint8_t dck[DECT_CIPHER_KEY_LEN]; + uint32_t res1; + uint8_t ac[4]; + + switch (msgtype) { + case DECT_MM_KEY_ALLOCATE: + if (pt->procedure != DECT_MM_NONE && + pt->procedure != DECT_MM_KEY_ALLOCATION) + return; + + if (ie->id == DECT_IE_RS) + pt->rs = (void *)__dect_ie_hold(common); + if (ie->id == DECT_IE_RAND) + pt->rand_f = (void *)__dect_ie_hold(common); + + pt->procedure = DECT_MM_KEY_ALLOCATION; + pt->last_msg = msgtype; + return; + case DECT_MM_AUTHENTICATION_REQUEST: + if (pt->procedure != DECT_MM_KEY_ALLOCATION || + pt->last_msg != DECT_MM_KEY_ALLOCATE) + return; + + if (ie->id == DECT_IE_RES) + pt->res = (void *)__dect_ie_hold(common); + + pt->last_msg = msgtype; + break; + default: + if (pt->procedure == DECT_MM_KEY_ALLOCATION) { + printf("unexpected message during key allocation\n"); + goto release; + } + return; + } + + if (pt->rs == NULL || pt->rand_f == NULL || + pt->res == NULL) + return; + + dect_pin_to_ac("0000", ac, sizeof(ac)); + dect_auth_b1(ac, sizeof(ac), k); + + dect_auth_a11(k, pt->rs->value, ks); + dect_auth_a12(ks, pt->rand_f->value, dck, &res1); + + if (res1 == pt->res->value) { + printf("authentication ok\n"); + + dect_auth_a21(k, pt->rs->value, ks); + + dect_hexdump("UAK", ks, sizeof(ks)); + memcpy(pt->uak, ks, sizeof(pt->uak)); + + dect_hexdump("DCK", dck, sizeof(dck)); + memcpy(pt->dck, dck, sizeof(pt->dck)); + } else + printf("authentication failed\n"); + +release: + dect_ie_release(dh, pt->portable_identity); + dect_ie_release(dh, pt->rs); + dect_ie_release(dh, pt->rand_f); + dect_ie_release(dh, pt->res); + pt->procedure = DECT_MM_NONE; +} + +static void dect_pt_track_auth(struct dect_pt *pt, uint8_t msgtype, + const struct dect_sfmt_ie *ie, + struct dect_ie_common *common) +{ + uint8_t k[DECT_AUTH_KEY_LEN], ks[DECT_AUTH_KEY_LEN]; + uint8_t dck[DECT_CIPHER_KEY_LEN]; + struct dect_ie_auth_res res1; + + switch (msgtype) { + case DECT_MM_AUTHENTICATION_REQUEST: + if (pt->procedure != DECT_MM_NONE && + pt->procedure != DECT_MM_AUTHENTICATION) + return; + + if (ie->id == DECT_IE_AUTH_TYPE) + pt->auth_type = (void *)__dect_ie_hold(common); + if (ie->id == DECT_IE_RS) + pt->rs = (void *)__dect_ie_hold(common); + if (ie->id == DECT_IE_RAND) + pt->rand_f = (void *)__dect_ie_hold(common); + + pt->procedure = DECT_MM_AUTHENTICATION; + pt->last_msg = msgtype; + return; + case DECT_MM_AUTHENTICATION_REPLY: + if (pt->procedure != DECT_MM_AUTHENTICATION || + pt->last_msg != DECT_MM_AUTHENTICATION_REQUEST) + return; + + if (ie->id == DECT_IE_RES) + pt->res = (void *)__dect_ie_hold(common); + break; + default: + if (pt->procedure == DECT_MM_AUTHENTICATION) { + printf("unexpected message during authentication\n"); + goto release; + } + return; + } + + if (pt->auth_type == NULL || pt->rs == NULL || pt->rand_f == NULL || + pt->res == NULL) + return; + + dect_auth_b1(pt->uak, sizeof(pt->uak), k); + + dect_auth_a11(k, pt->rs->value, ks); + dect_auth_a12(ks, pt->rand_f->value, dck, &res1.value); + + if (res1.value == pt->res->value) { + printf("authentication successful\n"); + if (pt->auth_type->flags & DECT_AUTH_FLAG_UPC) + memcpy(pt->dck, dck, sizeof(pt->dck)); + } else + printf("authentication failed\n"); + +release: + dect_ie_release(dh, pt->auth_type); + dect_ie_release(dh, pt->rs); + dect_ie_release(dh, pt->rand_f); + dect_ie_release(dh, pt->res); + pt->procedure = DECT_MM_NONE; +} + +static void dect_pt_track_ciphering(struct dect_pt *pt, uint8_t msgtype, + const struct dect_sfmt_ie *ie, + struct dect_ie_common *common) +{ + switch (msgtype) { + case DECT_MM_CIPHER_REQUEST: + if (pt->procedure != DECT_MM_NONE) + return; + pt->tbc->ciphered = true; + break; + default: + return; + } +} + +void dect_dl_data_ind(struct dect_dl *dl, struct dect_msg_buf *mb) +{ + struct dect_pt *pt; + struct dect_sfmt_ie ie; + struct dect_ie_common *common; + uint8_t msgtype; + + if (!(dumpopts & DECTMON_DUMP_NWK)) + return; + + msgtype = mb->data[1]; + + printf("\n"); + dect_hexdump("NWK", mb->data, mb->len); + printf("{%s} message:\n", nwk_msg_types[msgtype]); + + dect_mbuf_pull(mb, 2); + while (mb->len) { + if (dect_parse_sfmt_ie_header(&ie, mb) < 0) + return; + if (dect_parse_sfmt_ie(dh, ie.id, &common, &ie) < 0) + return; + + if (ie.id == DECT_IE_PORTABLE_IDENTITY) { + pt = dect_pt_lookup((void *)common); + if (pt == NULL) + pt = dect_pt_init((void *)common); + dl->pt = pt; + } + + if (dl->pt != NULL) { + dect_pt_track_key_allocation(dl->pt, msgtype, &ie, common); + dect_pt_track_auth(dl->pt, msgtype, &ie, common); + dect_pt_track_ciphering(dl->pt, msgtype, &ie, common); + } + + __dect_ie_put(dh, common); + dect_mbuf_pull(mb, ie.len); + } +}